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 "src/charsets.h"
59 #include "src/wtools.h" /* message() */
60 #include "src/main.h" /* print_vfs_message */
76 #if defined(_AIX) && !defined(NAME_MAX)
77 # define NAME_MAX FILENAME_MAX
80 /** They keep track of the current directory */
81 static struct vfs_class
*current_vfs
;
82 static char *current_dir
;
87 struct vfs_class
*vclass
;
98 static GPtrArray
*vfs_openfiles
;
99 static long vfs_free_handle_list
= -1;
100 #define VFS_FIRST_HANDLE 100
102 static struct vfs_class
*localfs_class
;
103 static GString
*vfs_str_buffer
;
105 /** Create new VFS handle and put it to the list */
107 vfs_new_handle (struct vfs_class
*vclass
, void *fsinfo
)
109 struct vfs_openfile
*h
;
111 h
= g_new (struct vfs_openfile
, 1);
115 /* Allocate the first free handle */
116 h
->handle
= vfs_free_handle_list
;
119 /* No free allocated handles, allocate one */
120 h
->handle
= vfs_openfiles
->len
;
121 g_ptr_array_add (vfs_openfiles
, h
);
125 vfs_free_handle_list
= (long) g_ptr_array_index (vfs_openfiles
, vfs_free_handle_list
);
126 g_ptr_array_index (vfs_openfiles
, h
->handle
) = h
;
129 h
->handle
+= VFS_FIRST_HANDLE
;
133 /** Find VFS class by file handle */
134 static struct vfs_class
*
137 struct vfs_openfile
*h
;
139 if (handle
< VFS_FIRST_HANDLE
|| (guint
) (handle
- VFS_FIRST_HANDLE
) >= vfs_openfiles
->len
)
142 h
= (struct vfs_openfile
*) g_ptr_array_index (vfs_openfiles
, handle
- VFS_FIRST_HANDLE
);
146 g_assert (h
->handle
== handle
);
151 /** Find private file data by file handle */
153 vfs_info (int handle
)
155 struct vfs_openfile
*h
;
157 if (handle
< VFS_FIRST_HANDLE
|| (guint
) (handle
- VFS_FIRST_HANDLE
) >= vfs_openfiles
->len
)
160 h
= (struct vfs_openfile
*) g_ptr_array_index (vfs_openfiles
, handle
- VFS_FIRST_HANDLE
);
164 g_assert (h
->handle
== handle
);
169 /** Free open file data for given file handle */
171 vfs_free_handle (int handle
)
173 const int idx
= handle
- VFS_FIRST_HANDLE
;
175 if (handle
>= VFS_FIRST_HANDLE
&& (guint
) idx
< vfs_openfiles
->len
)
177 struct vfs_openfile
*h
;
179 h
= (struct vfs_openfile
*) g_ptr_array_index (vfs_openfiles
, idx
);
181 g_ptr_array_index (vfs_openfiles
, idx
) = (void *) vfs_free_handle_list
;
182 vfs_free_handle_list
= idx
;
186 static struct vfs_class
*vfs_list
;
189 vfs_register_class (struct vfs_class
*vfs
)
191 if (vfs
->init
!= NULL
) /* vfs has own initialization function */
192 if (!(*vfs
->init
) (vfs
)) /* but it failed */
195 vfs
->next
= vfs_list
;
201 /** Return VFS class for the given prefix */
202 static struct vfs_class
*
203 vfs_prefix_to_class (char *prefix
)
205 struct vfs_class
*vfs
;
207 /* Avoid last class (localfs) that would accept any prefix */
208 for (vfs
= vfs_list
; vfs
->next
!= NULL
; vfs
= vfs
->next
)
210 if (vfs
->which
!= NULL
)
212 if ((*vfs
->which
) (vfs
, prefix
) == -1)
216 if (vfs
->prefix
!= NULL
&& strncmp (prefix
, vfs
->prefix
, strlen (vfs
->prefix
)) == 0)
222 /** Strip known vfs suffixes from a filename (possible improvement: strip
223 * suffix from last path component).
224 * \return a malloced string which has to be freed.
227 vfs_strip_suffix_from_filename (const char *filename
)
229 struct vfs_class
*vfs
;
233 if (filename
== NULL
)
234 vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
236 p
= g_strdup (filename
);
237 semi
= strrchr (p
, '#');
241 /* Avoid last class (localfs) that would accept any prefix */
242 for (vfs
= vfs_list
; vfs
->next
!= NULL
; vfs
= vfs
->next
)
244 if (vfs
->which
!= NULL
)
246 if ((*vfs
->which
) (vfs
, semi
+ 1) == -1)
248 *semi
= '\0'; /* Found valid suffix */
251 if (vfs
->prefix
!= NULL
&& strncmp (semi
+ 1, vfs
->prefix
, strlen (vfs
->prefix
)) == 0)
253 *semi
= '\0'; /* Found valid suffix */
261 path_magic (const char *path
)
265 return (stat (path
, &buf
) != 0);
269 * Splits path extracting vfs part.
272 * \verbatim /p1#op/inpath \endverbatim
274 * \verbatim inpath,op; \endverbatim
275 * returns which vfs it is.
276 * What is left in path is p1. You still want to g_free(path), you DON'T
277 * want to free neither *inpath nor *op
280 vfs_split (char *path
, char **inpath
, char **op
)
284 struct vfs_class
*ret
;
287 vfs_die ("Cannot split NULL");
289 semi
= strrchr (path
, '#');
290 if (semi
== NULL
|| !path_magic (path
))
293 slash
= strchr (semi
, PATH_SEP
);
305 ret
= vfs_prefix_to_class (semi
+ 1);
311 *inpath
= slash
!= NULL
? slash
+ 1 : NULL
;
318 ret
= vfs_split (path
, inpath
, op
);
323 static struct vfs_class
*
324 _vfs_get_class (char *path
)
328 struct vfs_class
*ret
;
330 g_return_val_if_fail (path
, NULL
);
332 semi
= strrchr (path
, '#');
333 if (semi
== NULL
|| !path_magic (path
))
336 slash
= strchr (semi
, PATH_SEP
);
341 ret
= vfs_prefix_to_class (semi
+ 1);
346 ret
= _vfs_get_class (path
);
353 vfs_get_class (const char *pathname
)
355 struct vfs_class
*vfs
;
356 char *path
= g_strdup (pathname
);
358 vfs
= _vfs_get_class (path
);
368 vfs_get_encoding (const char *path
)
370 static char result
[16];
375 work
= g_strdup (path
);
376 semi
= g_strrstr (work
, "#enc:");
380 semi
+= 5 * sizeof (char);
381 slash
= strchr (semi
, PATH_SEP
);
385 g_strlcpy (result
, semi
, sizeof (result
));
396 /* return if encoding can by used in vfs (is ascci full compactible) */
397 /* contains only a few encoding now */
399 vfs_supported_enconding (const char *encoding
)
401 gboolean result
= FALSE
;
406 for (t
= 0; t
< n_codepages
; t
++)
407 result
|= (g_ascii_strncasecmp (encoding
, codepages
[t
].id
,
408 strlen (codepages
[t
].id
)) == 0);
414 /* now used only by vfs_translate_path, but could be used in other vfs
415 * plugin to automatic detect encoding
416 * path - path to translate
417 * size - how many bytes from path translate
418 * defcnv - convertor, that is used as default, when path does not contain any
420 * buffer - used to store result of translation
423 _vfs_translate_path (const char *path
, int size
, GIConv defcnv
, GString
* buffer
)
428 estr_t state
= ESTR_SUCCESS
;
433 size
= (size
> 0) ? size
: (signed int) strlen (path
);
435 /* try found #end: */
436 semi
= g_strrstr_len (path
, size
, "#enc:");
440 GIConv coder
= INVALID_CONV
;
443 /* first must be translated part before #enc: */
446 /* remove '/' before #enc */
447 ps
= str_cget_prev_char (semi
);
448 if (ps
[0] == PATH_SEP
)
451 state
= _vfs_translate_path (path
, ms
, defcnv
, buffer
);
453 if (state
!= ESTR_SUCCESS
)
455 /* now can be translated part after #enc: */
458 slash
= strchr (semi
, PATH_SEP
);
459 /* ignore slashes after size; */
460 if (slash
- path
>= size
)
463 ms
= (slash
!= NULL
) ? slash
- semi
: (int) strlen (semi
);
464 ms
= min ((unsigned int) ms
, sizeof (encoding
) - 1);
465 /* limit encoding size (ms) to path size (size) */
466 if (semi
+ ms
> path
+ size
)
467 ms
= path
+ size
- semi
;
468 memcpy (encoding
, semi
, ms
);
471 if (vfs_supported_enconding (encoding
))
472 coder
= str_crt_conv_to (encoding
);
474 if (coder
!= INVALID_CONV
)
477 state
= str_vfs_convert_to (coder
, slash
, path
+ size
- slash
, buffer
);
478 else if (buffer
->str
[0] == '\0')
480 /* exmaple "/#enc:utf-8" */
481 g_string_append_c (buffer
, PATH_SEP
);
483 str_close_conv (coder
);
488 state
= ESTR_FAILURE
;
492 /* path can be translated whole at once */
493 state
= str_vfs_convert_to (defcnv
, path
, size
, buffer
);
500 vfs_translate_path (const char *path
)
504 g_string_set_size (vfs_str_buffer
, 0);
505 state
= _vfs_translate_path (path
, -1, str_cnv_from_term
, vfs_str_buffer
);
508 return (state == 0) ? vfs_str_buffer->data : NULL;
510 return (state
!= ESTR_FAILURE
) ? vfs_str_buffer
->str
: NULL
;
514 vfs_translate_path_n (const char *path
)
518 result
= vfs_translate_path (path
);
519 return (result
!= NULL
) ? g_strdup (result
) : NULL
;
523 vfs_canon_and_translate (const char *path
)
528 canon
= g_strdup ("");
530 canon
= vfs_canon (path
);
531 result
= vfs_translate_path_n (canon
);
537 ferrno (struct vfs_class
*vfs
)
539 return vfs
->ferrno
? (*vfs
->ferrno
) (vfs
) : E_UNKNOWN
;
540 /* Hope that error message is obscure enough ;-) */
544 mc_open (const char *filename
, int flags
, ...)
550 struct vfs_class
*vfs
;
552 file
= vfs_canon_and_translate (filename
);
556 vfs
= vfs_get_class (file
);
558 /* Get the mode flag */
561 va_start (ap
, flags
);
562 mode
= va_arg (ap
, int);
566 if (vfs
->open
== NULL
)
573 info
= vfs
->open (vfs
, file
, flags
, mode
); /* open must be supported */
577 errno
= ferrno (vfs
);
581 return vfs_new_handle (vfs
, info
);
585 #define MC_NAMEOP(name, inarg, callarg) \
586 int mc_##name inarg \
588 struct vfs_class *vfs; \
590 char *mpath = vfs_canon_and_translate (path); \
593 vfs = vfs_get_class (mpath); \
598 result = vfs->name != NULL ? vfs->name callarg : -1; \
601 errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
605 MC_NAMEOP (chmod
, (const char *path
, mode_t mode
), (vfs
, mpath
, mode
))
606 MC_NAMEOP (chown
, (const char *path
, uid_t owner
, gid_t group
), (vfs
, mpath
, owner
, group
))
607 MC_NAMEOP (utime
, (const char *path
, struct utimbuf
* times
), (vfs
, mpath
, times
))
608 MC_NAMEOP (readlink
, (const char *path
, char *buf
, size_t bufsiz
), (vfs
, mpath
, buf
, bufsiz
))
609 MC_NAMEOP (unlink
, (const char *path
), (vfs
, mpath
))
610 MC_NAMEOP (mkdir
, (const char *path
, mode_t mode
), (vfs
, mpath
, mode
))
611 MC_NAMEOP (rmdir
, (const char *path
), (vfs
, mpath
))
612 MC_NAMEOP (mknod
, (const char *path
, mode_t mode
, dev_t dev
), (vfs
, mpath
, mode
, dev
))
615 mc_symlink (const char *name1
, const char *path
)
617 struct vfs_class
*vfs
;
623 mpath
= vfs_canon_and_translate (path
);
627 tmp
= g_strdup (name1
);
628 lpath
= vfs_translate_path_n (tmp
);
633 vfs
= vfs_get_class (mpath
);
634 result
= vfs
->symlink
!= NULL
? vfs
->symlink (vfs
, lpath
, mpath
) : -1;
639 errno
= vfs
->symlink
!= NULL
? ferrno (vfs
) : E_NOTSUPP
;
648 #define MC_HANDLEOP(name, inarg, callarg) \
649 ssize_t mc_##name inarg \
651 struct vfs_class *vfs; \
655 vfs = vfs_op (handle); \
658 result = vfs->name != NULL ? vfs->name callarg : -1; \
660 errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
664 MC_HANDLEOP (read
, (int handle
, void *buffer
, size_t count
), (vfs_info (handle
), buffer
, count
))
665 MC_HANDLEOP (write
, (int handle
, const void *buf
, size_t nbyte
), (vfs_info (handle
), buf
, nbyte
))
667 #define MC_RENAMEOP(name) \
668 int mc_##name (const char *fname1, const char *fname2) \
670 struct vfs_class *vfs; \
672 char *name2, *name1; \
673 name1 = vfs_canon_and_translate (fname1); \
676 name2 = vfs_canon_and_translate (fname2); \
677 if (name2 == NULL) { \
681 vfs = vfs_get_class (name1); \
682 if (vfs != vfs_get_class (name2)) \
689 result = vfs->name != NULL ? vfs->name (vfs, name1, name2) : -1; \
693 errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
701 mc_ctl (int handle
, int ctlop
, void *arg
)
703 struct vfs_class
*vfs
= vfs_op (handle
);
708 return vfs
->ctl
? (*vfs
->ctl
) (vfs_info (handle
), ctlop
, arg
) : 0;
712 mc_setctl (const char *path
, int ctlop
, void *arg
)
714 struct vfs_class
*vfs
;
719 vfs_die ("You don't want to pass NULL to mc_setctl.");
721 mpath
= vfs_canon_and_translate (path
);
724 vfs
= vfs_get_class (mpath
);
725 result
= vfs
->setctl
!= NULL
? vfs
->setctl (vfs
, mpath
, ctlop
, arg
) : 0;
733 mc_close (int handle
)
735 struct vfs_class
*vfs
;
738 if (handle
== -1 || !vfs_info (handle
))
741 vfs
= vfs_op (handle
);
746 return close (handle
);
749 vfs_die ("VFS must support close.\n");
750 result
= (*vfs
->close
) (vfs_info (handle
));
751 vfs_free_handle (handle
);
753 errno
= ferrno (vfs
);
759 mc_opendir (const char *dirname
)
761 int handle
, *handlep
;
763 struct vfs_class
*vfs
;
766 struct vfs_dirinfo
*dirinfo
;
767 const char *encoding
;
769 canon
= vfs_canon (dirname
);
770 dname
= vfs_translate_path_n (canon
);
774 vfs
= vfs_get_class (dname
);
775 info
= vfs
->opendir
? (*vfs
->opendir
) (vfs
, dname
) : NULL
;
780 errno
= vfs
->opendir
? ferrno (vfs
) : E_NOTSUPP
;
785 dirinfo
= g_new (struct vfs_dirinfo
, 1);
786 dirinfo
->info
= info
;
788 encoding
= vfs_get_encoding (canon
);
790 dirinfo
->converter
= (encoding
!= NULL
) ? str_crt_conv_from (encoding
) : str_cnv_from_term
;
791 if (dirinfo
->converter
== INVALID_CONV
)
792 dirinfo
->converter
= str_cnv_from_term
;
794 handle
= vfs_new_handle (vfs
, dirinfo
);
796 handlep
= g_new (int, 1);
798 return (DIR *) handlep
;
807 static struct dirent
*mc_readdir_result
= NULL
;
810 mc_readdir (DIR * dirp
)
813 struct vfs_class
*vfs
;
814 struct dirent
*entry
= NULL
;
815 struct vfs_dirinfo
*dirinfo
;
818 if (!mc_readdir_result
)
820 /* We can't just allocate struct dirent as (see man dirent.h)
821 * struct dirent has VERY nonnaive semantics of allocating
822 * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
823 * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
824 * heap corrupter. So, allocate longliving dirent with at least
825 * (MAXNAMLEN + 1) for d_name in it.
826 * Strictly saying resulting dirent is unusable as we don't adjust internal
827 * structures, holding dirent size. But we don't use it in libc infrastructure.
828 * TODO: to make simpler homemade dirent-alike structure.
830 mc_readdir_result
= (struct dirent
*) g_malloc (sizeof (struct dirent
) + MAXNAMLEN
+ 1);
838 handle
= *(int *) dirp
;
840 vfs
= vfs_op (handle
);
844 dirinfo
= vfs_info (handle
);
847 entry
= (*vfs
->readdir
) (dirinfo
->info
);
850 g_string_set_size (vfs_str_buffer
, 0);
851 state
= str_vfs_convert_from (dirinfo
->converter
, entry
->d_name
, vfs_str_buffer
);
852 mc_readdir_result
->d_ino
= entry
->d_ino
;
853 g_strlcpy (mc_readdir_result
->d_name
, vfs_str_buffer
->str
, MAXNAMLEN
+ 1);
856 errno
= vfs
->readdir
? ferrno (vfs
) : E_NOTSUPP
;
857 return (entry
!= NULL
) ? mc_readdir_result
: NULL
;
861 mc_closedir (DIR * dirp
)
863 int handle
= *(int *) dirp
;
864 struct vfs_class
*vfs
;
867 vfs
= vfs_op (handle
);
870 struct vfs_dirinfo
*dirinfo
;
872 dirinfo
= vfs_info (handle
);
873 if (dirinfo
->converter
!= str_cnv_from_term
)
874 str_close_conv (dirinfo
->converter
);
876 result
= vfs
->closedir
? (*vfs
->closedir
) (dirinfo
->info
) : -1;
877 vfs_free_handle (handle
);
885 mc_stat (const char *filename
, struct stat
*buf
)
887 struct vfs_class
*vfs
;
891 path
= vfs_canon_and_translate (filename
);
896 vfs
= vfs_get_class (path
);
904 result
= vfs
->stat
? (*vfs
->stat
) (vfs
, path
, buf
) : -1;
909 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
914 mc_lstat (const char *filename
, struct stat
*buf
)
916 struct vfs_class
*vfs
;
920 path
= vfs_canon_and_translate (filename
);
925 vfs
= vfs_get_class (path
);
932 result
= vfs
->lstat
? (*vfs
->lstat
) (vfs
, path
, buf
) : -1;
935 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
940 mc_fstat (int handle
, struct stat
*buf
)
942 struct vfs_class
*vfs
;
948 vfs
= vfs_op (handle
);
952 result
= vfs
->fstat
? (*vfs
->fstat
) (vfs_info (handle
), buf
) : -1;
954 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
959 * Return current directory. If it's local, reread the current directory
960 * from the OS. You must g_strdup() whatever this function returns.
967 trans
= vfs_translate_path_n (current_dir
);
969 if (_vfs_get_class (trans
) == NULL
)
971 const char *encoding
= vfs_get_encoding (current_dir
);
973 if (encoding
== NULL
)
977 tmp
= g_get_current_dir ();
979 { /* One of the directories in the path is not readable */
983 g_string_set_size (vfs_str_buffer
, 0);
984 state
= str_vfs_convert_from (str_cnv_from_term
, tmp
, vfs_str_buffer
);
987 sys_cwd
= (state
== ESTR_SUCCESS
) ? g_strdup (vfs_str_buffer
->str
) : NULL
;
990 struct stat my_stat
, my_stat2
;
991 /* Check if it is O.K. to use the current_dir */
993 && mc_stat (sys_cwd
, &my_stat
) == 0
994 && mc_stat (current_dir
, &my_stat2
) == 0
995 && my_stat
.st_ino
== my_stat2
.st_ino
&& my_stat
.st_dev
== my_stat2
.st_dev
)
999 g_free (current_dir
);
1000 current_dir
= sys_cwd
;
1014 current_dir
= g_strdup (PATH_SEP_STR
);
1017 if (strlen (current_dir
) > MC_MAXPATHLEN
- 2)
1018 vfs_die ("Current dir too long.\n");
1020 current_vfs
= vfs_get_class (current_dir
);
1024 * Return current directory. If it's local, reread the current directory
1025 * from the OS. Put directory to the provided buffer.
1028 mc_get_current_wd (char *buffer
, size_t size
)
1030 const char *cwd
= _vfs_get_cwd ();
1032 g_strlcpy (buffer
, cwd
, size
);
1037 * Return current directory without any OS calls.
1040 vfs_get_current_dir (void)
1046 mc_lseek (int fd
, off_t offset
, int whence
)
1048 struct vfs_class
*vfs
;
1058 result
= vfs
->lseek
? (*vfs
->lseek
) (vfs_info (fd
), offset
, whence
) : -1;
1060 errno
= vfs
->lseek
? ferrno (vfs
) : E_NOTSUPP
;
1065 * remove //, /./ and /../
1068 #define ISSLASH(a) (!a || (a == '/'))
1071 vfs_canon (const char *path
)
1074 vfs_die ("Cannot canonicalize NULL");
1076 /* Relative to current directory */
1077 if (*path
!= PATH_SEP
)
1079 char *local
, *result
;
1081 local
= concat_dir_and_file (current_dir
, path
);
1083 result
= vfs_canon (local
);
1089 * So we have path of following form:
1090 * /p1/p2#op/.././././p3#op/p4. Good luck.
1093 char *result
= g_strdup (path
);
1094 canonicalize_pathname (result
);
1101 * Return 0 on success, -1 on failure.
1104 mc_chdir (const char *path
)
1108 struct vfs_class
*old_vfs
, *new_vfs
;
1112 new_dir
= vfs_canon (path
);
1113 trans_dir
= vfs_translate_path_n (new_dir
);
1114 if (trans_dir
!= NULL
)
1116 new_vfs
= vfs_get_class (trans_dir
);
1117 if (!new_vfs
->chdir
)
1124 result
= (*new_vfs
->chdir
) (new_vfs
, trans_dir
);
1128 errno
= ferrno (new_vfs
);
1134 old_vfsid
= vfs_getid (current_vfs
, current_dir
);
1135 old_vfs
= current_vfs
;
1137 /* Actually change directory */
1138 g_free (current_dir
);
1139 current_dir
= new_dir
;
1140 current_vfs
= new_vfs
;
1142 /* This function uses the new current_dir implicitly */
1143 vfs_stamp_create (old_vfs
, old_vfsid
);
1145 /* Sometimes we assume no trailing slash on cwd */
1149 p
= strchr (current_dir
, 0) - 1;
1150 if (*p
== PATH_SEP
&& p
> current_dir
)
1164 /* Return TRUE is the current VFS class is local */
1166 vfs_current_is_local (void)
1168 return (current_vfs
->flags
& VFSF_LOCAL
) != 0;
1171 /* Return flags of the VFS class of the given filename */
1173 vfs_file_class_flags (const char *filename
)
1175 struct vfs_class
*vfs
;
1178 fname
= vfs_canon_and_translate (filename
);
1180 return VFSF_UNKNOWN
;
1182 vfs
= vfs_get_class (fname
);
1188 mc_def_getlocalcopy (const char *filename
)
1196 fdin
= mc_open (filename
, O_RDONLY
| O_LINEAR
);
1200 fdout
= vfs_mkstemps (&tmp
, "vfs", filename
);
1204 while ((i
= mc_read (fdin
, buffer
, sizeof (buffer
))) > 0)
1206 if (write (fdout
, buffer
, i
) != i
)
1211 i
= mc_close (fdin
);
1215 if (close (fdout
) == -1)
1221 if (mc_stat (filename
, &mystat
) != -1)
1222 chmod (tmp
, mystat
.st_mode
);
1236 mc_getlocalcopy (const char *pathname
)
1238 char *result
= NULL
;
1241 path
= vfs_canon_and_translate (pathname
);
1244 struct vfs_class
*vfs
= vfs_get_class (path
);
1246 result
= vfs
->getlocalcopy
!= NULL
?
1247 vfs
->getlocalcopy (vfs
, path
) :
1248 mc_def_getlocalcopy (path
);
1251 errno
= ferrno (vfs
);
1258 mc_def_ungetlocalcopy (struct vfs_class
*vfs
, const char *filename
,
1259 const char *local
, int has_changed
)
1261 int fdin
= -1, fdout
= -1;
1270 fdin
= open (local
, O_RDONLY
);
1273 fdout
= mc_open (filename
, O_WRONLY
| O_TRUNC
);
1276 while ((i
= read (fdin
, buffer
, sizeof (buffer
))) > 0)
1277 if (mc_write (fdout
, buffer
, (size_t) i
) != i
)
1282 if (close (fdin
) == -1)
1288 if (mc_close (fdout
) == -1)
1298 message (D_ERROR
, _("Changes to file lost"), "%s", filename
);
1308 mc_ungetlocalcopy (const char *pathname
, const char *local
, int has_changed
)
1310 int return_value
= -1;
1313 path
= vfs_canon_and_translate (pathname
);
1316 struct vfs_class
*vfs
= vfs_get_class (path
);
1318 return_value
= vfs
->ungetlocalcopy
!= NULL
?
1319 vfs
->ungetlocalcopy (vfs
, path
, local
, has_changed
) :
1320 mc_def_ungetlocalcopy (vfs
, path
, local
, has_changed
);
1324 return return_value
;
1331 /* create the VFS handle array */
1332 vfs_openfiles
= g_ptr_array_new ();
1334 vfs_str_buffer
= g_string_new ("");
1335 /* localfs needs to be the first one */
1337 /* fallback value for vfs_get_class() */
1338 localfs_class
= vfs_list
;
1340 #ifdef ENABLE_VFS_CPIO
1342 #endif /* ENABLE_VFS_CPIO */
1343 #ifdef ENABLE_VFS_TAR
1345 #endif /* ENABLE_VFS_TAR */
1346 #ifdef ENABLE_VFS_SFS
1348 #endif /* ENABLE_VFS_SFS */
1349 #ifdef ENABLE_VFS_EXTFS
1351 #endif /* ENABLE_VFS_EXTFS */
1352 #ifdef ENABLE_VFS_UNDELFS
1354 #endif /* ENABLE_VFS_UNDELFS */
1356 #ifdef ENABLE_VFS_FTP
1358 #endif /* ENABLE_VFS_FTP */
1359 #ifdef ENABLE_VFS_FISH
1361 #endif /* ENABLE_VFS_FISH */
1362 #ifdef ENABLE_VFS_SMB
1364 #endif /* ENABLE_VFS_SMB */
1372 struct vfs_class
*vfs
;
1376 g_free (current_dir
);
1378 for (vfs
= vfs_list
; vfs
; vfs
= vfs
->next
)
1382 g_ptr_array_free (vfs_openfiles
, TRUE
);
1383 g_string_free (vfs_str_buffer
, TRUE
);
1384 g_free (mc_readdir_result
);
1388 * These ones grab information from the VFS
1389 * and handles them to an upper layer
1392 vfs_fill_names (fill_names_f func
)
1394 struct vfs_class
*vfs
;
1396 for (vfs
= vfs_list
; vfs
; vfs
= vfs
->next
)
1397 if (vfs
->fill_names
)
1398 (*vfs
->fill_names
) (vfs
, func
);
1402 * Returns vfs path corresponding to given url. If passed string is
1403 * not recognized as url, g_strdup(url) is returned.
1410 const char *substitute
;
1414 #ifdef ENABLE_VFS_FTP
1415 { "ftp://", 6, "/#ftp:" },
1417 #ifdef ENABLE_VFS_FISH
1418 { "sh://", 5, "/#sh:" },
1419 { "ssh://", 6, "/#sh:" },
1421 #ifdef ENABLE_VFS_SMB
1422 { "smb://", 6, "/#smb:" },
1429 vfs_translate_url (const char *url
)
1433 for (i
= 0; i
< sizeof (url_table
) / sizeof (url_table
[0]); i
++)
1434 if (strncmp (url
, url_table
[i
].name
, url_table
[i
].name_len
) == 0)
1435 return g_strconcat (url_table
[i
].substitute
, url
+ url_table
[i
].name_len
,
1438 return g_strdup (url
);
1442 vfs_file_is_local (const char *filename
)
1444 return (vfs_file_class_flags (filename
) & VFSF_LOCAL
) != 0;