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() */
49 #include "../src/global.h"
50 #include "../src/tty.h" /* enable/disable interrupt key */
51 #include "../src/wtools.h" /* message() */
52 #include "../src/main.h" /* print_vfs_message */
53 #include "../src/strutil.h"
66 /** They keep track of the current directory */
67 static struct vfs_class
*current_vfs
;
68 static char *current_dir
;
72 struct vfs_class
*vclass
;
82 static GSList
*vfs_openfiles
;
83 #define VFS_FIRST_HANDLE 100
85 static struct vfs_class
*localfs_class
;
86 static GString
*vfs_str_buffer
;
88 static const char *supported_encodings
[] = {
103 /** Create new VFS handle and put it to the list */
105 vfs_new_handle (struct vfs_class
*vclass
, void *fsinfo
)
107 static int vfs_handle_counter
= VFS_FIRST_HANDLE
;
108 struct vfs_openfile
*h
;
110 h
= g_new (struct vfs_openfile
, 1);
111 h
->handle
= vfs_handle_counter
++;
114 vfs_openfiles
= g_slist_prepend (vfs_openfiles
, h
);
118 /** Function to match handle, passed to g_slist_find_custom() */
120 vfs_cmp_handle (gconstpointer a
, gconstpointer b
)
124 return ((struct vfs_openfile
*) a
)->handle
!= (long) b
;
127 /** Find VFS class by file handle */
128 static inline struct vfs_class
*
132 struct vfs_openfile
*h
;
134 l
= g_slist_find_custom (vfs_openfiles
, (void *) (long) handle
,
138 h
= (struct vfs_openfile
*) l
->data
;
144 /** Find private file data by file handle */
146 vfs_info (int handle
)
149 struct vfs_openfile
*h
;
151 l
= g_slist_find_custom (vfs_openfiles
, (void *) (long) handle
,
155 h
= (struct vfs_openfile
*) l
->data
;
161 /** Free open file data for given file handle */
163 vfs_free_handle (int handle
)
167 l
= g_slist_find_custom (vfs_openfiles
, (void *) (long) handle
,
169 vfs_openfiles
= g_slist_delete_link (vfs_openfiles
, l
);
172 static struct vfs_class
*vfs_list
;
175 vfs_register_class (struct vfs_class
*vfs
)
177 if (vfs
->init
) /* vfs has own initialization function */
178 if (!(*vfs
->init
)(vfs
)) /* but it failed */
181 vfs
->next
= vfs_list
;
187 /** Return VFS class for the given prefix */
188 static struct vfs_class
*
189 vfs_prefix_to_class (char *prefix
)
191 struct vfs_class
*vfs
;
193 /* Avoid last class (localfs) that would accept any prefix */
194 for (vfs
= vfs_list
; vfs
->next
; vfs
= vfs
->next
) {
196 if ((*vfs
->which
) (vfs
, prefix
) == -1)
201 && !strncmp (prefix
, vfs
->prefix
, strlen (vfs
->prefix
)))
207 /** Strip known vfs suffixes from a filename (possible improvement: strip
208 * suffix from last path component).
209 * \return a malloced string which has to be freed.
212 vfs_strip_suffix_from_filename (const char *filename
)
214 struct vfs_class
*vfs
;
219 vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
221 p
= g_strdup (filename
);
222 if (!(semi
= strrchr (p
, '#')))
225 /* Avoid last class (localfs) that would accept any prefix */
226 for (vfs
= vfs_list
; vfs
->next
; vfs
= vfs
->next
) {
228 if ((*vfs
->which
) (vfs
, semi
+ 1) == -1)
230 *semi
= '\0'; /* Found valid suffix */
234 && !strncmp (semi
+ 1, vfs
->prefix
, strlen (vfs
->prefix
))) {
235 *semi
= '\0'; /* Found valid suffix */
243 path_magic (const char *path
)
247 if (!stat(path
, &buf
))
254 * Splits path '/p1#op/inpath' into inpath,op; returns which vfs it is.
255 * What is left in path is p1. You still want to g_free(path), you DON'T
256 * want to free neither *inpath nor *op
259 vfs_split (char *path
, char **inpath
, char **op
)
263 struct vfs_class
*ret
;
266 vfs_die("Cannot split NULL");
268 semi
= strrchr (path
, '#');
269 if (!semi
|| !path_magic(path
))
272 slash
= strchr (semi
, PATH_SEP
);
284 if ((ret
= vfs_prefix_to_class (semi
+1))){
288 *inpath
= slash
? slash
+ 1 : NULL
;
295 ret
= vfs_split (path
, inpath
, op
);
300 static struct vfs_class
*
301 _vfs_get_class (char *path
)
305 struct vfs_class
*ret
;
307 g_return_val_if_fail(path
, NULL
);
309 semi
= strrchr (path
, '#');
310 if (!semi
|| !path_magic (path
))
313 slash
= strchr (semi
, PATH_SEP
);
318 ret
= vfs_prefix_to_class (semi
+1);
323 ret
= _vfs_get_class (path
);
330 vfs_get_class (const char *pathname
)
332 struct vfs_class
*vfs
;
333 char *path
= g_strdup (pathname
);
335 vfs
= _vfs_get_class (path
);
345 vfs_get_encoding (const char *path
)
347 static char result
[16];
352 work
= g_strdup (path
);
353 semi
= g_strrstr (work
, "#enc:");
356 semi
+= 5 * sizeof (char);
357 slash
= strchr (semi
, PATH_SEP
);
361 g_strlcpy (result
, semi
, sizeof(result
));
370 /* return if encoding can by used in vfs (is ascci full compactible) */
371 /* contains only a few encoding now */
373 vfs_supported_enconding (const char *encoding
) {
377 for (t
= 0; supported_encodings
[t
] != NULL
; t
++) {
378 result
+= (g_ascii_strncasecmp (encoding
, supported_encodings
[t
],
379 strlen (supported_encodings
[t
])) == 0);
385 /* now used only by vfs_translate_path, but could be used in other vfs
386 * plugin to automatic detect encoding
387 * path - path to translate
388 * size - how many bytes from path translate
389 * defcnv - convertor, that is used as default, when path does not contain any
391 * buffer - used to store result of translation
394 _vfs_translate_path (const char *path
, int size
,
395 GIConv defcnv
, GString
*buffer
)
400 estr_t state
= ESTR_SUCCESS
;
401 static char encoding
[16];
405 if (size
== 0) return 0;
406 size
= ( size
> 0) ? size
: (signed int)strlen (path
);
408 /* try found #end: */
409 semi
= g_strrstr_len (path
, size
, "#enc:");
411 /* first must be translated part before #enc: */
414 /* remove '/' before #enc */
415 ps
= str_cget_prev_char (semi
);
416 if (ps
[0] == PATH_SEP
) ms
= ps
- path
;
418 state
= _vfs_translate_path (path
, ms
, defcnv
, buffer
);
420 if (state
!= ESTR_SUCCESS
)
422 /* now can be translated part after #enc: */
425 slash
= strchr (semi
, PATH_SEP
);
426 /* ignore slashes after size; */
427 if (slash
- path
>= size
) slash
= NULL
;
429 ms
= (slash
!= NULL
) ? slash
- semi
: (int) strlen (semi
);
430 ms
= min ((unsigned int) ms
, sizeof (encoding
) - 1);
431 /* limit encoding size (ms) to path size (size) */
432 if (semi
+ ms
> path
+ size
) ms
= path
+ size
- semi
;
433 memcpy (encoding
, semi
, ms
);
436 switch (vfs_supported_enconding (encoding
)) {
438 coder
= str_crt_conv_to (encoding
);
439 if (coder
!= INVALID_CONV
) {
441 state
= str_vfs_convert_to (coder
, slash
,
442 path
+ size
- slash
, buffer
);
443 } else if (buffer
->str
[0] == '\0') {
444 /* exmaple "/#enc:utf-8" */
445 g_string_append_c(buffer
, PATH_SEP
);
447 str_close_conv (coder
);
459 /* path can be translated whole at once */
460 state
= str_vfs_convert_to (defcnv
, path
, size
, buffer
);
468 vfs_translate_path (const char *path
)
472 g_string_set_size(vfs_str_buffer
,0);
473 state
= _vfs_translate_path (path
, -1, str_cnv_from_term
, vfs_str_buffer
);
476 return (state == 0) ? vfs_str_buffer->data : NULL;
478 return (state
!= ESTR_FAILURE
) ? vfs_str_buffer
->str
: NULL
;
482 vfs_translate_path_n (const char *path
)
486 result
= vfs_translate_path (path
);
487 return (result
!= NULL
) ? g_strdup (result
) : NULL
;
491 vfs_canon_and_translate (const char *path
)
495 canon
= vfs_canon (path
);
496 result
= vfs_translate_path_n (canon
);
502 ferrno (struct vfs_class
*vfs
)
504 return vfs
->ferrno
? (*vfs
->ferrno
)(vfs
) : E_UNKNOWN
;
505 /* Hope that error message is obscure enough ;-) */
509 mc_open (const char *filename
, int flags
, ...)
515 char *file
= vfs_canon_and_translate (filename
);
517 struct vfs_class
*vfs
= vfs_get_class (file
);
519 /* Get the mode flag */
520 if (flags
& O_CREAT
) {
521 va_start (ap
, flags
);
522 mode
= va_arg (ap
, int);
533 info
= (*vfs
->open
) (vfs
, file
, flags
, mode
); /* open must be supported */
536 errno
= ferrno (vfs
);
540 return vfs_new_handle (vfs
, info
);
545 #define MC_NAMEOP(name, inarg, callarg) \
546 int mc_##name inarg \
548 struct vfs_class *vfs; \
550 char *mpath = vfs_canon_and_translate (path); \
551 if (mpath != NULL) { \
552 vfs = vfs_get_class (mpath); \
553 result = vfs->name ? (*vfs->name)callarg : -1; \
556 errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
561 MC_NAMEOP (chmod
, (const char *path
, mode_t mode
), (vfs
, mpath
, mode
))
562 MC_NAMEOP (chown
, (const char *path
, uid_t owner
, gid_t group
), (vfs
, mpath
, owner
, group
))
563 MC_NAMEOP (utime
, (const char *path
, struct utimbuf
*times
), (vfs
, mpath
, times
))
564 MC_NAMEOP (readlink
, (const char *path
, char *buf
, int bufsiz
), (vfs
, mpath
, buf
, bufsiz
))
565 MC_NAMEOP (unlink
, (const char *path
), (vfs
, mpath
))
566 MC_NAMEOP (mkdir
, (const char *path
, mode_t mode
), (vfs
, mpath
, mode
))
567 MC_NAMEOP (rmdir
, (const char *path
), (vfs
, mpath
))
568 MC_NAMEOP (mknod
, (const char *path
, mode_t mode
, dev_t dev
), (vfs
, mpath
, mode
, dev
))
571 mc_symlink (const char *name1
, const char *path
)
573 struct vfs_class
*vfs
;
579 mpath
= vfs_canon_and_translate (path
);
581 tmp
= g_strdup (name1
);
582 lpath
= vfs_translate_path_n (tmp
);
586 vfs
= vfs_get_class (mpath
);
587 result
= vfs
->symlink
? (*vfs
->symlink
) (vfs
, lpath
, mpath
) : -1;
591 errno
= vfs
->symlink
? ferrno (vfs
) : E_NOTSUPP
;
599 #define MC_HANDLEOP(name, inarg, callarg) \
600 ssize_t mc_##name inarg \
602 struct vfs_class *vfs; \
606 vfs = vfs_op (handle); \
607 result = vfs->name ? (*vfs->name)callarg : -1; \
609 errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
613 MC_HANDLEOP(read
, (int handle
, void *buffer
, int count
), (vfs_info (handle
), buffer
, count
))
614 MC_HANDLEOP(write
, (int handle
, const void *buf
, int nbyte
), (vfs_info (handle
), buf
, nbyte
))
617 #define MC_RENAMEOP(name) \
618 int mc_##name (const char *fname1, const char *fname2) \
620 struct vfs_class *vfs; \
622 char *name2, *name1; \
623 name1 = vfs_canon_and_translate (fname1); \
624 if (name1 != NULL) { \
625 name2 = vfs_canon_and_translate (fname2); \
626 if (name2 != NULL) { \
627 vfs = vfs_get_class (name1); \
628 if (vfs != vfs_get_class (name2)){ \
634 result = vfs->name ? (*vfs->name)(vfs, name1, name2) : -1; \
638 errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
652 mc_ctl (int handle
, int ctlop
, void *arg
)
654 struct vfs_class
*vfs
= vfs_op (handle
);
656 return vfs
->ctl
? (*vfs
->ctl
)(vfs_info (handle
), ctlop
, arg
) : 0;
660 mc_setctl (const char *path
, int ctlop
, void *arg
)
662 struct vfs_class
*vfs
;
667 vfs_die("You don't want to pass NULL to mc_setctl.");
669 mpath
= vfs_canon_and_translate (path
);
671 vfs
= vfs_get_class (mpath
);
672 result
= vfs
->setctl
? (*vfs
->setctl
)(vfs
, mpath
, ctlop
, arg
) : 0;
679 mc_close (int handle
)
681 struct vfs_class
*vfs
;
684 if (handle
== -1 || !vfs_info (handle
))
687 vfs
= vfs_op (handle
);
689 return close (handle
);
692 vfs_die ("VFS must support close.\n");
693 result
= (*vfs
->close
)(vfs_info (handle
));
694 vfs_free_handle (handle
);
696 errno
= ferrno (vfs
);
702 mc_opendir (const char *dirname
)
704 int handle
, *handlep
;
706 struct vfs_class
*vfs
;
709 struct vfs_dirinfo
*dirinfo
;
710 const char *encoding
;
712 canon
= vfs_canon (dirname
);
713 dname
= vfs_translate_path_n (canon
);
716 vfs
= vfs_get_class (dname
);
717 info
= vfs
->opendir
? (*vfs
->opendir
)(vfs
, dname
) : NULL
;
721 errno
= vfs
->opendir
? ferrno (vfs
) : E_NOTSUPP
;
726 dirinfo
= g_new (struct vfs_dirinfo
, 1);
727 dirinfo
->info
= info
;
729 encoding
= vfs_get_encoding (canon
);
731 dirinfo
->converter
= (encoding
!= NULL
) ? str_crt_conv_from (encoding
) :
733 if (dirinfo
->converter
== INVALID_CONV
) dirinfo
->converter
=str_cnv_from_term
;
735 handle
= vfs_new_handle (vfs
, dirinfo
);
737 handlep
= g_new (int, 1);
739 return (DIR *) handlep
;
746 static struct dirent
* mc_readdir_result
= NULL
;
749 mc_readdir (DIR *dirp
)
752 struct vfs_class
*vfs
;
753 struct dirent
*entry
= NULL
;
754 struct vfs_dirinfo
*dirinfo
;
757 if (!mc_readdir_result
)
759 /* We can't just allocate struct dirent as (see man dirent.h)
760 * struct dirent has VERY nonnaive semantics of allocating
761 * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
762 * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
763 * heap corrupter. So, allocate longliving dirent with at least
764 * (NAME_MAX + 1) for d_name in it.
765 * Strictly saying resulting dirent is unusable as we don't adjust internal
766 * structures, holding dirent size. But we don't use it in libc infrastructure.
767 * TODO: to make simpler homemade dirent-alike structure.
769 mc_readdir_result
= (struct dirent
*)malloc(sizeof(struct dirent
*) + NAME_MAX
+ 1);
776 handle
= *(int *) dirp
;
777 vfs
= vfs_op (handle
);
778 dirinfo
= vfs_info (handle
);
780 entry
= (*vfs
->readdir
) (dirinfo
->info
);
781 if (entry
== NULL
) return NULL
;
782 g_string_set_size(vfs_str_buffer
,0);
783 state
= str_vfs_convert_from (dirinfo
->converter
,
784 entry
->d_name
, vfs_str_buffer
);
785 mc_readdir_result
->d_ino
= entry
->d_ino
;
786 g_strlcpy (mc_readdir_result
->d_name
, vfs_str_buffer
->str
, NAME_MAX
+ 1);
788 if (entry
== NULL
) errno
= vfs
->readdir
? ferrno (vfs
) : E_NOTSUPP
;
789 return (entry
!= NULL
) ? mc_readdir_result
: NULL
;
793 mc_closedir (DIR *dirp
)
795 int handle
= *(int *) dirp
;
796 struct vfs_class
*vfs
= vfs_op (handle
);
798 struct vfs_dirinfo
*dirinfo
;
800 dirinfo
= vfs_info (handle
);
801 if (dirinfo
->converter
!= str_cnv_from_term
) str_close_conv (dirinfo
->converter
);
803 result
= vfs
->closedir
? (*vfs
->closedir
)(dirinfo
->info
) : -1;
804 vfs_free_handle (handle
);
810 int mc_stat (const char *filename
, struct stat
*buf
) {
811 struct vfs_class
*vfs
;
815 path
= vfs_canon_and_translate (filename
);
818 vfs
= vfs_get_class (path
);
820 result
= vfs
->stat
? (*vfs
->stat
) (vfs
, path
, buf
) : -1;
825 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
830 int mc_lstat (const char *filename
, struct stat
*buf
) {
831 struct vfs_class
*vfs
;
835 path
= vfs_canon_and_translate (filename
);
838 vfs
= vfs_get_class (path
);
839 result
= vfs
->lstat
? (*vfs
->lstat
) (vfs
, path
, buf
) : -1;
842 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
847 int mc_fstat (int handle
, struct stat
*buf
) {
848 struct vfs_class
*vfs
;
853 vfs
= vfs_op (handle
);
854 result
= vfs
->fstat
? (*vfs
->fstat
) (vfs_info (handle
), buf
) : -1;
856 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
861 * Return current directory. If it's local, reread the current directory
862 * from the OS. You must g_strdup() whatever this function returns.
869 const char *encoding
;
872 struct stat my_stat
, my_stat2
;
874 trans
= vfs_translate_path_n (current_dir
); /* add check if NULL */
876 if (!_vfs_get_class (trans
)) {
877 encoding
= vfs_get_encoding (current_dir
);
878 if (encoding
== NULL
) {
879 tmp
= g_get_current_dir ();
880 if (tmp
!= NULL
) { /* One of the directories in the path is not readable */
881 g_string_set_size(vfs_str_buffer
,0);
882 state
= str_vfs_convert_from (str_cnv_from_term
, tmp
, vfs_str_buffer
);
884 sys_cwd
= (state
== ESTR_SUCCESS
) ? g_strdup (vfs_str_buffer
->str
) : NULL
;
888 /* Otherwise check if it is O.K. to use the current_dir */
889 if (!cd_symlinks
|| mc_stat (sys_cwd
, &my_stat
)
890 || mc_stat (current_dir
, &my_stat2
)
891 || my_stat
.st_ino
!= my_stat2
.st_ino
892 || my_stat
.st_dev
!= my_stat2
.st_dev
) {
893 g_free (current_dir
);
894 current_dir
= sys_cwd
;
896 }/* Otherwise we return current_dir below */
907 current_dir
= g_strdup (PATH_SEP_STR
);
910 if (strlen (current_dir
) > MC_MAXPATHLEN
- 2)
911 vfs_die ("Current dir too long.\n");
913 current_vfs
= vfs_get_class (current_dir
);
917 * Return current directory. If it's local, reread the current directory
918 * from the OS. Put directory to the provided buffer.
921 mc_get_current_wd (char *buffer
, int size
)
923 const char *cwd
= _vfs_get_cwd ();
925 g_strlcpy (buffer
, cwd
, size
);
930 * Return current directory without any OS calls.
933 vfs_get_current_dir (void)
938 off_t
mc_lseek (int fd
, off_t offset
, int whence
)
940 struct vfs_class
*vfs
;
947 result
= vfs
->lseek
? (*vfs
->lseek
)(vfs_info (fd
), offset
, whence
) : -1;
949 errno
= vfs
->lseek
? ferrno (vfs
) : E_NOTSUPP
;
954 * remove //, /./ and /../
957 #define ISSLASH(a) (!a || (a == '/'))
960 vfs_canon (const char *path
)
963 vfs_die("Cannot canonicalize NULL");
965 /* Relative to current directory */
966 if (*path
!= PATH_SEP
){
967 char *local
, *result
;
969 local
= concat_dir_and_file (current_dir
, path
);
971 result
= vfs_canon (local
);
977 * So we have path of following form:
978 * /p1/p2#op/.././././p3#op/p4. Good luck.
981 char *result
= g_strdup (path
);
982 canonicalize_pathname (result
);
989 * Return 0 on success, -1 on failure.
992 mc_chdir (const char *path
)
996 struct vfs_class
*old_vfs
, *new_vfs
;
1000 new_dir
= vfs_canon (path
);
1001 trans_dir
= vfs_translate_path_n (new_dir
);
1002 if (trans_dir
!= NULL
) {
1003 new_vfs
= vfs_get_class (trans_dir
);
1004 if (!new_vfs
->chdir
) {
1010 result
= (*new_vfs
->chdir
) (new_vfs
, trans_dir
);
1013 errno
= ferrno (new_vfs
);
1019 old_vfsid
= vfs_getid (current_vfs
, current_dir
);
1020 old_vfs
= current_vfs
;
1022 /* Actually change directory */
1023 g_free (current_dir
);
1024 current_dir
= new_dir
;
1025 current_vfs
= new_vfs
;
1027 /* This function uses the new current_dir implicitly */
1028 vfs_stamp_create (old_vfs
, old_vfsid
);
1030 /* Sometimes we assume no trailing slash on cwd */
1033 p
= strchr (current_dir
, 0) - 1;
1034 if (*p
== PATH_SEP
&& p
> current_dir
)
1046 /* Return 1 is the current VFS class is local */
1048 vfs_current_is_local (void)
1050 return (current_vfs
->flags
& VFSF_LOCAL
) != 0;
1053 /* Return flags of the VFS class of the given filename */
1055 vfs_file_class_flags (const char *filename
)
1057 struct vfs_class
*vfs
;
1060 fname
= vfs_canon_and_translate (filename
);
1061 if (fname
!= NULL
) {
1062 vfs
= vfs_get_class (fname
);
1069 mc_def_getlocalcopy (const char *filename
)
1076 fdin
= mc_open (filename
, O_RDONLY
| O_LINEAR
);
1080 fdout
= vfs_mkstemps (&tmp
, "vfs", filename
);
1084 while ((i
= mc_read (fdin
, buffer
, sizeof (buffer
))) > 0) {
1085 if (write (fdout
, buffer
, i
) != i
)
1090 i
= mc_close (fdin
);
1094 if (close (fdout
) == -1) {
1099 if (mc_stat (filename
, &mystat
) != -1) {
1100 chmod (tmp
, mystat
.st_mode
);
1114 mc_getlocalcopy (const char *pathname
)
1119 path
= vfs_canon_and_translate (pathname
);
1121 struct vfs_class
*vfs
= vfs_get_class (path
);
1123 result
= vfs
->getlocalcopy
? (*vfs
->getlocalcopy
)(vfs
, path
) :
1124 mc_def_getlocalcopy (path
);
1127 errno
= ferrno (vfs
);
1133 mc_def_ungetlocalcopy (struct vfs_class
*vfs
, const char *filename
,
1134 const char *local
, int has_changed
)
1136 int fdin
= -1, fdout
= -1, i
;
1143 fdin
= open (local
, O_RDONLY
);
1146 fdout
= mc_open (filename
, O_WRONLY
| O_TRUNC
);
1149 while ((i
= read (fdin
, buffer
, sizeof (buffer
))) > 0) {
1150 if (mc_write (fdout
, buffer
, i
) != i
)
1156 if (close (fdin
) == -1) {
1161 if (mc_close (fdout
) == -1) {
1170 message (D_ERROR
, _("Changes to file lost"), "%s", filename
);
1180 mc_ungetlocalcopy (const char *pathname
, const char *local
, int has_changed
)
1182 int return_value
= 0;
1185 path
= vfs_canon_and_translate (pathname
);
1187 struct vfs_class
*vfs
= vfs_get_class (path
);
1189 return_value
= vfs
->ungetlocalcopy
?
1190 (*vfs
->ungetlocalcopy
)(vfs
, path
, local
, has_changed
) :
1191 mc_def_ungetlocalcopy (vfs
, path
, local
, has_changed
);
1193 return return_value
;
1201 vfs_str_buffer
= g_string_new("");
1202 /* localfs needs to be the first one */
1204 /* fallback value for vfs_get_class() */
1205 localfs_class
= vfs_list
;
1212 #ifdef USE_EXT2FSLIB
1214 #endif /* USE_EXT2FSLIB */
1222 #endif /* WITH_SMBFS */
1225 #endif /* WITH_MCFS */
1226 #endif /* USE_NETCODE */
1234 struct vfs_class
*vfs
;
1238 g_free (current_dir
);
1240 for (vfs
= vfs_list
; vfs
; vfs
= vfs
->next
)
1244 g_slist_free (vfs_openfiles
);
1246 g_string_free (vfs_str_buffer
, TRUE
);
1250 * These ones grab information from the VFS
1251 * and handles them to an upper layer
1254 vfs_fill_names (fill_names_f func
)
1256 struct vfs_class
*vfs
;
1258 for (vfs
=vfs_list
; vfs
; vfs
=vfs
->next
)
1259 if (vfs
->fill_names
)
1260 (*vfs
->fill_names
) (vfs
, func
);
1264 * Returns vfs path corresponding to given url. If passed string is
1265 * not recognized as url, g_strdup(url) is returned.
1268 static const struct {
1271 const char *substitute
;
1272 } url_table
[] = { {"ftp://", 6, "/#ftp:"},
1273 {"mc://", 5, "/#mc:"},
1274 {"smb://", 6, "/#smb:"},
1275 {"sh://", 5, "/#sh:"},
1276 {"ssh://", 6, "/#sh:"},
1281 vfs_translate_url (const char *url
)
1285 for (i
= 0; i
< sizeof (url_table
)/sizeof (url_table
[0]); i
++)
1286 if (strncmp (url
, url_table
[i
].name
, url_table
[i
].name_len
) == 0)
1287 return g_strconcat (url_table
[i
].substitute
, url
+ url_table
[i
].name_len
, (char*) NULL
);
1289 return g_strdup (url
);
1292 int vfs_file_is_local (const char *filename
)
1294 return vfs_file_class_flags (filename
) & VFSF_LOCAL
;