1 /* Virtual File System switch code
2 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2007 Free Software Foundation, Inc.
5 Written by: 1995 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
25 * \brief Source: Virtual File System switch code
26 * \author Miguel de Icaza
27 * \author Jakub Jelinek
28 * \author Pavel Machek
30 * \warning funtions like extfs_lstat() have right to destroy any
31 * strings you pass to them. This is acutally ok as you g_strdup what
32 * you are passing to them, anyway; still, beware.
34 * Namespace: exports *many* functions with vfs_ prefix; exports
35 * parse_ls_lga and friends which do not have that prefix.
41 #include <stdlib.h> /* For atol() */
45 #include <sys/types.h>
47 #include <ctype.h> /* is_digit() */
53 #include "lib/global.h"
54 #include "lib/strutil.h"
56 #include "lib/widget.h" /* message() */
59 #include "lib/charsets.h"
61 #include "src/setup.h" /* cd_symlinks */
79 /*** global variables ****************************************************************************/
81 /*** file scope macro definitions ****************************************************************/
83 #if defined(_AIX) && !defined(NAME_MAX)
84 #define NAME_MAX FILENAME_MAX
87 #define VFS_FIRST_HANDLE 100
89 #define ISSLASH(a) (!a || (a == '/'))
91 /*** file scope type declarations ****************************************************************/
96 struct vfs_class
*vclass
;
106 /*** file scope variables ************************************************************************/
108 /** They keep track of the current directory */
109 static struct vfs_class
*current_vfs
;
110 static char *current_dir
;
112 static GPtrArray
*vfs_openfiles
;
113 static long vfs_free_handle_list
= -1;
115 static struct vfs_class
*localfs_class
;
116 static GString
*vfs_str_buffer
;
118 static struct vfs_class
*vfs_list
;
120 static struct dirent
*mc_readdir_result
= NULL
;
126 const char *substitute
;
130 #ifdef ENABLE_VFS_FTP
131 { "ftp://", 6, "/#ftp:" },
133 #ifdef ENABLE_VFS_FISH
134 { "sh://", 5, "/#sh:" },
135 { "ssh://", 6, "/#sh:" },
137 #ifdef ENABLE_VFS_SMB
138 { "smb://", 6, "/#smb:" },
144 /*** file scope functions ************************************************************************/
145 /* --------------------------------------------------------------------------------------------- */
147 * Create new VFS handle and put it to the list
151 vfs_new_handle (struct vfs_class
*vclass
, void *fsinfo
)
153 struct vfs_openfile
*h
;
155 h
= g_new (struct vfs_openfile
, 1);
159 /* Allocate the first free handle */
160 h
->handle
= vfs_free_handle_list
;
163 /* No free allocated handles, allocate one */
164 h
->handle
= vfs_openfiles
->len
;
165 g_ptr_array_add (vfs_openfiles
, h
);
169 vfs_free_handle_list
= (long) g_ptr_array_index (vfs_openfiles
, vfs_free_handle_list
);
170 g_ptr_array_index (vfs_openfiles
, h
->handle
) = h
;
173 h
->handle
+= VFS_FIRST_HANDLE
;
177 /* --------------------------------------------------------------------------------------------- */
178 /** Find VFS class by file handle */
180 static struct vfs_class
*
183 struct vfs_openfile
*h
;
185 if (handle
< VFS_FIRST_HANDLE
|| (guint
) (handle
- VFS_FIRST_HANDLE
) >= vfs_openfiles
->len
)
188 h
= (struct vfs_openfile
*) g_ptr_array_index (vfs_openfiles
, handle
- VFS_FIRST_HANDLE
);
192 g_assert (h
->handle
== handle
);
197 /* --------------------------------------------------------------------------------------------- */
198 /** Find private file data by file handle */
201 vfs_info (int handle
)
203 struct vfs_openfile
*h
;
205 if (handle
< VFS_FIRST_HANDLE
|| (guint
) (handle
- VFS_FIRST_HANDLE
) >= vfs_openfiles
->len
)
208 h
= (struct vfs_openfile
*) g_ptr_array_index (vfs_openfiles
, handle
- VFS_FIRST_HANDLE
);
212 g_assert (h
->handle
== handle
);
217 /* --------------------------------------------------------------------------------------------- */
218 /** Free open file data for given file handle */
221 vfs_free_handle (int handle
)
223 const int idx
= handle
- VFS_FIRST_HANDLE
;
225 if (handle
>= VFS_FIRST_HANDLE
&& (guint
) idx
< vfs_openfiles
->len
)
227 struct vfs_openfile
*h
;
229 h
= (struct vfs_openfile
*) g_ptr_array_index (vfs_openfiles
, idx
);
231 g_ptr_array_index (vfs_openfiles
, idx
) = (void *) vfs_free_handle_list
;
232 vfs_free_handle_list
= idx
;
237 /* --------------------------------------------------------------------------------------------- */
239 /** Return VFS class for the given prefix */
240 static struct vfs_class
*
241 vfs_prefix_to_class (char *prefix
)
243 struct vfs_class
*vfs
;
245 /* Avoid last class (localfs) that would accept any prefix */
246 for (vfs
= vfs_list
; vfs
->next
!= NULL
; vfs
= vfs
->next
)
248 if (vfs
->which
!= NULL
)
250 if ((*vfs
->which
) (vfs
, prefix
) == -1)
254 if (vfs
->prefix
!= NULL
&& strncmp (prefix
, vfs
->prefix
, strlen (vfs
->prefix
)) == 0)
260 /* --------------------------------------------------------------------------------------------- */
263 path_magic (const char *path
)
267 return (stat (path
, &buf
) != 0);
270 /* --------------------------------------------------------------------------------------------- */
272 static struct vfs_class
*
273 _vfs_get_class (char *path
)
277 struct vfs_class
*ret
;
279 g_return_val_if_fail (path
, NULL
);
281 semi
= strrchr (path
, '#');
282 if (semi
== NULL
|| !path_magic (path
))
285 slash
= strchr (semi
, PATH_SEP
);
290 ret
= vfs_prefix_to_class (semi
+ 1);
295 ret
= _vfs_get_class (path
);
301 /* --------------------------------------------------------------------------------------------- */
302 /* now used only by vfs_translate_path, but could be used in other vfs
303 * plugin to automatic detect encoding
304 * path - path to translate
305 * size - how many bytes from path translate
306 * defcnv - convertor, that is used as default, when path does not contain any
308 * buffer - used to store result of translation
312 _vfs_translate_path (const char *path
, int size
, GIConv defcnv
, GString
* buffer
)
316 estr_t state
= ESTR_SUCCESS
;
321 size
= (size
> 0) ? size
: (signed int) strlen (path
);
323 /* try found /#enc: */
324 semi
= g_strrstr_len (path
, size
, PATH_SEP_STR VFS_ENCODING_PREFIX
);
328 GIConv coder
= INVALID_CONV
;
331 /* first must be translated part before /#enc: */
334 state
= _vfs_translate_path (path
, ms
, defcnv
, buffer
);
336 if (state
!= ESTR_SUCCESS
)
339 /* now can be translated part after #enc: */
340 semi
+= strlen (VFS_ENCODING_PREFIX
) + 1; /* skip "/#enc:" */
341 slash
= strchr (semi
, PATH_SEP
);
342 /* ignore slashes after size; */
343 if (slash
- path
>= size
)
346 ms
= (slash
!= NULL
) ? slash
- semi
: (int) strlen (semi
);
347 ms
= min ((unsigned int) ms
, sizeof (encoding
) - 1);
348 /* limit encoding size (ms) to path size (size) */
349 if (semi
+ ms
> path
+ size
)
350 ms
= path
+ size
- semi
;
351 memcpy (encoding
, semi
, ms
);
355 if (is_supported_encoding (encoding
))
356 coder
= str_crt_conv_to (encoding
);
359 if (coder
!= INVALID_CONV
)
362 state
= str_vfs_convert_to (coder
, slash
, path
+ size
- slash
, buffer
);
363 else if (buffer
->len
== 0)
364 g_string_append_c (buffer
, PATH_SEP
);
365 str_close_conv (coder
);
370 state
= ESTR_FAILURE
;
374 /* path can be translated whole at once */
375 state
= str_vfs_convert_to (defcnv
, path
, size
, buffer
);
381 /* --------------------------------------------------------------------------------------------- */
384 ferrno (struct vfs_class
*vfs
)
386 return vfs
->ferrno
? (*vfs
->ferrno
) (vfs
) : E_UNKNOWN
;
387 /* Hope that error message is obscure enough ;-) */
390 /* --------------------------------------------------------------------------------------------- */
392 * Return current directory. If it's local, reread the current directory
393 * from the OS. You must g_strdup() whatever this function returns.
401 trans
= vfs_translate_path_n (current_dir
);
403 if (_vfs_get_class (trans
) == NULL
)
405 const char *encoding
= vfs_get_encoding (current_dir
);
407 if (encoding
== NULL
)
411 tmp
= g_get_current_dir ();
413 { /* One of the directories in the path is not readable */
417 g_string_set_size (vfs_str_buffer
, 0);
418 state
= str_vfs_convert_from (str_cnv_from_term
, tmp
, vfs_str_buffer
);
421 sys_cwd
= (state
== ESTR_SUCCESS
) ? g_strdup (vfs_str_buffer
->str
) : NULL
;
424 struct stat my_stat
, my_stat2
;
425 /* Check if it is O.K. to use the current_dir */
427 && mc_stat (sys_cwd
, &my_stat
) == 0
428 && mc_stat (current_dir
, &my_stat2
) == 0
429 && my_stat
.st_ino
== my_stat2
.st_ino
&& my_stat
.st_dev
== my_stat2
.st_dev
)
433 g_free (current_dir
);
434 current_dir
= sys_cwd
;
445 /* --------------------------------------------------------------------------------------------- */
450 current_dir
= g_strdup (PATH_SEP_STR
);
453 if (strlen (current_dir
) > MC_MAXPATHLEN
- 2)
454 vfs_die ("Current dir too long.\n");
456 current_vfs
= vfs_get_class (current_dir
);
459 /* --------------------------------------------------------------------------------------------- */
462 mc_def_getlocalcopy (const char *filename
)
470 fdin
= mc_open (filename
, O_RDONLY
| O_LINEAR
);
474 fdout
= vfs_mkstemps (&tmp
, "vfs", filename
);
478 while ((i
= mc_read (fdin
, buffer
, sizeof (buffer
))) > 0)
480 if (write (fdout
, buffer
, i
) != i
)
489 if (close (fdout
) == -1)
495 if (mc_stat (filename
, &mystat
) != -1)
496 chmod (tmp
, mystat
.st_mode
);
509 /* --------------------------------------------------------------------------------------------- */
512 mc_def_ungetlocalcopy (struct vfs_class
*vfs
, const char *filename
,
513 const char *local
, int has_changed
)
515 int fdin
= -1, fdout
= -1;
524 fdin
= open (local
, O_RDONLY
);
527 fdout
= mc_open (filename
, O_WRONLY
| O_TRUNC
);
530 while ((i
= read (fdin
, buffer
, sizeof (buffer
))) > 0)
531 if (mc_write (fdout
, buffer
, (size_t) i
) != i
)
536 if (close (fdin
) == -1)
542 if (mc_close (fdout
) == -1)
552 message (D_ERROR
, _("Changes to file lost"), "%s", filename
);
561 /* --------------------------------------------------------------------------------------------- */
562 /*** public functions ****************************************************************************/
563 /* --------------------------------------------------------------------------------------------- */
566 vfs_register_class (struct vfs_class
*vfs
)
568 if (vfs
->init
!= NULL
) /* vfs has own initialization function */
569 if (!(*vfs
->init
) (vfs
)) /* but it failed */
572 vfs
->next
= vfs_list
;
578 /* --------------------------------------------------------------------------------------------- */
579 /** Strip known vfs suffixes from a filename (possible improvement: strip
580 * suffix from last path component).
581 * \return a malloced string which has to be freed.
585 vfs_strip_suffix_from_filename (const char *filename
)
587 struct vfs_class
*vfs
;
591 if (filename
== NULL
)
592 vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
594 p
= g_strdup (filename
);
595 semi
= strrchr (p
, '#');
599 /* Avoid last class (localfs) that would accept any prefix */
600 for (vfs
= vfs_list
; vfs
->next
!= NULL
; vfs
= vfs
->next
)
602 if (vfs
->which
!= NULL
)
604 if ((*vfs
->which
) (vfs
, semi
+ 1) == -1)
606 *semi
= '\0'; /* Found valid suffix */
609 if (vfs
->prefix
!= NULL
&& strncmp (semi
+ 1, vfs
->prefix
, strlen (vfs
->prefix
)) == 0)
611 *semi
= '\0'; /* Found valid suffix */
618 /* --------------------------------------------------------------------------------------------- */
621 * Splits path extracting vfs part.
624 * \verbatim /p1#op/inpath \endverbatim
626 * \verbatim inpath,op; \endverbatim
627 * returns which vfs it is.
628 * What is left in path is p1. You still want to g_free(path), you DON'T
629 * want to free neither *inpath nor *op
633 vfs_split (char *path
, char **inpath
, char **op
)
637 struct vfs_class
*ret
;
640 vfs_die ("Cannot split NULL");
642 semi
= strrchr (path
, '#');
643 if (semi
== NULL
|| !path_magic (path
))
646 slash
= strchr (semi
, PATH_SEP
);
658 ret
= vfs_prefix_to_class (semi
+ 1);
664 *inpath
= slash
!= NULL
? slash
+ 1 : NULL
;
671 ret
= vfs_split (path
, inpath
, op
);
676 /* --------------------------------------------------------------------------------------------- */
679 vfs_get_class (const char *pathname
)
681 struct vfs_class
*vfs
;
682 char *path
= g_strdup (pathname
);
684 vfs
= _vfs_get_class (path
);
693 /* --------------------------------------------------------------------------------------------- */
696 vfs_get_encoding (const char *path
)
698 static char result
[16];
703 work
= g_strdup (path
);
704 /* try found /#enc: */
705 semi
= g_strrstr (work
, PATH_SEP_STR VFS_ENCODING_PREFIX
);
709 semi
+= strlen (VFS_ENCODING_PREFIX
) + 1; /* skip "/#enc:" */
710 slash
= strchr (semi
, PATH_SEP
);
714 g_strlcpy (result
, semi
, sizeof (result
));
725 /* --------------------------------------------------------------------------------------------- */
728 vfs_translate_path (const char *path
)
732 g_string_set_size (vfs_str_buffer
, 0);
733 state
= _vfs_translate_path (path
, -1, str_cnv_from_term
, vfs_str_buffer
);
736 return (state == 0) ? vfs_str_buffer->data : NULL;
738 return (state
!= ESTR_FAILURE
) ? vfs_str_buffer
->str
: NULL
;
741 /* --------------------------------------------------------------------------------------------- */
744 vfs_translate_path_n (const char *path
)
748 result
= vfs_translate_path (path
);
749 return (result
!= NULL
) ? g_strdup (result
) : NULL
;
752 /* --------------------------------------------------------------------------------------------- */
755 vfs_canon_and_translate (const char *path
)
760 canon
= g_strdup ("");
762 canon
= vfs_canon (path
);
763 result
= vfs_translate_path_n (canon
);
768 /* --------------------------------------------------------------------------------------------- */
771 mc_open (const char *filename
, int flags
, ...)
777 struct vfs_class
*vfs
;
779 file
= vfs_canon_and_translate (filename
);
783 vfs
= vfs_get_class (file
);
785 /* Get the mode flag */
788 va_start (ap
, flags
);
789 mode
= va_arg (ap
, int);
793 if (vfs
->open
== NULL
)
800 info
= vfs
->open (vfs
, file
, flags
, mode
); /* open must be supported */
804 errno
= ferrno (vfs
);
808 return vfs_new_handle (vfs
, info
);
811 /* --------------------------------------------------------------------------------------------- */
815 #define MC_NAMEOP(name, inarg, callarg) \
816 int mc_##name inarg \
818 struct vfs_class *vfs; \
821 mpath = vfs_canon_and_translate (path); \
824 vfs = vfs_get_class (mpath); \
830 result = vfs->name != NULL ? vfs->name callarg : -1; \
833 errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
837 MC_NAMEOP (chmod
, (const char *path
, mode_t mode
), (vfs
, mpath
, mode
))
838 MC_NAMEOP (chown
, (const char *path
, uid_t owner
, gid_t group
), (vfs
, mpath
, owner
, group
))
839 MC_NAMEOP (utime
, (const char *path
, struct utimbuf
* times
), (vfs
, mpath
, times
))
840 MC_NAMEOP (readlink
, (const char *path
, char *buf
, size_t bufsiz
), (vfs
, mpath
, buf
, bufsiz
))
841 MC_NAMEOP (unlink
, (const char *path
), (vfs
, mpath
))
842 MC_NAMEOP (mkdir
, (const char *path
, mode_t mode
), (vfs
, mpath
, mode
))
843 MC_NAMEOP (rmdir
, (const char *path
), (vfs
, mpath
))
844 MC_NAMEOP (mknod
, (const char *path
, mode_t mode
, dev_t dev
), (vfs
, mpath
, mode
, dev
))
848 /* --------------------------------------------------------------------------------------------- */
851 mc_symlink (const char *name1
, const char *path
)
853 struct vfs_class
*vfs
;
859 mpath
= vfs_canon_and_translate (path
);
863 tmp
= g_strdup (name1
);
864 lpath
= vfs_translate_path_n (tmp
);
869 vfs
= vfs_get_class (mpath
);
870 result
= vfs
->symlink
!= NULL
? vfs
->symlink (vfs
, lpath
, mpath
) : -1;
875 errno
= vfs
->symlink
!= NULL
? ferrno (vfs
) : E_NOTSUPP
;
884 /* --------------------------------------------------------------------------------------------- */
888 #define MC_HANDLEOP(name, inarg, callarg) \
889 ssize_t mc_##name inarg \
891 struct vfs_class *vfs; \
895 vfs = vfs_op (handle); \
898 result = vfs->name != NULL ? vfs->name callarg : -1; \
900 errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
904 MC_HANDLEOP (read
, (int handle
, void *buffer
, size_t count
), (vfs_info (handle
), buffer
, count
))
905 MC_HANDLEOP (write
, (int handle
, const void *buf
, size_t nbyte
), (vfs_info (handle
), buf
, nbyte
))
907 /* --------------------------------------------------------------------------------------------- */
909 #define MC_RENAMEOP(name) \
910 int mc_##name (const char *fname1, const char *fname2) \
912 struct vfs_class *vfs; \
914 char *name2, *name1; \
915 name1 = vfs_canon_and_translate (fname1); \
918 name2 = vfs_canon_and_translate (fname2); \
919 if (name2 == NULL) { \
923 vfs = vfs_get_class (name1); \
924 if (vfs != vfs_get_class (name2)) \
931 result = vfs->name != NULL ? vfs->name (vfs, name1, name2) : -1; \
935 errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
944 /* --------------------------------------------------------------------------------------------- */
947 mc_ctl (int handle
, int ctlop
, void *arg
)
949 struct vfs_class
*vfs
= vfs_op (handle
);
954 return vfs
->ctl
? (*vfs
->ctl
) (vfs_info (handle
), ctlop
, arg
) : 0;
957 /* --------------------------------------------------------------------------------------------- */
960 mc_setctl (const char *path
, int ctlop
, void *arg
)
962 struct vfs_class
*vfs
;
967 vfs_die ("You don't want to pass NULL to mc_setctl.");
969 mpath
= vfs_canon_and_translate (path
);
972 vfs
= vfs_get_class (mpath
);
973 result
= vfs
->setctl
!= NULL
? vfs
->setctl (vfs
, mpath
, ctlop
, arg
) : 0;
980 /* --------------------------------------------------------------------------------------------- */
983 mc_close (int handle
)
985 struct vfs_class
*vfs
;
988 if (handle
== -1 || !vfs_info (handle
))
991 vfs
= vfs_op (handle
);
996 return close (handle
);
999 vfs_die ("VFS must support close.\n");
1000 result
= (*vfs
->close
) (vfs_info (handle
));
1001 vfs_free_handle (handle
);
1003 errno
= ferrno (vfs
);
1008 /* --------------------------------------------------------------------------------------------- */
1011 mc_opendir (const char *dirname
)
1013 int handle
, *handlep
;
1015 struct vfs_class
*vfs
;
1018 struct vfs_dirinfo
*dirinfo
;
1019 const char *encoding
;
1021 canon
= vfs_canon (dirname
);
1022 dname
= vfs_translate_path_n (canon
);
1026 vfs
= vfs_get_class (dname
);
1027 info
= vfs
->opendir
? (*vfs
->opendir
) (vfs
, dname
) : NULL
;
1032 errno
= vfs
->opendir
? ferrno (vfs
) : E_NOTSUPP
;
1037 dirinfo
= g_new (struct vfs_dirinfo
, 1);
1038 dirinfo
->info
= info
;
1040 encoding
= vfs_get_encoding (canon
);
1042 dirinfo
->converter
= (encoding
!= NULL
) ? str_crt_conv_from (encoding
) : str_cnv_from_term
;
1043 if (dirinfo
->converter
== INVALID_CONV
)
1044 dirinfo
->converter
= str_cnv_from_term
;
1046 handle
= vfs_new_handle (vfs
, dirinfo
);
1048 handlep
= g_new (int, 1);
1050 return (DIR *) handlep
;
1059 /* --------------------------------------------------------------------------------------------- */
1062 mc_readdir (DIR * dirp
)
1065 struct vfs_class
*vfs
;
1066 struct dirent
*entry
= NULL
;
1067 struct vfs_dirinfo
*dirinfo
;
1070 if (!mc_readdir_result
)
1072 /* We can't just allocate struct dirent as (see man dirent.h)
1073 * struct dirent has VERY nonnaive semantics of allocating
1074 * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
1075 * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
1076 * heap corrupter. So, allocate longliving dirent with at least
1077 * (MAXNAMLEN + 1) for d_name in it.
1078 * Strictly saying resulting dirent is unusable as we don't adjust internal
1079 * structures, holding dirent size. But we don't use it in libc infrastructure.
1080 * TODO: to make simpler homemade dirent-alike structure.
1082 mc_readdir_result
= (struct dirent
*) g_malloc (sizeof (struct dirent
) + MAXNAMLEN
+ 1);
1090 handle
= *(int *) dirp
;
1092 vfs
= vfs_op (handle
);
1096 dirinfo
= vfs_info (handle
);
1099 entry
= (*vfs
->readdir
) (dirinfo
->info
);
1102 g_string_set_size (vfs_str_buffer
, 0);
1103 state
= str_vfs_convert_from (dirinfo
->converter
, entry
->d_name
, vfs_str_buffer
);
1104 mc_readdir_result
->d_ino
= entry
->d_ino
;
1105 g_strlcpy (mc_readdir_result
->d_name
, vfs_str_buffer
->str
, MAXNAMLEN
+ 1);
1108 errno
= vfs
->readdir
? ferrno (vfs
) : E_NOTSUPP
;
1109 return (entry
!= NULL
) ? mc_readdir_result
: NULL
;
1112 /* --------------------------------------------------------------------------------------------- */
1115 mc_closedir (DIR * dirp
)
1117 int handle
= *(int *) dirp
;
1118 struct vfs_class
*vfs
;
1121 vfs
= vfs_op (handle
);
1124 struct vfs_dirinfo
*dirinfo
;
1126 dirinfo
= vfs_info (handle
);
1127 if (dirinfo
->converter
!= str_cnv_from_term
)
1128 str_close_conv (dirinfo
->converter
);
1130 result
= vfs
->closedir
? (*vfs
->closedir
) (dirinfo
->info
) : -1;
1131 vfs_free_handle (handle
);
1138 /* --------------------------------------------------------------------------------------------- */
1141 mc_stat (const char *filename
, struct stat
*buf
)
1143 struct vfs_class
*vfs
;
1147 path
= vfs_canon_and_translate (filename
);
1152 vfs
= vfs_get_class (path
);
1160 result
= vfs
->stat
? (*vfs
->stat
) (vfs
, path
, buf
) : -1;
1165 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
1169 /* --------------------------------------------------------------------------------------------- */
1172 mc_lstat (const char *filename
, struct stat
*buf
)
1174 struct vfs_class
*vfs
;
1178 path
= vfs_canon_and_translate (filename
);
1183 vfs
= vfs_get_class (path
);
1190 result
= vfs
->lstat
? (*vfs
->lstat
) (vfs
, path
, buf
) : -1;
1193 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
1197 /* --------------------------------------------------------------------------------------------- */
1200 mc_fstat (int handle
, struct stat
*buf
)
1202 struct vfs_class
*vfs
;
1208 vfs
= vfs_op (handle
);
1212 result
= vfs
->fstat
? (*vfs
->fstat
) (vfs_info (handle
), buf
) : -1;
1214 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
1218 /* --------------------------------------------------------------------------------------------- */
1220 * Return current directory. If it's local, reread the current directory
1221 * from the OS. Put directory to the provided buffer.
1225 mc_get_current_wd (char *buffer
, size_t size
)
1227 const char *cwd
= _vfs_get_cwd ();
1229 g_strlcpy (buffer
, cwd
, size
);
1233 /* --------------------------------------------------------------------------------------------- */
1235 * Return current directory without any OS calls.
1239 vfs_get_current_dir (void)
1244 /* --------------------------------------------------------------------------------------------- */
1247 mc_lseek (int fd
, off_t offset
, int whence
)
1249 struct vfs_class
*vfs
;
1259 result
= vfs
->lseek
? (*vfs
->lseek
) (vfs_info (fd
), offset
, whence
) : -1;
1261 errno
= vfs
->lseek
? ferrno (vfs
) : E_NOTSUPP
;
1265 /* --------------------------------------------------------------------------------------------- */
1267 * remove //, /./ and /../
1271 vfs_canon (const char *path
)
1274 vfs_die ("Cannot canonicalize NULL");
1276 /* Relative to current directory */
1277 if (*path
!= PATH_SEP
)
1279 char *local
, *result
;
1281 local
= concat_dir_and_file (current_dir
, path
);
1283 result
= vfs_canon (local
);
1289 * So we have path of following form:
1290 * /p1/p2#op/.././././p3#op/p4. Good luck.
1293 char *result
= g_strdup (path
);
1294 canonicalize_pathname (result
);
1299 /* --------------------------------------------------------------------------------------------- */
1302 * Return 0 on success, -1 on failure.
1306 mc_chdir (const char *path
)
1310 struct vfs_class
*old_vfs
, *new_vfs
;
1314 new_dir
= vfs_canon (path
);
1315 trans_dir
= vfs_translate_path_n (new_dir
);
1316 if (trans_dir
!= NULL
)
1318 new_vfs
= vfs_get_class (trans_dir
);
1319 if (!new_vfs
->chdir
)
1326 result
= (*new_vfs
->chdir
) (new_vfs
, trans_dir
);
1330 errno
= ferrno (new_vfs
);
1336 old_vfsid
= vfs_getid (current_vfs
, current_dir
);
1337 old_vfs
= current_vfs
;
1339 /* Actually change directory */
1340 g_free (current_dir
);
1341 current_dir
= new_dir
;
1342 current_vfs
= new_vfs
;
1344 /* This function uses the new current_dir implicitly */
1345 vfs_stamp_create (old_vfs
, old_vfsid
);
1347 /* Sometimes we assume no trailing slash on cwd */
1351 p
= strchr (current_dir
, 0) - 1;
1352 if (*p
== PATH_SEP
&& p
> current_dir
)
1366 /* --------------------------------------------------------------------------------------------- */
1367 /* Return TRUE is the current VFS class is local */
1370 vfs_current_is_local (void)
1372 return (current_vfs
->flags
& VFSF_LOCAL
) != 0;
1375 /* --------------------------------------------------------------------------------------------- */
1376 /* Return flags of the VFS class of the given filename */
1379 vfs_file_class_flags (const char *filename
)
1381 struct vfs_class
*vfs
;
1384 fname
= vfs_canon_and_translate (filename
);
1386 return VFSF_UNKNOWN
;
1388 vfs
= vfs_get_class (fname
);
1393 /* --------------------------------------------------------------------------------------------- */
1396 mc_getlocalcopy (const char *pathname
)
1398 char *result
= NULL
;
1401 path
= vfs_canon_and_translate (pathname
);
1404 struct vfs_class
*vfs
= vfs_get_class (path
);
1406 result
= vfs
->getlocalcopy
!= NULL
?
1407 vfs
->getlocalcopy (vfs
, path
) : mc_def_getlocalcopy (path
);
1410 errno
= ferrno (vfs
);
1416 /* --------------------------------------------------------------------------------------------- */
1419 mc_ungetlocalcopy (const char *pathname
, const char *local
, int has_changed
)
1421 int return_value
= -1;
1424 path
= vfs_canon_and_translate (pathname
);
1427 struct vfs_class
*vfs
= vfs_get_class (path
);
1429 return_value
= vfs
->ungetlocalcopy
!= NULL
?
1430 vfs
->ungetlocalcopy (vfs
, path
, local
, has_changed
) :
1431 mc_def_ungetlocalcopy (vfs
, path
, local
, has_changed
);
1435 return return_value
;
1438 /* --------------------------------------------------------------------------------------------- */
1443 /* create the VFS handle array */
1444 vfs_openfiles
= g_ptr_array_new ();
1446 vfs_str_buffer
= g_string_new ("");
1447 /* localfs needs to be the first one */
1449 /* fallback value for vfs_get_class() */
1450 localfs_class
= vfs_list
;
1452 #ifdef ENABLE_VFS_CPIO
1454 #endif /* ENABLE_VFS_CPIO */
1455 #ifdef ENABLE_VFS_TAR
1457 #endif /* ENABLE_VFS_TAR */
1458 #ifdef ENABLE_VFS_SFS
1460 #endif /* ENABLE_VFS_SFS */
1461 #ifdef ENABLE_VFS_EXTFS
1463 #endif /* ENABLE_VFS_EXTFS */
1464 #ifdef ENABLE_VFS_UNDELFS
1466 #endif /* ENABLE_VFS_UNDELFS */
1468 #ifdef ENABLE_VFS_FTP
1470 #endif /* ENABLE_VFS_FTP */
1471 #ifdef ENABLE_VFS_FISH
1473 #endif /* ENABLE_VFS_FISH */
1474 #ifdef ENABLE_VFS_SMB
1476 #endif /* ENABLE_VFS_SMB */
1481 /* --------------------------------------------------------------------------------------------- */
1486 struct vfs_class
*vfs
;
1490 g_free (current_dir
);
1492 for (vfs
= vfs_list
; vfs
; vfs
= vfs
->next
)
1496 g_ptr_array_free (vfs_openfiles
, TRUE
);
1497 g_string_free (vfs_str_buffer
, TRUE
);
1498 g_free (mc_readdir_result
);
1501 /* --------------------------------------------------------------------------------------------- */
1503 * These ones grab information from the VFS
1504 * and handles them to an upper layer
1508 vfs_fill_names (fill_names_f func
)
1510 struct vfs_class
*vfs
;
1512 for (vfs
= vfs_list
; vfs
; vfs
= vfs
->next
)
1513 if (vfs
->fill_names
)
1514 (*vfs
->fill_names
) (vfs
, func
);
1517 /* --------------------------------------------------------------------------------------------- */
1519 * Returns vfs path corresponding to given url. If passed string is
1520 * not recognized as url, g_strdup(url) is returned.
1524 vfs_translate_url (const char *url
)
1528 for (i
= 0; i
< sizeof (url_table
) / sizeof (url_table
[0]); i
++)
1529 if (strncmp (url
, url_table
[i
].name
, url_table
[i
].name_len
) == 0)
1530 return g_strconcat (url_table
[i
].substitute
, url
+ url_table
[i
].name_len
,
1533 return g_strdup (url
);
1536 /* --------------------------------------------------------------------------------------------- */
1539 vfs_file_is_local (const char *filename
)
1541 return (vfs_file_class_flags (filename
) & VFSF_LOCAL
) != 0;
1544 /* --------------------------------------------------------------------------------------------- */