home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / vfs / mcfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  22.6 KB  |  1,010 lines

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