mcfs.c 27 KB

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