1 /* Virtual File System: Midnight Commander file system.
3 Copyright (C) 1995, 1996, 1997 The Free Software Foundation
5 Written by Miguel de Icaza
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License
11 as published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 /* Namespace: exports mcfs_vfs_ops, tcp_invalidate_socket */
35 #include <sys/types.h> /* POSIX-required by sys/socket.h and netdb.h */
36 #include <netdb.h> /* struct hostent */
37 #include <sys/socket.h> /* AF_INET */
38 #include <netinet/in.h> /* struct in_addr */
39 #ifdef HAVE_ARPA_INET_H
40 #include <arpa/inet.h>
45 #include <rpc/pmap_prot.h>
46 #ifdef HAVE_RPC_PMAP_CLNT_H
47 #include <rpc/pmap_clnt.h>
57 #include "../src/dialog.h"
59 #define MCFS_MAX_CONNECTIONS 32
61 static struct _mcfs_connection
{
68 } mcfs_connections
[MCFS_MAX_CONNECTIONS
];
71 #define mcserver_port 9876
73 typedef struct _mcfs_connection mcfs_connection
;
77 mcfs_connection
*conn
;
82 static char *mcfs_gethome (mcfs_connection
* mc
);
84 /* Extract the hostname and username from the path */
85 /* path is in the form: hostname:user/remote-dir */
87 mcfs_get_host_and_username (char *path
, char **host
, char **user
,
88 int *port
, char **pass
)
90 return vfs_split_url (path
, host
, user
, port
, pass
, 0, 0);
94 mcfs_fill_names (vfs
*me
, void (*func
) (char *))
99 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
100 if (mcfs_connections
[i
].host
== 0)
102 name
= g_strconcat ("/#mc:", mcfs_connections
[i
].user
,
103 "@", mcfs_connections
[i
].host
, NULL
);
109 /* This routine checks the server RPC version and logs the user in */
111 mcfs_login_server (int my_socket
, char *user
, int port
,
112 int port_autodetected
, char *netrcpass
, int *version
)
117 /* Send the version number */
118 rpc_send (my_socket
, RPC_INT
, *version
, RPC_END
);
119 if (0 == rpc_get (my_socket
, RPC_INT
, &result
, RPC_END
))
122 if (result
!= MC_VERSION_OK
) {
123 message_1s (1, _(" MCFS "),
124 _(" The server does not support this version "));
129 /* FIXME: figure out why last_current_dir used to be passed here */
130 rpc_send (my_socket
, RPC_INT
, MC_LOGIN
, RPC_STRING
, "/",
131 RPC_STRING
, user
, RPC_END
);
133 if (0 == rpc_get (my_socket
, RPC_INT
, &result
, RPC_END
))
136 if (result
== MC_NEED_PASSWORD
) {
137 if (port
> 1024 && port_autodetected
) {
139 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"),
144 3, 2, _("&Yes"), _("&No"));
151 if (netrcpass
!= NULL
)
152 pass
= g_strdup (netrcpass
);
154 pass
= vfs_get_password (_(" MCFS Password required "));
156 rpc_send (my_socket
, RPC_INT
, MC_QUIT
, RPC_END
);
160 rpc_send (my_socket
, RPC_INT
, MC_PASS
, RPC_STRING
, pass
, RPC_END
);
162 wipe_password (pass
);
164 if (0 == rpc_get (my_socket
, RPC_INT
, &result
, RPC_END
))
167 if (result
!= MC_LOGINOK
) {
168 message_1s (1, _(" MCFS "), _(" Invalid password "));
169 rpc_send (my_socket
, RPC_INT
, MC_QUIT
, RPC_END
);
178 get_remote_port (struct sockaddr_in
*sin
, int *version
)
180 #ifdef HAVE_PMAP_GETMAPS
185 port
= mcserver_port
;
186 for (pl
= pmap_getmaps (sin
); pl
; pl
= pl
->pml_next
)
187 if (pl
->pml_map
.pm_prog
== RPC_PROGNUM
188 && pl
->pml_map
.pm_prot
== IPPROTO_TCP
189 && pl
->pml_map
.pm_vers
>= *version
) {
190 *version
= pl
->pml_map
.pm_vers
;
191 port
= pl
->pml_map
.pm_port
;
195 #ifdef HAVE_PMAP_GETPORT
197 for (*version
= RPC_PROGVER
; *version
>= 1; (*version
)--)
198 if (port
= pmap_getport (sin
, RPC_PROGNUM
, *version
, IPPROTO_TCP
))
200 #endif /* HAVE_PMAP_GETPORT */
201 #endif /* HAVE_PMAP_GETMAPS */
203 return mcserver_port
;
206 /* This used to be in utilvfs.c, but as it deals with portmapper, it
207 is probably usefull for mcfs */
209 open_tcp_link (char *host
, int *port
, int *version
, char *caller
)
211 struct sockaddr_in server_address
;
212 unsigned long inaddr
;
219 memset ((char *) &server_address
, 0, sizeof (server_address
));
220 server_address
.sin_family
= AF_INET
;
222 /* Try to use the dotted decimal number */
223 if ((inaddr
= inet_addr (host
)) != -1)
224 memcpy ((char *) &server_address
.sin_addr
, (char *) &inaddr
,
227 if ((hp
= gethostbyname (host
)) == NULL
) {
228 message_2s (1, caller
, _(" Cannot locate hostname: %s "),
232 memcpy ((char *) &server_address
.sin_addr
, (char *) hp
->h_addr
,
236 /* Try to contact a remote portmapper to obtain the listening port */
238 *port
= get_remote_port (&server_address
, version
);
244 server_address
.sin_port
= htons (*port
);
246 if ((my_socket
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0) {
247 message_2s (1, caller
, _(" Cannot create socket: %s "),
248 unix_error_string (errno
));
251 if (connect (my_socket
, (struct sockaddr
*) &server_address
,
252 sizeof (server_address
)) < 0) {
253 message_2s (1, caller
, _(" Cannot connect to server: %s "),
254 unix_error_string (errno
));
262 mcfs_open_tcp_link (char *host
, char *user
,
263 int *port
, char *netrcpass
, int *version
)
266 int old_port
= *port
;
268 my_socket
= open_tcp_link (host
, port
, version
, " MCfs ");
272 /* We got the connection to the server, verify if the server
273 implements our version of the RPC mechanism and then login
276 return mcfs_login_server (my_socket
, user
, *port
, old_port
== 0,
280 static int mcfs_get_free_bucket_init
= 1;
281 static mcfs_connection
*
282 mcfs_get_free_bucket (void)
286 if (mcfs_get_free_bucket_init
) {
287 mcfs_get_free_bucket_init
= 0;
288 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++)
289 mcfs_connections
[i
].host
= 0;
291 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
292 if (!mcfs_connections
[i
].host
)
293 return &mcfs_connections
[i
];
295 /* This can't happend, since we have checked for max connections before */
296 vfs_die ("Internal error: mcfs_get_free_bucket");
297 return 0; /* shut up, stupid gcc */
300 /* This routine keeps track of open connections */
301 /* Returns a connected socket to host */
302 static mcfs_connection
*
303 mcfs_open_link (char *host
, char *user
, int *port
, char *netrcpass
)
305 static int mcfs_open_connections
= 0;
306 int i
, sock
, version
;
307 mcfs_connection
*bucket
;
309 /* Is the link actually open? */
310 if (mcfs_get_free_bucket_init
) {
311 mcfs_get_free_bucket_init
= 0;
312 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++)
313 mcfs_connections
[i
].host
= 0;
315 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
316 if (!mcfs_connections
[i
].host
)
318 if ((strcmp (host
, mcfs_connections
[i
].host
) == 0) &&
319 (strcmp (user
, mcfs_connections
[i
].user
) == 0))
320 return &mcfs_connections
[i
];
322 if (mcfs_open_connections
== MCFS_MAX_CONNECTIONS
) {
323 message_1s (1, MSG_ERROR
, _(" Too many open connections "));
329 mcfs_open_tcp_link (host
, user
, port
, netrcpass
, &version
)))
332 bucket
= mcfs_get_free_bucket ();
333 mcfs_open_connections
++;
334 bucket
->host
= g_strdup (host
);
335 bucket
->user
= g_strdup (user
);
337 bucket
->port
= *port
;
339 bucket
->version
= version
;
345 is_error (int result
, int errno_num
)
350 my_errno
= errno_num
;
355 the_error (int result
, int errno_num
)
358 my_errno
= errno_num
;
365 mcfs_get_path (mcfs_connection
**mc
, char *path
)
367 char *user
, *host
, *remote_path
;
371 /* An absolute path name, try to determine connection socket */
372 if (strncmp (path
, "/#mc:", 5))
376 /* Port = 0 means that open_tcp_link will try to contact the
377 * remote portmapper to get the port number
381 mcfs_get_host_and_username (path
, &host
, &user
, &port
, &pass
)))
382 if (!(*mc
= mcfs_open_link (host
, user
, &port
, pass
))) {
383 g_free (remote_path
);
389 wipe_password (pass
);
394 /* NOTE: tildes are deprecated. See ftpfs.c */
396 int f
= !strcmp (remote_path
, "/~");
397 if (f
|| !strncmp (remote_path
, "/~/", 3)) {
399 s
= concat_dir_and_file (mcfs_gethome (*mc
),
400 remote_path
+ 3 - f
);
401 g_free (remote_path
);
408 /* Simple function for routines returning only an integer from the server */
410 mcfs_handle_simple_error (int sock
, int return_status
)
414 if (0 == rpc_get (sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
415 return the_error (-1, EIO
);
417 if (is_error (status
, error
))
426 mcfs_rpc_two_paths (int command
, char *s1
, char *s2
)
431 if ((r1
= mcfs_get_path (&mc
, s1
)) == 0)
434 if ((r2
= mcfs_get_path (&mc
, s2
)) == 0) {
440 RPC_INT
, command
, RPC_STRING
, r1
, RPC_STRING
, r2
, RPC_END
);
443 return mcfs_handle_simple_error (mc
->sock
, 0);
447 mcfs_rpc_path (int command
, char *path
)
452 if ((remote_file
= mcfs_get_path (&mc
, path
)) == 0)
456 RPC_INT
, command
, RPC_STRING
, remote_file
, RPC_END
);
458 g_free (remote_file
);
459 return mcfs_handle_simple_error (mc
->sock
, 0);
463 mcfs_rpc_path_int (int command
, char *path
, int data
)
468 if ((remote_file
= mcfs_get_path (&mc
, path
)) == 0)
473 RPC_STRING
, remote_file
, RPC_INT
, data
, RPC_END
);
475 g_free (remote_file
);
476 return mcfs_handle_simple_error (mc
->sock
, 0);
480 mcfs_rpc_path_int_int (int command
, char *path
, int n1
, int n2
)
485 if ((remote_file
= mcfs_get_path (&mc
, path
)) == 0)
490 RPC_STRING
, remote_file
, RPC_INT
, n1
, RPC_INT
, n2
, RPC_END
);
492 g_free (remote_file
);
493 return mcfs_handle_simple_error (mc
->sock
, 0);
497 mcfs_gethome (mcfs_connection
*mc
)
502 return g_strdup (mc
->home
);
504 rpc_send (mc
->sock
, RPC_INT
, MC_GETHOME
, RPC_END
);
505 if (0 == rpc_get (mc
->sock
, RPC_STRING
, &buffer
, RPC_END
))
506 return g_strdup (PATH_SEP_STR
);
508 return g_strdup (buffer
);
514 mcfs_open (vfs
*me
, char *file
, int flags
, int mode
)
518 int result
, error_num
;
519 mcfs_handle
*remote_handle
;
521 if (!(remote_file
= mcfs_get_path (&mc
, file
)))
524 rpc_send (mc
->sock
, RPC_INT
, MC_OPEN
, RPC_STRING
, remote_file
,
525 RPC_INT
, flags
, RPC_INT
, mode
, RPC_END
);
526 g_free (remote_file
);
529 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error_num
, RPC_END
))
532 if (is_error (result
, error_num
))
535 remote_handle
= g_new (mcfs_handle
, 2);
536 remote_handle
->handle
= result
;
537 remote_handle
->conn
= mc
;
539 return remote_handle
;
543 mcfs_read (void *data
, char *buffer
, int count
)
545 mcfs_handle
*info
= (mcfs_handle
*) data
;
551 handle
= info
->handle
;
553 rpc_send (mc
->sock
, RPC_INT
, MC_READ
, RPC_INT
, handle
,
554 RPC_INT
, count
, RPC_END
);
557 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error
, RPC_END
))
558 return the_error (-1, EIO
);
560 if (is_error (result
, error
))
563 if (0 == rpc_get (mc
->sock
, RPC_BLOCK
, result
, buffer
, RPC_END
))
564 return the_error (-1, EIO
);
570 mcfs_write (void *data
, char *buf
, int nbyte
)
572 mcfs_handle
*info
= (mcfs_handle
*) data
;
577 handle
= info
->handle
;
582 RPC_INT
, nbyte
, RPC_BLOCK
, nbyte
, buf
, RPC_END
);
584 return mcfs_handle_simple_error (mc
->sock
, 1);
588 mcfs_close (void *data
)
590 mcfs_handle
*info
= (mcfs_handle
*) data
;
592 int handle
, result
, error
;
597 handle
= info
->handle
;
600 rpc_send (mc
->sock
, RPC_INT
, MC_CLOSE
, RPC_INT
, handle
, RPC_END
);
603 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error
, RPC_END
))
604 return the_error (-1, EIO
);
606 is_error (result
, error
);
618 typedef struct dir_entry
{
620 struct dir_entry
*next
;
626 mcfs_connection
*conn
;
633 mcfs_opendir (vfs
*me
, char *dirname
)
635 opendir_info
*mcfs_info
;
637 int handle
, error_num
;
641 if (!(remote_dir
= mcfs_get_path (&mc
, dirname
)))
644 rpc_send (mc
->sock
, RPC_INT
, MC_OPENDIR
, RPC_STRING
, remote_dir
,
649 rpc_get (mc
->sock
, RPC_INT
, &result
, RPC_INT
, &error_num
, RPC_END
))
652 if (is_error (result
, error_num
))
657 mcfs_info
= g_new (opendir_info
, 1);
658 mcfs_info
->conn
= mc
;
659 mcfs_info
->handle
= handle
;
660 mcfs_info
->entries
= 0;
661 mcfs_info
->current
= 0;
666 static int get_stat_info (mcfs_connection
* mc
, struct stat
*buf
);
669 mcfs_loaddir (opendir_info
*mcfs_info
)
672 mcfs_connection
*mc
= mcfs_info
->conn
;
676 rpc_send (link
, RPC_INT
, MC_READDIR
, RPC_INT
, mcfs_info
->handle
,
681 dir_entry
*new_entry
;
683 if (!rpc_get (link
, RPC_INT
, &entry_len
, RPC_END
))
689 new_entry
= g_new (dir_entry
, 1);
690 new_entry
->text
= g_new0 (char, entry_len
+ 1);
694 mcfs_info
->entries
= new_entry
;
695 mcfs_info
->current
= new_entry
;
698 mcfs_info
->current
->next
= new_entry
;
699 mcfs_info
->current
= new_entry
;
703 (link
, RPC_BLOCK
, entry_len
, new_entry
->text
, RPC_END
))
706 /* Then we get the status from the lstat */
707 if (!rpc_get (link
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
710 if (is_error (status
, error
))
711 new_entry
->merrno
= error
;
713 new_entry
->merrno
= 0;
714 if (!get_stat_info (mc
, &(new_entry
->my_stat
)))
718 mcfs_info
->current
= mcfs_info
->entries
;
724 mcfs_free_dir (dir_entry
*de
)
728 mcfs_free_dir (de
->next
);
733 static union vfs_dirent mcfs_readdir_data
;
735 /* The readdir routine loads the complete directory */
736 /* It's too slow to ask the server each time */
737 /* It now also sends the complete lstat information for each file */
738 static struct stat
*cached_lstat_info
;
741 mcfs_readdir (void *info
)
743 opendir_info
*mcfs_info
;
746 mcfs_info
= (opendir_info
*) info
;
748 if (!mcfs_info
->entries
)
749 if (!mcfs_loaddir (mcfs_info
))
752 if (mcfs_info
->current
== 0) {
753 cached_lstat_info
= 0;
754 mcfs_free_dir (mcfs_info
->entries
);
755 mcfs_info
->entries
= 0;
758 dirent_dest
= mcfs_readdir_data
.dent
.d_name
;
759 strncpy (dirent_dest
, mcfs_info
->current
->text
, MC_MAXPATHLEN
);
760 dirent_dest
[MC_MAXPATHLEN
] = 0;
761 cached_lstat_info
= &mcfs_info
->current
->my_stat
;
762 mcfs_info
->current
= mcfs_info
->current
->next
;
764 compute_namelen (&mcfs_readdir_data
.dent
);
766 return &mcfs_readdir_data
;
770 mcfs_closedir (void *info
)
772 opendir_info
*mcfs_info
= (opendir_info
*) info
;
775 rpc_send (mcfs_info
->conn
->sock
, RPC_INT
, MC_CLOSEDIR
,
776 RPC_INT
, mcfs_info
->handle
, RPC_END
);
778 for (p
= mcfs_info
->entries
; p
;) {
789 mcfs_get_time (mcfs_connection
*mc
)
793 if (mc
->version
== 1) {
799 RPC_INT
, &tt
.tm_hour
,
800 RPC_INT
, &tt
.tm_mday
,
801 RPC_INT
, &tt
.tm_year
, RPC_INT
, &tt
.tm_mon
, RPC_END
);
810 rpc_get (sock
, RPC_STRING
, &buf
, RPC_END
);
811 sscanf (buf
, "%lx", &tm
);
819 get_stat_info (mcfs_connection
*mc
, struct stat
*buf
)
826 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
828 buf
->st_rdev
= mylong
;
830 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
831 buf
->st_ino
= mylong
;
832 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
833 buf
->st_mode
= mylong
;
834 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
835 buf
->st_nlink
= mylong
;
836 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
837 buf
->st_uid
= mylong
;
838 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
839 buf
->st_gid
= mylong
;
840 rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
);
841 buf
->st_size
= mylong
;
843 if (!rpc_get (sock
, RPC_INT
, &mylong
, RPC_END
))
845 #ifdef HAVE_ST_BLOCKS
846 buf
->st_blocks
= mylong
;
848 buf
->st_atime
= mcfs_get_time (mc
);
849 buf
->st_mtime
= mcfs_get_time (mc
);
850 buf
->st_ctime
= mcfs_get_time (mc
);
855 mcfs_stat_cmd (int cmd
, char *path
, struct stat
*buf
)
861 if ((remote_file
= mcfs_get_path (&mc
, path
)) == 0)
864 rpc_send (mc
->sock
, RPC_INT
, cmd
, RPC_STRING
, remote_file
, RPC_END
);
865 g_free (remote_file
);
866 if (!rpc_get (mc
->sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
867 return the_error (-1, errno
);
869 if (is_error (status
, error
))
872 if (get_stat_info (mc
, buf
))
875 return the_error (-1, EIO
);
879 mcfs_stat (vfs
*me
, char *path
, struct stat
*buf
)
881 return mcfs_stat_cmd (MC_STAT
, path
, buf
);
885 mcfs_lstat (vfs
*me
, char *path
, struct stat
*buf
)
887 int path_len
= strlen (path
);
888 int entry_len
= strlen (mcfs_readdir_data
.dent
.d_name
);
891 if (strcmp (path
+ path_len
- entry_len
,
892 mcfs_readdir_data
.dent
.d_name
) == 0 && cached_lstat_info
) {
893 *buf
= *cached_lstat_info
;
896 return mcfs_stat_cmd (MC_LSTAT
, path
, buf
);
900 mcfs_fstat (void *data
, struct stat
*buf
)
902 mcfs_handle
*info
= (mcfs_handle
*) data
;
906 sock
= info
->conn
->sock
;
907 handle
= info
->handle
;
909 rpc_send (sock
, RPC_INT
, MC_FSTAT
, RPC_INT
, handle
, RPC_END
);
910 if (!rpc_get (sock
, RPC_INT
, &result
, RPC_INT
, &error
, RPC_END
))
911 return the_error (-1, EIO
);
913 if (is_error (result
, error
))
916 if (get_stat_info (info
->conn
, buf
))
919 return the_error (-1, EIO
);
923 mcfs_chmod (vfs
*me
, char *path
, int mode
)
925 return mcfs_rpc_path_int (MC_CHMOD
, path
, mode
);
929 mcfs_chown (vfs
*me
, char *path
, int owner
, int group
)
931 return mcfs_rpc_path_int_int (MC_CHOWN
, path
, owner
, group
);
935 mcfs_utime (vfs
*me
, char *path
, struct utimbuf
*times
)
941 if (!(file
= mcfs_get_path (&mc
, path
)))
945 if (mc
->version
>= 2) {
946 char abuf
[BUF_SMALL
];
947 char mbuf
[BUF_SMALL
];
950 atime
= (long) times
->actime
;
951 mtime
= (long) times
->modtime
;
953 g_snprintf (abuf
, sizeof (abuf
), "%lx", atime
);
954 g_snprintf (mbuf
, sizeof (mbuf
), "%lx", mtime
);
956 rpc_send (mc
->sock
, RPC_INT
, MC_UTIME
,
958 RPC_STRING
, abuf
, RPC_STRING
, mbuf
, RPC_END
);
959 status
= mcfs_handle_simple_error (mc
->sock
, 0);
967 mcfs_readlink (vfs
*me
, char *path
, char *buf
, int size
)
969 char *remote_file
, *stat_str
;
973 if (!(remote_file
= mcfs_get_path (&mc
, path
)))
976 rpc_send (mc
->sock
, RPC_INT
, MC_READLINK
, RPC_STRING
, remote_file
,
978 g_free (remote_file
);
979 if (!rpc_get (mc
->sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
980 return the_error (-1, EIO
);
982 if (is_error (status
, errno
))
985 if (!rpc_get (mc
->sock
, RPC_STRING
, &stat_str
, RPC_END
))
986 return the_error (-1, EIO
);
988 strncpy (buf
, stat_str
, size
);
994 mcfs_unlink (vfs
*me
, char *path
)
996 return mcfs_rpc_path (MC_UNLINK
, path
);
1000 mcfs_symlink (vfs
*me
, char *n1
, char *n2
)
1002 return mcfs_rpc_two_paths (MC_SYMLINK
, n1
, n2
);
1006 mcfs_rename (vfs
*me
, char *a
, char *b
)
1008 return mcfs_rpc_two_paths (MC_RENAME
, a
, b
);
1012 mcfs_chdir (vfs
*me
, char *path
)
1015 mcfs_connection
*mc
;
1018 if (!(remote_dir
= mcfs_get_path (&mc
, path
)))
1021 rpc_send (mc
->sock
, RPC_INT
, MC_CHDIR
, RPC_STRING
, remote_dir
,
1023 g_free (remote_dir
);
1024 if (!rpc_get (mc
->sock
, RPC_INT
, &status
, RPC_INT
, &error
, RPC_END
))
1025 return the_error (-1, EIO
);
1027 if (is_error (status
, error
))
1033 mcfs_lseek (void *data
, off_t offset
, int whence
)
1035 mcfs_handle
*info
= (mcfs_handle
*) data
;
1038 sock
= info
->conn
->sock
;
1039 handle
= info
->handle
;
1041 /* FIXME: off_t may be too long to fit */
1042 rpc_send (sock
, RPC_INT
, MC_LSEEK
, RPC_INT
, handle
, RPC_INT
,
1043 (int) offset
, RPC_INT
, whence
, RPC_END
);
1045 return mcfs_handle_simple_error (sock
, 1);
1049 mcfs_mknod (vfs
*me
, char *path
, int mode
, int dev
)
1051 return mcfs_rpc_path_int_int (MC_MKNOD
, path
, mode
, dev
);
1055 mcfs_mkdir (vfs
*me
, char *path
, mode_t mode
)
1057 return mcfs_rpc_path_int (MC_MKDIR
, path
, mode
);
1061 mcfs_rmdir (vfs
*me
, char *path
)
1063 return mcfs_rpc_path (MC_RMDIR
, path
);
1067 mcfs_link (vfs
*me
, char *p1
, char *p2
)
1069 return mcfs_rpc_two_paths (MC_LINK
, p1
, p2
);
1072 /* We do not free anything right now: we free resources when we run
1076 mcfs_getid (vfs
*me
, char *p
, struct vfs_stamping
**parent
)
1084 mcfs_nothingisopen (vfsid id
)
1090 mcfs_free (vfsid id
)
1092 /* FIXME: Should not be empty */
1095 /* Gives up on a socket and reopnes the connection, the child own the socket
1099 my_forget (char *path
)
1101 char *host
, *user
, *pass
, *p
;
1104 if (strncmp (path
, "/#mc:", 5))
1108 if (path
[0] == '/' && path
[1] == '/')
1112 mcfs_get_host_and_username (path
, &host
, &user
, &port
,
1117 wipe_password (pass
);
1120 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++) {
1121 if ((strcmp (host
, mcfs_connections
[i
].host
) == 0) &&
1122 (strcmp (user
, mcfs_connections
[i
].user
) == 0) &&
1123 (port
== mcfs_connections
[i
].port
)) {
1125 /* close socket: the child owns it now */
1126 close (mcfs_connections
[i
].sock
);
1128 /* reopen the connection */
1129 mcfs_connections
[i
].sock
=
1130 mcfs_open_tcp_link (host
, user
, &port
, pass
, &vers
);
1137 wipe_password (pass
);
1141 mcfs_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
1144 case MCCTL_FORGET_ABOUT
:
1151 vfs vfs_mcfs_ops
= {
1152 NULL
, /* This is place of next pointer */
1203 mcfs_setctl MMAPNULL
1208 mcfs_free_bucket (int bucket
)
1210 g_free (mcfs_connections
[bucket
].host
);
1211 g_free (mcfs_connections
[bucket
].user
);
1212 g_free (mcfs_connections
[bucket
].home
);
1214 /* Set all the fields to zero */
1215 mcfs_connections
[bucket
].host
=
1216 mcfs_connections
[bucket
].user
= mcfs_connections
[bucket
].home
= 0;
1217 mcfs_connections
[bucket
].sock
= mcfs_connections
[bucket
].version
= 0;
1221 mcfs_invalidate_socket (int sock
)
1224 extern int mc_chdir (char *);
1226 for (i
= 0; i
< MCFS_MAX_CONNECTIONS
; i
++)
1227 if (mcfs_connections
[i
].sock
== sock
) {
1228 mcfs_free_bucket (i
);
1233 return -1; /* It was not our sock */
1234 /* Break from any possible loop */
1240 tcp_invalidate_socket (int sock
)
1242 mcfs_invalidate_socket (sock
);
1245 #endif /* WITH_MCFS */