1 /* Virtual File System: Midnight Commander file system.
3 Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2007 Free Software Foundation, Inc.
6 Written by Miguel de Icaza
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public License
12 as published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
26 * \brief Source: Midnight Commander file system
27 * \author Miguel de Icaza
28 * \author Andrej Borsenkow
29 * \author Norbert Warmuth
31 * Namespace: exports mcfs_vfs_ops, tcp_invalidate_socket
36 #ifdef ENABLE_VFS_MCFS
44 #include <sys/types.h> /* POSIX-required by sys/socket.h and netdb.h */
45 #include <netdb.h> /* struct hostent */
46 #include <sys/socket.h> /* AF_INET */
47 #include <netinet/in.h> /* struct in_addr */
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
54 #include <rpc/pmap_prot.h>
55 #ifdef HAVE_RPC_PMAP_CLNT_H
56 #include <rpc/pmap_clnt.h>
60 #include "lib/global.h"
61 #include "src/wtools.h" /* message() */
62 #include "src/main.h" /* print_vfs_message */
71 # define INADDR_NONE (0xffffffffU)
74 #define MCFS_MAX_CONNECTIONS 32
76 static struct _mcfs_connection
{
83 } mcfs_connections
[MCFS_MAX_CONNECTIONS
];
86 #define mcserver_port 9876
88 typedef struct _mcfs_connection mcfs_connection
;
92 mcfs_connection
*conn
;
95 static char *mcfs_gethome (mcfs_connection
* mc
);
97 static struct vfs_class vfs_mcfs_ops
;
99 /* Extract the hostname and username from the path */
100 /* path is in the form: hostname:user/remote-dir */
102 mcfs_get_host_and_username (const char *path
, char **host
, char **user
,
103 int *port
, char **pass
)
105 return vfs_split_url (path
, host
, user
, port
, pass
, 0, 0);
109 mcfs_fill_names (struct vfs_class
*me
, fill_names_f func
)
116 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
117 if (mcfs_connections
[i
].host
== 0)
119 name
= g_strconcat ("/#mc:", mcfs_connections
[i
].user
,
120 "@", mcfs_connections
[i
].host
, (char *) NULL
);
126 /* This routine checks the server RPC version and logs the user in */
128 mcfs_login_server (int my_socket
, char *user
, int port
,
129 int port_autodetected
, char *netrcpass
, int *version
)
134 /* Send the version number */
135 rpc_send (my_socket
, RPC_INT
, *version
, RPC_END
);
136 if (0 == rpc_get (my_socket
, RPC_INT
, &result
, RPC_END
))
139 if (result
!= MC_VERSION_OK
) {
140 message (D_ERROR
, _(" MCFS "),
141 _(" The server does not support this version "));
146 /* FIXME: figure out why last_current_dir used to be passed here */
147 rpc_send (my_socket
, RPC_INT
, MC_LOGIN
, RPC_STRING
, "/",
148 RPC_STRING
, user
, RPC_END
);
150 if (0 == rpc_get (my_socket
, RPC_INT
, &result
, RPC_END
))
153 if (result
== MC_NEED_PASSWORD
) {
154 if (port
> 1024 && port_autodetected
) {
156 v
= query_dialog (_("Warning"),
158 (" The remote server is not running on a system port \n"
159 " you need a password to log in, but the information may \n"
160 " not be safe on the remote side. Continue? \n"),
161 D_ERROR
, 2, _("&Yes"), _("&No"));
168 if (netrcpass
!= NULL
)
169 pass
= g_strdup (netrcpass
);
171 pass
= vfs_get_password (_(" MCFS Password required "));
173 rpc_send (my_socket
, RPC_INT
, MC_QUIT
, RPC_END
);
177 rpc_send (my_socket
, RPC_INT
, MC_PASS
, RPC_STRING
, pass
, RPC_END
);
179 wipe_password (pass
);
181 if (0 == rpc_get (my_socket
, RPC_INT
, &result
, RPC_END
))
184 if (result
!= MC_LOGINOK
) {
185 message (D_ERROR
, _(" MCFS "), _(" Invalid password "));
186 rpc_send (my_socket
, RPC_INT
, MC_QUIT
, RPC_END
);
195 mcfs_get_remote_port (struct sockaddr_in
*sin
, int *version
)
197 #ifdef HAVE_PMAP_GETMAPS
202 port
= mcserver_port
;
203 for (pl
= pmap_getmaps (sin
); pl
; pl
= pl
->pml_next
)
204 if (pl
->pml_map
.pm_prog
== RPC_PROGNUM
205 && pl
->pml_map
.pm_prot
== IPPROTO_TCP
206 && pl
->pml_map
.pm_vers
>= (unsigned long) *version
) {
207 *version
= (int) pl
->pml_map
.pm_vers
;
208 port
= pl
->pml_map
.pm_port
;
212 #ifdef HAVE_PMAP_GETPORT
214 for (*version
= RPC_PROGVER
; *version
>= 1; (*version
)--)
215 port
= pmap_getport (sin
, RPC_PROGNUM
, *version
, IPPROTO_TCP
);
218 #endif /* HAVE_PMAP_GETPORT */
220 return mcserver_port
;
221 #endif /* HAVE_PMAP_GETMAPS */
224 /* This used to be in utilvfs.c, but as it deals with portmapper, it
225 is probably useful for mcfs */
227 mcfs_create_tcp_link (const char *host
, int *port
, int *version
, const char *caller
)
229 struct sockaddr_in server_address
;
230 unsigned long inaddr
;
237 memset ((char *) &server_address
, 0, sizeof (server_address
));
238 server_address
.sin_family
= AF_INET
;
240 /* Try to use the dotted decimal number */
241 inaddr
= inet_addr (host
);
242 if (inaddr
!= INADDR_NONE
) {
243 memcpy ((char *) &server_address
.sin_addr
, (char *) &inaddr
,
246 hp
= gethostbyname (host
);
248 message (D_ERROR
, caller
, _(" Cannot locate hostname: %s "),
252 memcpy ((char *) &server_address
.sin_addr
, (char *) hp
->h_addr
,
256 /* Try to contact a remote portmapper to obtain the listening port */
258 *port
= mcfs_get_remote_port (&server_address
, version
);
264 server_address
.sin_port
= htons (*port
);
265 my_socket
= socket (AF_INET
, SOCK_STREAM
, 0);
267 message (D_ERROR
, caller
, _(" Cannot create socket: %s "),
268 unix_error_string (errno
));
271 if (connect (my_socket
, (struct sockaddr
*) &server_address
,
272 sizeof (server_address
)) < 0) {
273 message (D_ERROR
, caller
, _(" Cannot connect to server: %s "),
274 unix_error_string (errno
));
282 mcfs_open_tcp_link (char *host
, char *user
,
283 int *port
, char *netrcpass
, int *version
)
286 int old_port
= *port
;
288 my_socket
= mcfs_create_tcp_link (host
, port
, version
, " MCfs ");
292 /* We got the connection to the server, verify if the server
293 implements our version of the RPC mechanism and then login
296 return mcfs_login_server (my_socket
, user
, *port
, old_port
== 0,
300 static int mcfs_get_free_bucket_init
= 1;
301 static mcfs_connection
*
302 mcfs_get_free_bucket (void)
306 if (mcfs_get_free_bucket_init
) {
307 mcfs_get_free_bucket_init
= 0;
308 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++)
309 mcfs_connections
[i
].host
= 0;
311 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
312 if (!mcfs_connections
[i
].host
)
313 return &mcfs_connections
[i
];
315 /* This can't happend, since we have checked for max connections before */
316 vfs_die ("Internal error: mcfs_get_free_bucket");
317 return 0; /* shut up, stupid gcc */
320 /* This routine keeps track of open connections */
321 /* Returns a connected socket to host */
322 static mcfs_connection
*
323 mcfs_open_link (char *host
, char *user
, int *port
, char *netrcpass
)
325 static int mcfs_open_connections
= 0;
326 int i
, sock
, version
;
327 mcfs_connection
*bucket
;
329 /* Is the link actually open? */
330 if (mcfs_get_free_bucket_init
) {
331 mcfs_get_free_bucket_init
= 0;
332 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++)
333 mcfs_connections
[i
].host
= 0;
335 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
336 if (!mcfs_connections
[i
].host
)
338 if ((strcmp (host
, mcfs_connections
[i
].host
) == 0) &&
339 (strcmp (user
, mcfs_connections
[i
].user
) == 0))
340 return &mcfs_connections
[i
];
342 if (mcfs_open_connections
== MCFS_MAX_CONNECTIONS
) {
343 message (D_ERROR
, MSG_ERROR
, _(" Too many open connections "));
346 sock
= mcfs_open_tcp_link (host
, user
, port
, netrcpass
, &version
);
350 bucket
= mcfs_get_free_bucket ();
351 mcfs_open_connections
++;
352 bucket
->host
= g_strdup (host
);
353 bucket
->user
= g_strdup (user
);
355 bucket
->port
= *port
;
357 bucket
->version
= version
;
363 mcfs_is_error (int result
, int errno_num
)
368 my_errno
= errno_num
;
373 mcfs_set_error (int result
, int errno_num
)
376 my_errno
= errno_num
;
383 mcfs_get_path (mcfs_connection
**mc
, const char *path
)
385 char *user
, *host
, *remote_path
;
389 /* An absolute path name, try to determine connection socket */
390 if (strncmp (path
, "/#mc:", 5))
394 /* Port = 0 means that mcfs_create_tcp_link will try to contact the
395 * remote portmapper to get the port number
398 remote_path
= mcfs_get_host_and_username (path
, &host
, &user
, &port
, &pass
);
399 if (remote_path
!= NULL
) {
400 *mc
= mcfs_open_link (host
, user
, &port
, pass
);
402 g_free (remote_path
);
409 wipe_password (pass
);
414 /* NOTE: tildes are deprecated. See ftpfs.c */
416 int f
= !strcmp (remote_path
, "/~");
417 if (f
|| !strncmp (remote_path
, "/~/", 3)) {
419 s
= concat_dir_and_file (mcfs_gethome (*mc
),
420 remote_path
+ 3 - f
);
421 g_free (remote_path
);
428 /* Simple function for routines returning only an integer from the server */
430 mcfs_handle_simple_error (int sock
, int return_status
)
434 if (0 == rpc_get (sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
435 return mcfs_set_error (-1, EIO
);
437 if (mcfs_is_error (status
, error
))
446 mcfs_rpc_two_paths (int command
, const char *s1
, const char *s2
)
451 r1
= mcfs_get_path (&mc
, s1
);
455 r2
= mcfs_get_path (&mc
, s2
);
462 RPC_INT
, command
, RPC_STRING
, r1
, RPC_STRING
, r2
, RPC_END
);
465 return mcfs_handle_simple_error (mc
->sock
, 0);
469 mcfs_rpc_path (int command
, const char *path
)
474 remote_file
= mcfs_get_path (&mc
, path
);
475 if (remote_file
== NULL
)
479 RPC_INT
, command
, RPC_STRING
, remote_file
, RPC_END
);
481 g_free (remote_file
);
482 return mcfs_handle_simple_error (mc
->sock
, 0);
486 mcfs_rpc_path_int (int command
, const char *path
, int data
)
491 remote_file
= mcfs_get_path (&mc
, path
);
492 if (remote_file
== NULL
)
497 RPC_STRING
, remote_file
, RPC_INT
, data
, RPC_END
);
499 g_free (remote_file
);
500 return mcfs_handle_simple_error (mc
->sock
, 0);
504 mcfs_rpc_path_int_int (int command
, const char *path
, int n1
, int n2
)
509 remote_file
= mcfs_get_path (&mc
, path
);
510 if (remote_file
== NULL
)
515 RPC_STRING
, remote_file
, RPC_INT
, n1
, RPC_INT
, n2
, RPC_END
);
517 g_free (remote_file
);
518 return mcfs_handle_simple_error (mc
->sock
, 0);
522 mcfs_gethome (mcfs_connection
*mc
)
527 return g_strdup (mc
->home
);
529 rpc_send (mc
->sock
, RPC_INT
, MC_GETHOME
, RPC_END
);
530 if (0 == rpc_get (mc
->sock
, RPC_STRING
, &buffer
, RPC_END
))
531 return g_strdup (PATH_SEP_STR
);
533 return g_strdup (buffer
);
539 mcfs_open (struct vfs_class
*me
, const char *file
, int flags
, int mode
)
543 int result
, error_num
;
544 mcfs_handle
*remote_handle
;
548 remote_file
= mcfs_get_path (&mc
, file
);
549 if (remote_file
== NULL
)
552 rpc_send (mc
->sock
, RPC_INT
, MC_OPEN
, RPC_STRING
, remote_file
, RPC_INT
,
553 flags
, RPC_INT
, mode
, RPC_END
);
554 g_free (remote_file
);
557 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error_num
, RPC_END
))
560 if (mcfs_is_error (result
, error_num
))
563 remote_handle
= g_new (mcfs_handle
, 2);
564 remote_handle
->handle
= result
;
565 remote_handle
->conn
= mc
;
567 return remote_handle
;
571 mcfs_read (void *data
, char *buffer
, int count
)
573 mcfs_handle
*info
= (mcfs_handle
*) data
;
579 handle
= info
->handle
;
581 rpc_send (mc
->sock
, RPC_INT
, MC_READ
, RPC_INT
, handle
,
582 RPC_INT
, count
, RPC_END
);
585 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error
, RPC_END
))
586 return mcfs_set_error (-1, EIO
);
588 if (mcfs_is_error (result
, error
))
591 if (0 == rpc_get (mc
->sock
, RPC_BLOCK
, result
, buffer
, RPC_END
))
592 return mcfs_set_error (-1, EIO
);
598 mcfs_write (void *data
, const char *buf
, int nbyte
)
600 mcfs_handle
*info
= (mcfs_handle
*) data
;
605 handle
= info
->handle
;
610 RPC_INT
, nbyte
, RPC_BLOCK
, nbyte
, buf
, RPC_END
);
612 return mcfs_handle_simple_error (mc
->sock
, 1);
616 mcfs_close (void *data
)
618 mcfs_handle
*info
= (mcfs_handle
*) data
;
620 int handle
, result
, error
;
625 handle
= info
->handle
;
628 rpc_send (mc
->sock
, RPC_INT
, MC_CLOSE
, RPC_INT
, handle
, RPC_END
);
631 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error
, RPC_END
))
632 return mcfs_set_error (-1, EIO
);
634 mcfs_is_error (result
, error
);
641 mcfs_errno (struct vfs_class
*me
)
648 typedef struct dir_entry
{
650 struct dir_entry
*next
;
656 mcfs_connection
*conn
;
663 mcfs_opendir (struct vfs_class
*me
, const char *dirname
)
665 opendir_info
*mcfs_info
;
667 int handle
, error_num
;
673 remote_dir
= mcfs_get_path (&mc
, dirname
);
674 if (remote_dir
== NULL
)
677 rpc_send (mc
->sock
, RPC_INT
, MC_OPENDIR
, RPC_STRING
, remote_dir
,
682 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error_num
, RPC_END
))
685 if (mcfs_is_error (result
, error_num
))
690 mcfs_info
= g_new (opendir_info
, 1);
691 mcfs_info
->conn
= mc
;
692 mcfs_info
->handle
= handle
;
693 mcfs_info
->entries
= 0;
694 mcfs_info
->current
= 0;
696 return (void *) mcfs_info
;
699 static int mcfs_get_stat_info (mcfs_connection
* mc
, struct stat
*buf
);
702 mcfs_loaddir (opendir_info
*mcfs_info
)
705 mcfs_connection
*mc
= mcfs_info
->conn
;
706 int lc_link
= mc
->sock
;
709 rpc_send (lc_link
, RPC_INT
, MC_READDIR
, RPC_INT
, mcfs_info
->handle
,
714 dir_entry
*new_entry
;
716 if (!rpc_get (lc_link
, RPC_INT
, &entry_len
, RPC_END
))
722 new_entry
= g_new (dir_entry
, 1);
723 new_entry
->text
= g_new0 (char, entry_len
+ 1);
727 mcfs_info
->entries
= new_entry
;
728 mcfs_info
->current
= new_entry
;
731 mcfs_info
->current
->next
= new_entry
;
732 mcfs_info
->current
= new_entry
;
736 (lc_link
, RPC_BLOCK
, entry_len
, new_entry
->text
, RPC_END
))
739 /* Then we get the status from the lstat */
740 if (!rpc_get (lc_link
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
743 if (mcfs_is_error (status
, error
))
744 new_entry
->merrno
= error
;
746 new_entry
->merrno
= 0;
747 if (!mcfs_get_stat_info (mc
, &(new_entry
->my_stat
)))
751 mcfs_info
->current
= mcfs_info
->entries
;
757 mcfs_free_dir (dir_entry
*de
)
761 mcfs_free_dir (de
->next
);
766 static union vfs_dirent mcfs_readdir_data
;
768 /* The readdir routine loads the complete directory */
769 /* It's too slow to ask the server each time */
770 /* It now also sends the complete lstat information for each file */
771 static struct stat
*cached_lstat_info
;
774 mcfs_readdir (void *info
)
776 opendir_info
*mcfs_info
;
779 mcfs_info
= (opendir_info
*) info
;
781 if (!mcfs_info
->entries
)
782 if (!mcfs_loaddir (mcfs_info
))
785 if (mcfs_info
->current
== 0) {
786 cached_lstat_info
= 0;
787 mcfs_free_dir (mcfs_info
->entries
);
788 mcfs_info
->entries
= 0;
791 dirent_dest
= mcfs_readdir_data
.dent
.d_name
;
792 g_strlcpy (dirent_dest
, mcfs_info
->current
->text
, MC_MAXPATHLEN
);
793 cached_lstat_info
= &mcfs_info
->current
->my_stat
;
794 mcfs_info
->current
= mcfs_info
->current
->next
;
796 compute_namelen (&mcfs_readdir_data
.dent
);
798 return &mcfs_readdir_data
;
802 mcfs_closedir (void *info
)
804 opendir_info
*mcfs_info
= (opendir_info
*) info
;
807 rpc_send (mcfs_info
->conn
->sock
, RPC_INT
, MC_CLOSEDIR
,
808 RPC_INT
, mcfs_info
->handle
, RPC_END
);
810 for (p
= mcfs_info
->entries
; p
;) {
821 mcfs_get_time (mcfs_connection
*mc
)
825 if (mc
->version
== 1) {
831 RPC_INT
, &tt
.tm_hour
,
832 RPC_INT
, &tt
.tm_mday
,
833 RPC_INT
, &tt
.tm_year
, RPC_INT
, &tt
.tm_mon
, RPC_END
);
842 rpc_get (sock
, RPC_STRING
, &buf
, RPC_END
);
843 sscanf (buf
, "%lx", &tm
);
851 mcfs_get_stat_info (mcfs_connection
*mc
, struct stat
*buf
)
858 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
859 #ifdef HAVE_STRUCT_STAT_ST_RDEV
860 buf
->st_rdev
= mylong
;
862 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
863 buf
->st_ino
= mylong
;
864 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
865 buf
->st_mode
= mylong
;
866 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
867 buf
->st_nlink
= mylong
;
868 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
869 buf
->st_uid
= mylong
;
870 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
871 buf
->st_gid
= mylong
;
872 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
873 buf
->st_size
= mylong
;
875 if (!rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
))
877 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
878 buf
->st_blocks
= mylong
;
880 buf
->st_atime
= mcfs_get_time (mc
);
881 buf
->st_mtime
= mcfs_get_time (mc
);
882 buf
->st_ctime
= mcfs_get_time (mc
);
887 mcfs_stat_cmd (int cmd
, const char *path
, struct stat
*buf
)
893 remote_file
= mcfs_get_path (&mc
, path
);
894 if (remote_file
== NULL
)
897 rpc_send (mc
->sock
, RPC_INT
, cmd
, RPC_STRING
, remote_file
, RPC_END
);
898 g_free (remote_file
);
899 if (!rpc_get (mc
->sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
900 return mcfs_set_error (-1, errno
);
902 if (mcfs_is_error (status
, error
))
905 if (mcfs_get_stat_info (mc
, buf
))
908 return mcfs_set_error (-1, EIO
);
912 mcfs_stat (struct vfs_class
*me
, const char *path
, struct stat
*buf
)
916 return mcfs_stat_cmd (MC_STAT
, path
, buf
);
920 mcfs_lstat (struct vfs_class
*me
, const char *path
, struct stat
*buf
)
922 int path_len
= strlen (path
);
923 int entry_len
= strlen (mcfs_readdir_data
.dent
.d_name
);
928 if (strcmp (path
+ path_len
- entry_len
,
929 mcfs_readdir_data
.dent
.d_name
) == 0 && cached_lstat_info
) {
930 *buf
= *cached_lstat_info
;
933 return mcfs_stat_cmd (MC_LSTAT
, path
, buf
);
937 mcfs_fstat (void *data
, struct stat
*buf
)
939 mcfs_handle
*info
= (mcfs_handle
*) data
;
943 sock
= info
->conn
->sock
;
944 handle
= info
->handle
;
946 rpc_send (sock
, RPC_INT
, MC_FSTAT
, RPC_INT
, handle
, RPC_END
);
947 if (!rpc_get (sock
, RPC_INT
, &result
, RPC_INT
, &error
, RPC_END
))
948 return mcfs_set_error (-1, EIO
);
950 if (mcfs_is_error (result
, error
))
953 if (mcfs_get_stat_info (info
->conn
, buf
))
956 return mcfs_set_error (-1, EIO
);
960 mcfs_chmod (struct vfs_class
*me
, const char *path
, int mode
)
964 return mcfs_rpc_path_int (MC_CHMOD
, path
, mode
);
968 mcfs_chown (struct vfs_class
*me
, const char *path
, int owner
, int group
)
972 return mcfs_rpc_path_int_int (MC_CHOWN
, path
, owner
, group
);
976 mcfs_utime (struct vfs_class
*me
, const char *path
, struct utimbuf
*times
)
984 remote_file
= mcfs_get_path (&mc
, path
);
985 if (remote_file
== NULL
)
989 if (mc
->version
>= 2) {
990 char abuf
[BUF_SMALL
];
991 char mbuf
[BUF_SMALL
];
994 atime
= (long) times
->actime
;
995 mtime
= (long) times
->modtime
;
997 g_snprintf (abuf
, sizeof (abuf
), "%lx", atime
);
998 g_snprintf (mbuf
, sizeof (mbuf
), "%lx", mtime
);
1000 rpc_send (mc
->sock
, RPC_INT
, MC_UTIME
,
1002 RPC_STRING
, abuf
, RPC_STRING
, mbuf
, RPC_END
);
1003 status
= mcfs_handle_simple_error (mc
->sock
, 0);
1011 mcfs_readlink (struct vfs_class
*me
, const char *path
, char *buf
, size_t size
)
1013 char *remote_file
, *stat_str
;
1015 mcfs_connection
*mc
;
1020 remote_file
= mcfs_get_path (&mc
, path
);
1021 if (remote_file
== NULL
)
1024 rpc_send (mc
->sock
, RPC_INT
, MC_READLINK
, RPC_STRING
, remote_file
,
1026 g_free (remote_file
);
1027 if (!rpc_get (mc
->sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
1028 return mcfs_set_error (-1, EIO
);
1030 if (mcfs_is_error (status
, errno
))
1033 if (!rpc_get (mc
->sock
, RPC_STRING
, &stat_str
, RPC_END
))
1034 return mcfs_set_error (-1, EIO
);
1036 len
= strlen (stat_str
);
1039 /* readlink() does not append a NUL character to buf */
1040 memcpy (buf
, stat_str
, size
);
1046 mcfs_unlink (struct vfs_class
*me
, const char *path
)
1050 return mcfs_rpc_path (MC_UNLINK
, path
);
1054 mcfs_symlink (struct vfs_class
*me
, const char *n1
, const char *n2
)
1058 return mcfs_rpc_two_paths (MC_SYMLINK
, n1
, n2
);
1062 mcfs_rename (struct vfs_class
*me
, const char *a
, const char *b
)
1066 return mcfs_rpc_two_paths (MC_RENAME
, a
, b
);
1070 mcfs_chdir (struct vfs_class
*me
, const char *path
)
1073 mcfs_connection
*mc
;
1078 remote_file
= mcfs_get_path (&mc
, path
);
1079 if (remote_file
== NULL
)
1082 rpc_send (mc
->sock
, RPC_INT
, MC_CHDIR
, RPC_STRING
, remote_dir
,
1084 g_free (remote_dir
);
1085 if (!rpc_get (mc
->sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
1086 return mcfs_set_error (-1, EIO
);
1088 if (mcfs_is_error (status
, error
))
1094 mcfs_lseek (void *data
, off_t offset
, int whence
)
1096 mcfs_handle
*info
= (mcfs_handle
*) data
;
1099 sock
= info
->conn
->sock
;
1100 handle
= info
->handle
;
1102 /* FIXME: off_t may be too long to fit */
1103 rpc_send (sock
, RPC_INT
, MC_LSEEK
, RPC_INT
, handle
, RPC_INT
,
1104 (int) offset
, RPC_INT
, whence
, RPC_END
);
1106 return mcfs_handle_simple_error (sock
, 1);
1110 mcfs_mknod (struct vfs_class
*me
, const char *path
, int mode
, int dev
)
1114 return mcfs_rpc_path_int_int (MC_MKNOD
, path
, mode
, dev
);
1118 mcfs_mkdir (struct vfs_class
*me
, const char *path
, mode_t mode
)
1122 return mcfs_rpc_path_int (MC_MKDIR
, path
, mode
);
1126 mcfs_rmdir (struct vfs_class
*me
, const char *path
)
1130 return mcfs_rpc_path (MC_RMDIR
, path
);
1134 mcfs_link (struct vfs_class
*me
, const char *p1
, const char *p2
)
1138 return mcfs_rpc_two_paths (MC_LINK
, p1
, p2
);
1141 /* Gives up on a socket and reopens the connection, the child own the socket
1145 mcfs_forget (const char *path
)
1147 char *host
, *user
, *pass
, *p
;
1150 if (strncmp (path
, "/#mc:", 5))
1154 if ((path
[0] == '/') && (path
[1] == '/'))
1157 p
= mcfs_get_host_and_username (path
, &host
, &user
, &port
, &pass
);
1162 wipe_password (pass
);
1165 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
1166 if ((strcmp (host
, mcfs_connections
[i
].host
) == 0) &&
1167 (strcmp (user
, mcfs_connections
[i
].user
) == 0) &&
1168 (port
== mcfs_connections
[i
].port
)) {
1170 /* close socket: the child owns it now */
1171 close (mcfs_connections
[i
].sock
);
1173 /* reopen the connection */
1174 mcfs_connections
[i
].sock
=
1175 mcfs_open_tcp_link (host
, user
, &port
, pass
, &vers
);
1182 wipe_password (pass
);
1186 mcfs_setctl (struct vfs_class
*me
, const char *path
, int ctlop
, void *arg
)
1192 case VFS_SETCTL_FORGET
:
1204 vfs_mcfs_ops
.name
= "mcfs";
1205 vfs_mcfs_ops
.prefix
= "mc:";
1206 vfs_mcfs_ops
.fill_names
= mcfs_fill_names
;
1207 vfs_mcfs_ops
.open
= mcfs_open
;
1208 vfs_mcfs_ops
.close
= mcfs_close
;
1209 vfs_mcfs_ops
.read
= mcfs_read
;
1210 vfs_mcfs_ops
.write
= mcfs_write
;
1211 vfs_mcfs_ops
.opendir
= mcfs_opendir
;
1212 vfs_mcfs_ops
.readdir
= mcfs_readdir
;
1213 vfs_mcfs_ops
.closedir
= mcfs_closedir
;
1214 vfs_mcfs_ops
.stat
= mcfs_stat
;
1215 vfs_mcfs_ops
.lstat
= mcfs_lstat
;
1216 vfs_mcfs_ops
.fstat
= mcfs_fstat
;
1217 vfs_mcfs_ops
.chmod
= mcfs_chmod
;
1218 vfs_mcfs_ops
.chown
= mcfs_chown
;
1219 vfs_mcfs_ops
.utime
= mcfs_utime
;
1220 vfs_mcfs_ops
.readlink
= mcfs_readlink
;
1221 vfs_mcfs_ops
.symlink
= mcfs_symlink
;
1222 vfs_mcfs_ops
.link
= mcfs_link
;
1223 vfs_mcfs_ops
.unlink
= mcfs_unlink
;
1224 vfs_mcfs_ops
.rename
= mcfs_rename
;
1225 vfs_mcfs_ops
.chdir
= mcfs_chdir
;
1226 vfs_mcfs_ops
.ferrno
= mcfs_errno
;
1227 vfs_mcfs_ops
.lseek
= mcfs_lseek
;
1228 vfs_mcfs_ops
.mknod
= mcfs_mknod
;
1229 vfs_mcfs_ops
.mkdir
= mcfs_mkdir
;
1230 vfs_mcfs_ops
.rmdir
= mcfs_rmdir
;
1231 vfs_mcfs_ops
.setctl
= mcfs_setctl
;
1232 vfs_register_class (&vfs_mcfs_ops
);
1236 mcfs_free_bucket (int bucket
)
1238 g_free (mcfs_connections
[bucket
].host
);
1239 g_free (mcfs_connections
[bucket
].user
);
1240 g_free (mcfs_connections
[bucket
].home
);
1242 /* Set all the fields to zero */
1243 mcfs_connections
[bucket
].host
=
1244 mcfs_connections
[bucket
].user
= mcfs_connections
[bucket
].home
= 0;
1245 mcfs_connections
[bucket
].sock
= mcfs_connections
[bucket
].version
= 0;
1249 mcfs_invalidate_socket (int sock
)
1253 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++)
1254 if (mcfs_connections
[i
].sock
== sock
) {
1255 mcfs_free_bucket (i
);
1260 return -1; /* It was not our sock */
1261 /* Break from any possible loop */
1267 tcp_invalidate_socket (int sock
)
1269 mcfs_invalidate_socket (sock
);
1271 #endif /* ENABLE_VFS_MCFS */