mcfs.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271
  1. /* Virtual File System: Midnight Commander file system.
  2. Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
  3. 2004, 2005, 2007 Free Software Foundation, Inc.
  4. Written by Miguel de Icaza
  5. Andrej Borsenkow
  6. Norbert Warmuth
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public License
  9. as published by the Free Software Foundation; either version 2 of
  10. the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  18. /**
  19. * \file
  20. * \brief Source: Midnight Commander file system
  21. * \author Miguel de Icaza
  22. * \author Andrej Borsenkow
  23. * \author Norbert Warmuth
  24. *
  25. * Namespace: exports mcfs_vfs_ops, tcp_invalidate_socket
  26. */
  27. #include <config.h>
  28. #ifdef ENABLE_VFS_MCFS
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #include <stdlib.h>
  34. #include <stdarg.h>
  35. #include <pwd.h>
  36. #include <sys/types.h> /* POSIX-required by sys/socket.h and netdb.h */
  37. #include <netdb.h> /* struct hostent */
  38. #include <sys/socket.h> /* AF_INET */
  39. #include <netinet/in.h> /* struct in_addr */
  40. #ifdef HAVE_ARPA_INET_H
  41. #include <arpa/inet.h>
  42. #endif
  43. #ifdef HAVE_PMAP_SET
  44. #include <rpc/rpc.h>
  45. #include <rpc/pmap_prot.h>
  46. #ifdef HAVE_RPC_PMAP_CLNT_H
  47. #include <rpc/pmap_clnt.h>
  48. #endif
  49. #endif
  50. #include "lib/global.h"
  51. #include "src/wtools.h" /* message() */
  52. #include "src/main.h" /* print_vfs_message */
  53. #include "utilvfs.h"
  54. #include "vfs.h"
  55. #include "vfs-impl.h"
  56. #include "mcfs.h"
  57. #include "mcfsutil.h"
  58. #include "netutil.h"
  59. #ifndef INADDR_NONE
  60. # define INADDR_NONE (0xffffffffU)
  61. #endif
  62. #define MCFS_MAX_CONNECTIONS 32
  63. static struct _mcfs_connection {
  64. char *host;
  65. char *user;
  66. char *home;
  67. int sock;
  68. int port;
  69. int version;
  70. } mcfs_connections[MCFS_MAX_CONNECTIONS];
  71. #define mcserver_port 9876
  72. typedef struct _mcfs_connection mcfs_connection;
  73. typedef struct {
  74. int handle;
  75. mcfs_connection *conn;
  76. } mcfs_handle;
  77. static char *mcfs_gethome (mcfs_connection * mc);
  78. static int my_errno;
  79. static struct vfs_class vfs_mcfs_ops;
  80. /* Extract the hostname and username from the path */
  81. /* path is in the form: hostname:user/remote-dir */
  82. static char *
  83. mcfs_get_host_and_username (const char *path, char **host, char **user,
  84. int *port, char **pass)
  85. {
  86. return vfs_split_url (path, host, user, port, pass, 0, 0);
  87. }
  88. static void
  89. mcfs_fill_names (struct vfs_class *me, fill_names_f func)
  90. {
  91. int i;
  92. char *name;
  93. (void) me;
  94. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++) {
  95. if (mcfs_connections[i].host == 0)
  96. continue;
  97. name = g_strconcat ("/#mc:", mcfs_connections[i].user,
  98. "@", mcfs_connections[i].host, (char *) NULL);
  99. (*func) (name);
  100. g_free (name);
  101. }
  102. }
  103. /* This routine checks the server RPC version and logs the user in */
  104. static int
  105. mcfs_login_server (int my_socket, char *user, int port,
  106. int port_autodetected, char *netrcpass, int *version)
  107. {
  108. int result;
  109. char *pass;
  110. /* Send the version number */
  111. rpc_send (my_socket, RPC_INT, *version, RPC_END);
  112. if (0 == rpc_get (my_socket, RPC_INT, &result, RPC_END))
  113. return 0;
  114. if (result != MC_VERSION_OK) {
  115. message (D_ERROR, _(" MCFS "),
  116. _(" The server does not support this version "));
  117. close (my_socket);
  118. return 0;
  119. }
  120. /* FIXME: figure out why last_current_dir used to be passed here */
  121. rpc_send (my_socket, RPC_INT, MC_LOGIN, RPC_STRING, "/",
  122. RPC_STRING, user, RPC_END);
  123. if (0 == rpc_get (my_socket, RPC_INT, &result, RPC_END))
  124. return 0;
  125. if (result == MC_NEED_PASSWORD) {
  126. if (port > 1024 && port_autodetected) {
  127. int v;
  128. v = query_dialog (_("Warning"),
  129. _
  130. (" The remote server is not running on a system port \n"
  131. " you need a password to log in, but the information may \n"
  132. " not be safe on the remote side. Continue? \n"),
  133. D_ERROR, 2, _("&Yes"), _("&No"));
  134. if (v == 1) {
  135. close (my_socket);
  136. return 0;
  137. }
  138. }
  139. if (netrcpass != NULL)
  140. pass = g_strdup (netrcpass);
  141. else
  142. pass = vfs_get_password (_(" MCFS Password required "));
  143. if (!pass) {
  144. rpc_send (my_socket, RPC_INT, MC_QUIT, RPC_END);
  145. close (my_socket);
  146. return 0;
  147. }
  148. rpc_send (my_socket, RPC_INT, MC_PASS, RPC_STRING, pass, RPC_END);
  149. wipe_password (pass);
  150. if (0 == rpc_get (my_socket, RPC_INT, &result, RPC_END))
  151. return 0;
  152. if (result != MC_LOGINOK) {
  153. message (D_ERROR, _(" MCFS "), _(" Invalid password "));
  154. rpc_send (my_socket, RPC_INT, MC_QUIT, RPC_END);
  155. close (my_socket);
  156. return 0;
  157. }
  158. }
  159. return my_socket;
  160. }
  161. static int
  162. mcfs_get_remote_port (struct sockaddr_in *sin, int *version)
  163. {
  164. #ifdef HAVE_PMAP_GETMAPS
  165. int port;
  166. struct pmaplist *pl;
  167. *version = 1;
  168. port = mcserver_port;
  169. for (pl = pmap_getmaps (sin); pl; pl = pl->pml_next)
  170. if (pl->pml_map.pm_prog == RPC_PROGNUM
  171. && pl->pml_map.pm_prot == IPPROTO_TCP
  172. && pl->pml_map.pm_vers >= (unsigned long) *version) {
  173. *version = (int) pl->pml_map.pm_vers;
  174. port = pl->pml_map.pm_port;
  175. }
  176. return port;
  177. #else
  178. #ifdef HAVE_PMAP_GETPORT
  179. int port;
  180. for (*version = RPC_PROGVER; *version >= 1; (*version)--)
  181. port = pmap_getport (sin, RPC_PROGNUM, *version, IPPROTO_TCP);
  182. if (port != NULL)
  183. return port;
  184. #endif /* HAVE_PMAP_GETPORT */
  185. *version = 1;
  186. return mcserver_port;
  187. #endif /* HAVE_PMAP_GETMAPS */
  188. }
  189. /* This used to be in utilvfs.c, but as it deals with portmapper, it
  190. is probably useful for mcfs */
  191. static int
  192. mcfs_create_tcp_link (const char *host, int *port, int *version, const char *caller)
  193. {
  194. struct sockaddr_in server_address;
  195. unsigned long inaddr;
  196. struct hostent *hp;
  197. int my_socket;
  198. if (!*host)
  199. return 0;
  200. memset ((char *) &server_address, 0, sizeof (server_address));
  201. server_address.sin_family = AF_INET;
  202. /* Try to use the dotted decimal number */
  203. inaddr = inet_addr (host);
  204. if (inaddr != INADDR_NONE) {
  205. memcpy ((char *) &server_address.sin_addr, (char *) &inaddr,
  206. sizeof (inaddr));
  207. } else {
  208. hp = gethostbyname (host);
  209. if (hp == NULL) {
  210. message (D_ERROR, caller, _(" Cannot locate hostname: %s "),
  211. host);
  212. return 0;
  213. }
  214. memcpy ((char *) &server_address.sin_addr, (char *) hp->h_addr,
  215. hp->h_length);
  216. }
  217. /* Try to contact a remote portmapper to obtain the listening port */
  218. if (*port == 0) {
  219. *port = mcfs_get_remote_port (&server_address, version);
  220. if (*port < 1)
  221. return 0;
  222. } else
  223. *version = 1;
  224. server_address.sin_port = htons (*port);
  225. my_socket = socket (AF_INET, SOCK_STREAM, 0);
  226. if (my_socket < 0) {
  227. message (D_ERROR, caller, _(" Cannot create socket: %s "),
  228. unix_error_string (errno));
  229. return 0;
  230. }
  231. if (connect (my_socket, (struct sockaddr *) &server_address,
  232. sizeof (server_address)) < 0) {
  233. message (D_ERROR, caller, _(" Cannot connect to server: %s "),
  234. unix_error_string (errno));
  235. close (my_socket);
  236. return 0;
  237. }
  238. return my_socket;
  239. }
  240. static int
  241. mcfs_open_tcp_link (char *host, char *user,
  242. int *port, char *netrcpass, int *version)
  243. {
  244. int my_socket;
  245. int old_port = *port;
  246. my_socket = mcfs_create_tcp_link (host, port, version, " MCfs ");
  247. if (my_socket <= 0)
  248. return 0;
  249. /* We got the connection to the server, verify if the server
  250. implements our version of the RPC mechanism and then login
  251. the user.
  252. */
  253. return mcfs_login_server (my_socket, user, *port, old_port == 0,
  254. netrcpass, version);
  255. }
  256. static int mcfs_get_free_bucket_init = 1;
  257. static mcfs_connection *
  258. mcfs_get_free_bucket (void)
  259. {
  260. int i;
  261. if (mcfs_get_free_bucket_init) {
  262. mcfs_get_free_bucket_init = 0;
  263. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++)
  264. mcfs_connections[i].host = 0;
  265. }
  266. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++) {
  267. if (!mcfs_connections[i].host)
  268. return &mcfs_connections[i];
  269. }
  270. /* This can't happend, since we have checked for max connections before */
  271. vfs_die ("Internal error: mcfs_get_free_bucket");
  272. return 0; /* shut up, stupid gcc */
  273. }
  274. /* This routine keeps track of open connections */
  275. /* Returns a connected socket to host */
  276. static mcfs_connection *
  277. mcfs_open_link (char *host, char *user, int *port, char *netrcpass)
  278. {
  279. static int mcfs_open_connections = 0;
  280. int i, sock, version;
  281. mcfs_connection *bucket;
  282. /* Is the link actually open? */
  283. if (mcfs_get_free_bucket_init) {
  284. mcfs_get_free_bucket_init = 0;
  285. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++)
  286. mcfs_connections[i].host = 0;
  287. } else
  288. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++) {
  289. if (!mcfs_connections[i].host)
  290. continue;
  291. if ((strcmp (host, mcfs_connections[i].host) == 0) &&
  292. (strcmp (user, mcfs_connections[i].user) == 0))
  293. return &mcfs_connections[i];
  294. }
  295. if (mcfs_open_connections == MCFS_MAX_CONNECTIONS) {
  296. message (D_ERROR, MSG_ERROR, _(" Too many open connections "));
  297. return 0;
  298. }
  299. sock = mcfs_open_tcp_link (host, user, port, netrcpass, &version);
  300. if (sock == 0)
  301. return 0;
  302. bucket = mcfs_get_free_bucket ();
  303. mcfs_open_connections++;
  304. bucket->host = g_strdup (host);
  305. bucket->user = g_strdup (user);
  306. bucket->home = 0;
  307. bucket->port = *port;
  308. bucket->sock = sock;
  309. bucket->version = version;
  310. return bucket;
  311. }
  312. static int
  313. mcfs_is_error (int result, int errno_num)
  314. {
  315. if (!(result == -1))
  316. return my_errno = 0;
  317. else
  318. my_errno = errno_num;
  319. return 1;
  320. }
  321. static int
  322. mcfs_set_error (int result, int errno_num)
  323. {
  324. if (result == -1)
  325. my_errno = errno_num;
  326. else
  327. my_errno = 0;
  328. return result;
  329. }
  330. static char *
  331. mcfs_get_path (mcfs_connection **mc, const char *path)
  332. {
  333. char *user, *host, *remote_path;
  334. char *pass;
  335. int port;
  336. /* An absolute path name, try to determine connection socket */
  337. if (strncmp (path, "/#mc:", 5))
  338. return NULL;
  339. path += 5;
  340. /* Port = 0 means that mcfs_create_tcp_link will try to contact the
  341. * remote portmapper to get the port number
  342. */
  343. port = 0;
  344. remote_path = mcfs_get_host_and_username (path, &host, &user, &port, &pass);
  345. if (remote_path != NULL) {
  346. *mc = mcfs_open_link (host, user, &port, pass);
  347. if (*mc == NULL) {
  348. g_free (remote_path);
  349. remote_path = NULL;
  350. }
  351. }
  352. g_free (host);
  353. g_free (user);
  354. if (pass)
  355. wipe_password (pass);
  356. if (!remote_path)
  357. return NULL;
  358. /* NOTE: tildes are deprecated. See ftpfs.c */
  359. {
  360. int f = !strcmp (remote_path, "/~");
  361. if (f || !strncmp (remote_path, "/~/", 3)) {
  362. char *s;
  363. s = concat_dir_and_file (mcfs_gethome (*mc),
  364. remote_path + 3 - f);
  365. g_free (remote_path);
  366. remote_path = s;
  367. }
  368. }
  369. return remote_path;
  370. }
  371. /* Simple function for routines returning only an integer from the server */
  372. static int
  373. mcfs_handle_simple_error (int sock, int return_status)
  374. {
  375. int status, error;
  376. if (0 == rpc_get (sock, RPC_INT, &status, RPC_INT, &error, RPC_END))
  377. return mcfs_set_error (-1, EIO);
  378. if (mcfs_is_error (status, error))
  379. return -1;
  380. if (return_status)
  381. return status;
  382. return 0;
  383. }
  384. /* Nice wrappers */
  385. static int
  386. mcfs_rpc_two_paths (int command, const char *s1, const char *s2)
  387. {
  388. mcfs_connection *mc;
  389. char *r1, *r2;
  390. r1 = mcfs_get_path (&mc, s1);
  391. if (r1 == NULL)
  392. return -1;
  393. r2 = mcfs_get_path (&mc, s2);
  394. if (r2 == NULL) {
  395. g_free (r1);
  396. return -1;
  397. }
  398. rpc_send (mc->sock,
  399. RPC_INT, command, RPC_STRING, r1, RPC_STRING, r2, RPC_END);
  400. g_free (r1);
  401. g_free (r2);
  402. return mcfs_handle_simple_error (mc->sock, 0);
  403. }
  404. static int
  405. mcfs_rpc_path (int command, const char *path)
  406. {
  407. mcfs_connection *mc;
  408. char *remote_file;
  409. remote_file = mcfs_get_path (&mc, path);
  410. if (remote_file == NULL)
  411. return -1;
  412. rpc_send (mc->sock,
  413. RPC_INT, command, RPC_STRING, remote_file, RPC_END);
  414. g_free (remote_file);
  415. return mcfs_handle_simple_error (mc->sock, 0);
  416. }
  417. static int
  418. mcfs_rpc_path_int (int command, const char *path, int data)
  419. {
  420. mcfs_connection *mc;
  421. char *remote_file;
  422. remote_file = mcfs_get_path (&mc, path);
  423. if (remote_file == NULL)
  424. return -1;
  425. rpc_send (mc->sock,
  426. RPC_INT, command,
  427. RPC_STRING, remote_file, RPC_INT, data, RPC_END);
  428. g_free (remote_file);
  429. return mcfs_handle_simple_error (mc->sock, 0);
  430. }
  431. static int
  432. mcfs_rpc_path_int_int (int command, const char *path, int n1, int n2)
  433. {
  434. mcfs_connection *mc;
  435. char *remote_file;
  436. remote_file = mcfs_get_path (&mc, path);
  437. if (remote_file == NULL)
  438. return -1;
  439. rpc_send (mc->sock,
  440. RPC_INT, command,
  441. RPC_STRING, remote_file, RPC_INT, n1, RPC_INT, n2, RPC_END);
  442. g_free (remote_file);
  443. return mcfs_handle_simple_error (mc->sock, 0);
  444. }
  445. static char *
  446. mcfs_gethome (mcfs_connection *mc)
  447. {
  448. char *buffer;
  449. if (mc->home)
  450. return g_strdup (mc->home);
  451. else {
  452. rpc_send (mc->sock, RPC_INT, MC_GETHOME, RPC_END);
  453. if (0 == rpc_get (mc->sock, RPC_STRING, &buffer, RPC_END))
  454. return g_strdup (PATH_SEP_STR);
  455. mc->home = buffer;
  456. return g_strdup (buffer);
  457. }
  458. }
  459. /* The callbacks */
  460. static void *
  461. mcfs_open (struct vfs_class *me, const char *file, int flags, int mode)
  462. {
  463. char *remote_file;
  464. mcfs_connection *mc;
  465. int result, error_num;
  466. mcfs_handle *remote_handle;
  467. (void) me;
  468. remote_file = mcfs_get_path (&mc, file);
  469. if (remote_file == NULL)
  470. return 0;
  471. rpc_send (mc->sock, RPC_INT, MC_OPEN, RPC_STRING, remote_file, RPC_INT,
  472. flags, RPC_INT, mode, RPC_END);
  473. g_free (remote_file);
  474. if (0 ==
  475. rpc_get (mc->sock, RPC_INT, &result, RPC_INT, &error_num, RPC_END))
  476. return 0;
  477. if (mcfs_is_error (result, error_num))
  478. return 0;
  479. remote_handle = g_new (mcfs_handle, 2);
  480. remote_handle->handle = result;
  481. remote_handle->conn = mc;
  482. return remote_handle;
  483. }
  484. static ssize_t
  485. mcfs_read (void *data, char *buffer, int count)
  486. {
  487. mcfs_handle *info = (mcfs_handle *) data;
  488. int result, error;
  489. int handle;
  490. mcfs_connection *mc;
  491. mc = info->conn;
  492. handle = info->handle;
  493. rpc_send (mc->sock, RPC_INT, MC_READ, RPC_INT, handle,
  494. RPC_INT, count, RPC_END);
  495. if (0 ==
  496. rpc_get (mc->sock, RPC_INT, &result, RPC_INT, &error, RPC_END))
  497. return mcfs_set_error (-1, EIO);
  498. if (mcfs_is_error (result, error))
  499. return 0;
  500. if (0 == rpc_get (mc->sock, RPC_BLOCK, result, buffer, RPC_END))
  501. return mcfs_set_error (-1, EIO);
  502. return result;
  503. }
  504. static ssize_t
  505. mcfs_write (void *data, const char *buf, int nbyte)
  506. {
  507. mcfs_handle *info = (mcfs_handle *) data;
  508. mcfs_connection *mc;
  509. int handle;
  510. mc = info->conn;
  511. handle = info->handle;
  512. rpc_send (mc->sock,
  513. RPC_INT, MC_WRITE,
  514. RPC_INT, handle,
  515. RPC_INT, nbyte, RPC_BLOCK, nbyte, buf, RPC_END);
  516. return mcfs_handle_simple_error (mc->sock, 1);
  517. }
  518. static int
  519. mcfs_close (void *data)
  520. {
  521. mcfs_handle *info = (mcfs_handle *) data;
  522. mcfs_connection *mc;
  523. int handle, result, error;
  524. if (!data)
  525. return -1;
  526. handle = info->handle;
  527. mc = info->conn;
  528. rpc_send (mc->sock, RPC_INT, MC_CLOSE, RPC_INT, handle, RPC_END);
  529. if (0 ==
  530. rpc_get (mc->sock, RPC_INT, &result, RPC_INT, &error, RPC_END))
  531. return mcfs_set_error (-1, EIO);
  532. mcfs_is_error (result, error);
  533. g_free (data);
  534. return result;
  535. }
  536. static int
  537. mcfs_errno (struct vfs_class *me)
  538. {
  539. (void) me;
  540. return my_errno;
  541. }
  542. typedef struct dir_entry {
  543. char *text;
  544. struct dir_entry *next;
  545. struct stat my_stat;
  546. int merrno;
  547. } dir_entry;
  548. typedef struct {
  549. mcfs_connection *conn;
  550. int handle;
  551. dir_entry *entries;
  552. dir_entry *current;
  553. } opendir_info;
  554. static void *
  555. mcfs_opendir (struct vfs_class *me, const char *dirname)
  556. {
  557. opendir_info *mcfs_info;
  558. mcfs_connection *mc;
  559. int handle, error_num;
  560. char *remote_dir;
  561. int result;
  562. (void) me;
  563. remote_dir = mcfs_get_path (&mc, dirname);
  564. if (remote_dir == NULL)
  565. return NULL;
  566. rpc_send (mc->sock, RPC_INT, MC_OPENDIR, RPC_STRING, remote_dir,
  567. RPC_END);
  568. g_free (remote_dir);
  569. if (0 ==
  570. rpc_get (mc->sock, RPC_INT, &result, RPC_INT, &error_num, RPC_END))
  571. return NULL;
  572. if (mcfs_is_error (result, error_num))
  573. return NULL;
  574. handle = result;
  575. mcfs_info = g_new (opendir_info, 1);
  576. mcfs_info->conn = mc;
  577. mcfs_info->handle = handle;
  578. mcfs_info->entries = 0;
  579. mcfs_info->current = 0;
  580. return (void *) mcfs_info;
  581. }
  582. static int mcfs_get_stat_info (mcfs_connection * mc, struct stat *buf);
  583. static int
  584. mcfs_loaddir (opendir_info *mcfs_info)
  585. {
  586. int status, error;
  587. mcfs_connection *mc = mcfs_info->conn;
  588. int lc_link = mc->sock;
  589. int first = 1;
  590. rpc_send (lc_link, RPC_INT, MC_READDIR, RPC_INT, mcfs_info->handle,
  591. RPC_END);
  592. for (;;) {
  593. int entry_len;
  594. dir_entry *new_entry;
  595. if (!rpc_get (lc_link, RPC_INT, &entry_len, RPC_END))
  596. return 0;
  597. if (entry_len == 0)
  598. break;
  599. new_entry = g_new (dir_entry, 1);
  600. new_entry->text = g_new0 (char, entry_len + 1);
  601. new_entry->next = 0;
  602. if (first) {
  603. mcfs_info->entries = new_entry;
  604. mcfs_info->current = new_entry;
  605. first = 0;
  606. } else {
  607. mcfs_info->current->next = new_entry;
  608. mcfs_info->current = new_entry;
  609. }
  610. if (!rpc_get
  611. (lc_link, RPC_BLOCK, entry_len, new_entry->text, RPC_END))
  612. return 0;
  613. /* Then we get the status from the lstat */
  614. if (!rpc_get (lc_link, RPC_INT, &status, RPC_INT, &error, RPC_END))
  615. return 0;
  616. if (mcfs_is_error (status, error))
  617. new_entry->merrno = error;
  618. else {
  619. new_entry->merrno = 0;
  620. if (!mcfs_get_stat_info (mc, &(new_entry->my_stat)))
  621. return 0;
  622. }
  623. }
  624. mcfs_info->current = mcfs_info->entries;
  625. return 1;
  626. }
  627. static void
  628. mcfs_free_dir (dir_entry *de)
  629. {
  630. if (!de)
  631. return;
  632. mcfs_free_dir (de->next);
  633. g_free (de->text);
  634. g_free (de);
  635. }
  636. static union vfs_dirent mcfs_readdir_data;
  637. /* The readdir routine loads the complete directory */
  638. /* It's too slow to ask the server each time */
  639. /* It now also sends the complete lstat information for each file */
  640. static struct stat *cached_lstat_info;
  641. static void *
  642. mcfs_readdir (void *info)
  643. {
  644. opendir_info *mcfs_info;
  645. char *dirent_dest;
  646. mcfs_info = (opendir_info *) info;
  647. if (!mcfs_info->entries)
  648. if (!mcfs_loaddir (mcfs_info))
  649. return NULL;
  650. if (mcfs_info->current == 0) {
  651. cached_lstat_info = 0;
  652. mcfs_free_dir (mcfs_info->entries);
  653. mcfs_info->entries = 0;
  654. return NULL;
  655. }
  656. dirent_dest = mcfs_readdir_data.dent.d_name;
  657. g_strlcpy (dirent_dest, mcfs_info->current->text, MC_MAXPATHLEN);
  658. cached_lstat_info = &mcfs_info->current->my_stat;
  659. mcfs_info->current = mcfs_info->current->next;
  660. compute_namelen (&mcfs_readdir_data.dent);
  661. return &mcfs_readdir_data;
  662. }
  663. static int
  664. mcfs_closedir (void *info)
  665. {
  666. opendir_info *mcfs_info = (opendir_info *) info;
  667. dir_entry *p, *q;
  668. rpc_send (mcfs_info->conn->sock, RPC_INT, MC_CLOSEDIR,
  669. RPC_INT, mcfs_info->handle, RPC_END);
  670. for (p = mcfs_info->entries; p;) {
  671. q = p;
  672. p = p->next;
  673. g_free (q->text);
  674. g_free (q);
  675. }
  676. g_free (info);
  677. return 0;
  678. }
  679. static time_t
  680. mcfs_get_time (mcfs_connection *mc)
  681. {
  682. int sock = mc->sock;
  683. if (mc->version == 1) {
  684. struct tm tt;
  685. rpc_get (sock,
  686. RPC_INT, &tt.tm_sec,
  687. RPC_INT, &tt.tm_min,
  688. RPC_INT, &tt.tm_hour,
  689. RPC_INT, &tt.tm_mday,
  690. RPC_INT, &tt.tm_year, RPC_INT, &tt.tm_mon, RPC_END);
  691. tt.tm_year -= 1900;
  692. tt.tm_isdst = 0;
  693. return mktime (&tt);
  694. } else {
  695. char *buf;
  696. long tm;
  697. rpc_get (sock, RPC_STRING, &buf, RPC_END);
  698. sscanf (buf, "%lx", &tm);
  699. g_free (buf);
  700. return (time_t) tm;
  701. }
  702. }
  703. static int
  704. mcfs_get_stat_info (mcfs_connection *mc, struct stat *buf)
  705. {
  706. long mylong;
  707. int sock = mc->sock;
  708. buf->st_dev = 0;
  709. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  710. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  711. buf->st_rdev = mylong;
  712. #endif
  713. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  714. buf->st_ino = mylong;
  715. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  716. buf->st_mode = mylong;
  717. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  718. buf->st_nlink = mylong;
  719. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  720. buf->st_uid = mylong;
  721. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  722. buf->st_gid = mylong;
  723. rpc_get (sock, RPC_INT, &mylong, RPC_END);
  724. buf->st_size = mylong;
  725. if (!rpc_get (sock, RPC_INT, &mylong, RPC_END))
  726. return 0;
  727. #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
  728. buf->st_blocks = mylong;
  729. #endif
  730. buf->st_atime = mcfs_get_time (mc);
  731. buf->st_mtime = mcfs_get_time (mc);
  732. buf->st_ctime = mcfs_get_time (mc);
  733. return 1;
  734. }
  735. static int
  736. mcfs_stat_cmd (int cmd, const char *path, struct stat *buf)
  737. {
  738. char *remote_file;
  739. mcfs_connection *mc;
  740. int status, error;
  741. remote_file = mcfs_get_path (&mc, path);
  742. if (remote_file == NULL)
  743. return -1;
  744. rpc_send (mc->sock, RPC_INT, cmd, RPC_STRING, remote_file, RPC_END);
  745. g_free (remote_file);
  746. if (!rpc_get (mc->sock, RPC_INT, &status, RPC_INT, &error, RPC_END))
  747. return mcfs_set_error (-1, errno);
  748. if (mcfs_is_error (status, error))
  749. return -1;
  750. if (mcfs_get_stat_info (mc, buf))
  751. return 0;
  752. else
  753. return mcfs_set_error (-1, EIO);
  754. }
  755. static int
  756. mcfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
  757. {
  758. (void) me;
  759. return mcfs_stat_cmd (MC_STAT, path, buf);
  760. }
  761. static int
  762. mcfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
  763. {
  764. int path_len = strlen (path);
  765. int entry_len = strlen (mcfs_readdir_data.dent.d_name);
  766. (void) me;
  767. /* Hack ... */
  768. if (strcmp (path + path_len - entry_len,
  769. mcfs_readdir_data.dent.d_name) == 0 && cached_lstat_info) {
  770. *buf = *cached_lstat_info;
  771. return 0;
  772. }
  773. return mcfs_stat_cmd (MC_LSTAT, path, buf);
  774. }
  775. static int
  776. mcfs_fstat (void *data, struct stat *buf)
  777. {
  778. mcfs_handle *info = (mcfs_handle *) data;
  779. int result, error;
  780. int handle, sock;
  781. sock = info->conn->sock;
  782. handle = info->handle;
  783. rpc_send (sock, RPC_INT, MC_FSTAT, RPC_INT, handle, RPC_END);
  784. if (!rpc_get (sock, RPC_INT, &result, RPC_INT, &error, RPC_END))
  785. return mcfs_set_error (-1, EIO);
  786. if (mcfs_is_error (result, error))
  787. return -1;
  788. if (mcfs_get_stat_info (info->conn, buf))
  789. return 0;
  790. else
  791. return mcfs_set_error (-1, EIO);
  792. }
  793. static int
  794. mcfs_chmod (struct vfs_class *me, const char *path, int mode)
  795. {
  796. (void) me;
  797. return mcfs_rpc_path_int (MC_CHMOD, path, mode);
  798. }
  799. static int
  800. mcfs_chown (struct vfs_class *me, const char *path, int owner, int group)
  801. {
  802. (void) me;
  803. return mcfs_rpc_path_int_int (MC_CHOWN, path, owner, group);
  804. }
  805. static int
  806. mcfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
  807. {
  808. mcfs_connection *mc;
  809. int status;
  810. char *file;
  811. (void) me;
  812. file = mcfs_get_path (&mc, path);
  813. if (file == NULL)
  814. return -1;
  815. status = 0;
  816. if (mc->version >= 2) {
  817. char abuf[BUF_SMALL];
  818. char mbuf[BUF_SMALL];
  819. long atime, mtime;
  820. atime = (long) times->actime;
  821. mtime = (long) times->modtime;
  822. g_snprintf (abuf, sizeof (abuf), "%lx", atime);
  823. g_snprintf (mbuf, sizeof (mbuf), "%lx", mtime);
  824. rpc_send (mc->sock, RPC_INT, MC_UTIME,
  825. RPC_STRING, file,
  826. RPC_STRING, abuf, RPC_STRING, mbuf, RPC_END);
  827. status = mcfs_handle_simple_error (mc->sock, 0);
  828. }
  829. g_free (file);
  830. return (status);
  831. }
  832. static int
  833. mcfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
  834. {
  835. char *remote_file, *stat_str;
  836. int status, error;
  837. mcfs_connection *mc;
  838. size_t len;
  839. (void) me;
  840. remote_file = mcfs_get_path (&mc, path);
  841. if (remote_file == NULL)
  842. return -1;
  843. rpc_send (mc->sock, RPC_INT, MC_READLINK, RPC_STRING, remote_file,
  844. RPC_END);
  845. g_free (remote_file);
  846. if (!rpc_get (mc->sock, RPC_INT, &status, RPC_INT, &error, RPC_END))
  847. return mcfs_set_error (-1, EIO);
  848. if (mcfs_is_error (status, errno))
  849. return -1;
  850. if (!rpc_get (mc->sock, RPC_STRING, &stat_str, RPC_END))
  851. return mcfs_set_error (-1, EIO);
  852. len = strlen (stat_str);
  853. if (len < size)
  854. size = len;
  855. /* readlink() does not append a NUL character to buf */
  856. memcpy (buf, stat_str, size);
  857. g_free (stat_str);
  858. return size;
  859. }
  860. static int
  861. mcfs_unlink (struct vfs_class *me, const char *path)
  862. {
  863. (void) me;
  864. return mcfs_rpc_path (MC_UNLINK, path);
  865. }
  866. static int
  867. mcfs_symlink (struct vfs_class *me, const char *n1, const char *n2)
  868. {
  869. (void) me;
  870. return mcfs_rpc_two_paths (MC_SYMLINK, n1, n2);
  871. }
  872. static int
  873. mcfs_rename (struct vfs_class *me, const char *a, const char *b)
  874. {
  875. (void) me;
  876. return mcfs_rpc_two_paths (MC_RENAME, a, b);
  877. }
  878. static int
  879. mcfs_chdir (struct vfs_class *me, const char *path)
  880. {
  881. char *remote_dir;
  882. mcfs_connection *mc;
  883. int status, error;
  884. (void) me;
  885. remote_dir = mcfs_get_path (&mc, path);
  886. if (remote_dir == NULL)
  887. return -1;
  888. rpc_send (mc->sock, RPC_INT, MC_CHDIR, RPC_STRING, remote_dir,
  889. RPC_END);
  890. g_free (remote_dir);
  891. if (!rpc_get (mc->sock, RPC_INT, &status, RPC_INT, &error, RPC_END))
  892. return mcfs_set_error (-1, EIO);
  893. if (mcfs_is_error (status, error))
  894. return -1;
  895. return 0;
  896. }
  897. static off_t
  898. mcfs_lseek (void *data, off_t offset, int whence)
  899. {
  900. mcfs_handle *info = (mcfs_handle *) data;
  901. int handle, sock;
  902. sock = info->conn->sock;
  903. handle = info->handle;
  904. /* FIXME: off_t may be too long to fit */
  905. rpc_send (sock, RPC_INT, MC_LSEEK, RPC_INT, handle, RPC_INT,
  906. (int) offset, RPC_INT, whence, RPC_END);
  907. return mcfs_handle_simple_error (sock, 1);
  908. }
  909. static int
  910. mcfs_mknod (struct vfs_class *me, const char *path, int mode, int dev)
  911. {
  912. (void) me;
  913. return mcfs_rpc_path_int_int (MC_MKNOD, path, mode, dev);
  914. }
  915. static int
  916. mcfs_mkdir (struct vfs_class *me, const char *path, mode_t mode)
  917. {
  918. (void) me;
  919. return mcfs_rpc_path_int (MC_MKDIR, path, mode);
  920. }
  921. static int
  922. mcfs_rmdir (struct vfs_class *me, const char *path)
  923. {
  924. (void) me;
  925. return mcfs_rpc_path (MC_RMDIR, path);
  926. }
  927. static int
  928. mcfs_link (struct vfs_class *me, const char *p1, const char *p2)
  929. {
  930. (void) me;
  931. return mcfs_rpc_two_paths (MC_LINK, p1, p2);
  932. }
  933. /* Gives up on a socket and reopens the connection, the child own the socket
  934. * now
  935. */
  936. static void
  937. mcfs_forget (const char *path)
  938. {
  939. char *host, *user, *pass, *p;
  940. int port, i, vers;
  941. if (strncmp (path, "/#mc:", 5))
  942. return;
  943. path += 5;
  944. if ((path[0] == '/') && (path[1] == '/'))
  945. path += 2;
  946. p = mcfs_get_host_and_username (path, &host, &user, &port, &pass);
  947. if (p == NULL) {
  948. g_free (host);
  949. g_free (user);
  950. if (pass)
  951. wipe_password (pass);
  952. return;
  953. }
  954. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++) {
  955. if ((strcmp (host, mcfs_connections[i].host) == 0) &&
  956. (strcmp (user, mcfs_connections[i].user) == 0) &&
  957. (port == mcfs_connections[i].port)) {
  958. /* close socket: the child owns it now */
  959. close (mcfs_connections[i].sock);
  960. /* reopen the connection */
  961. mcfs_connections[i].sock =
  962. mcfs_open_tcp_link (host, user, &port, pass, &vers);
  963. }
  964. }
  965. g_free (p);
  966. g_free (host);
  967. g_free (user);
  968. if (pass)
  969. wipe_password (pass);
  970. }
  971. static int
  972. mcfs_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
  973. {
  974. (void) me;
  975. (void) arg;
  976. switch (ctlop) {
  977. case VFS_SETCTL_FORGET:
  978. mcfs_forget (path);
  979. return 0;
  980. }
  981. return 0;
  982. }
  983. void
  984. init_mcfs (void)
  985. {
  986. tcp_init();
  987. vfs_mcfs_ops.name = "mcfs";
  988. vfs_mcfs_ops.prefix = "mc:";
  989. vfs_mcfs_ops.fill_names = mcfs_fill_names;
  990. vfs_mcfs_ops.open = mcfs_open;
  991. vfs_mcfs_ops.close = mcfs_close;
  992. vfs_mcfs_ops.read = mcfs_read;
  993. vfs_mcfs_ops.write = mcfs_write;
  994. vfs_mcfs_ops.opendir = mcfs_opendir;
  995. vfs_mcfs_ops.readdir = mcfs_readdir;
  996. vfs_mcfs_ops.closedir = mcfs_closedir;
  997. vfs_mcfs_ops.stat = mcfs_stat;
  998. vfs_mcfs_ops.lstat = mcfs_lstat;
  999. vfs_mcfs_ops.fstat = mcfs_fstat;
  1000. vfs_mcfs_ops.chmod = mcfs_chmod;
  1001. vfs_mcfs_ops.chown = mcfs_chown;
  1002. vfs_mcfs_ops.utime = mcfs_utime;
  1003. vfs_mcfs_ops.readlink = mcfs_readlink;
  1004. vfs_mcfs_ops.symlink = mcfs_symlink;
  1005. vfs_mcfs_ops.link = mcfs_link;
  1006. vfs_mcfs_ops.unlink = mcfs_unlink;
  1007. vfs_mcfs_ops.rename = mcfs_rename;
  1008. vfs_mcfs_ops.chdir = mcfs_chdir;
  1009. vfs_mcfs_ops.ferrno = mcfs_errno;
  1010. vfs_mcfs_ops.lseek = mcfs_lseek;
  1011. vfs_mcfs_ops.mknod = mcfs_mknod;
  1012. vfs_mcfs_ops.mkdir = mcfs_mkdir;
  1013. vfs_mcfs_ops.rmdir = mcfs_rmdir;
  1014. vfs_mcfs_ops.setctl = mcfs_setctl;
  1015. vfs_register_class (&vfs_mcfs_ops);
  1016. }
  1017. static void
  1018. mcfs_free_bucket (int bucket)
  1019. {
  1020. g_free (mcfs_connections[bucket].host);
  1021. g_free (mcfs_connections[bucket].user);
  1022. g_free (mcfs_connections[bucket].home);
  1023. /* Set all the fields to zero */
  1024. mcfs_connections[bucket].host =
  1025. mcfs_connections[bucket].user = mcfs_connections[bucket].home = 0;
  1026. mcfs_connections[bucket].sock = mcfs_connections[bucket].version = 0;
  1027. }
  1028. static int
  1029. mcfs_invalidate_socket (int sock)
  1030. {
  1031. int i, j = -1;
  1032. for (i = 0; i < MCFS_MAX_CONNECTIONS; i++)
  1033. if (mcfs_connections[i].sock == sock) {
  1034. mcfs_free_bucket (i);
  1035. j = 0;
  1036. }
  1037. if (j == -1)
  1038. return -1; /* It was not our sock */
  1039. /* Break from any possible loop */
  1040. mc_chdir ("/");
  1041. return 0;
  1042. }
  1043. void
  1044. tcp_invalidate_socket (int sock)
  1045. {
  1046. mcfs_invalidate_socket (sock);
  1047. }
  1048. #endif /* ENABLE_VFS_MCFS */