mcfs.c 27 KB

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