1 /* Virtual File System switch code
2 Copyright (C) 1995 The Free Software Foundation
4 Written by: 1995 Miguel de Icaza
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public License
12 as published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 /* Warning: funtions like extfs_lstat() have right to destroy any
25 * strings you pass to them. This is acutally ok as you g_strdup what
26 * you are passing to them, anyway; still, beware. */
28 /* Namespace: exports *many* functions with vfs_ prefix; exports
29 parse_ls_lga and friends which do not have that prefix. */
38 #include <stdlib.h> /* For atol() */
42 #include <sys/types.h>
48 #include "../src/dir.h"
49 #include "../src/main.h"
50 #ifndef VFS_STANDALONE
51 #include "../src/panel.h"
52 #include "../src/key.h" /* Required for the async alarm handler */
53 #include "../src/layout.h" /* For get_panel_widget and get_other_index */
54 #include "../src/dialog.h"
57 #include "xdirentry.h"
59 #include "extfs.h" /* FIXME: we should not know anything about our modules */
69 extern int get_other_type (void);
71 int vfs_timeout
= 60; /* VFS timeout in seconds */
72 int vfs_flags
= 0; /* Flags */
74 extern int cd_symlinks
; /* Defined in main.c */
76 /* They keep track of the current directory */
77 static vfs
*current_vfs
= &vfs_local_ops
;
78 static char *current_dir
= NULL
;
81 * FIXME: this is broken. It depends on mc not crossing border on month!
83 static int current_mday
;
84 static int current_mon
;
85 static int current_year
;
90 /* FIXME: Open files managed by the vfs layer, should be dynamical */
91 #define MAX_VFS_FILES 100
96 } vfs_file_table
[MAX_VFS_FILES
];
103 /* 0, 1, 2 are reserved file descriptors, while (DIR *) 0 means error */
104 for (i
= 3; i
< MAX_VFS_FILES
; i
++){
105 if (!vfs_file_table
[i
].fs_info
)
109 vfs_die ("No more virtual file handles");
113 /* vfs_local_ops needs to be the first one */
114 static vfs
*vfs_list
= &vfs_local_ops
;
117 vfs_register (vfs
*vfs
)
120 vfs_die("You can not register NULL.");
122 if (vfs
->init
) /* vfs has own initialization function */
123 if (!(*vfs
->init
)(vfs
)) /* but it failed */
126 vfs
->next
= vfs_list
;
133 vfs_type_from_op (char *path
)
138 vfs_die ("vfs_type_from_op got NULL: impossible");
140 for (vfs
= vfs_list
; vfs
!= &vfs_local_ops
; vfs
= vfs
->next
){
142 if ((*vfs
->which
) (vfs
, path
) == -1)
146 if (!strncmp (path
, vfs
->prefix
, strlen (vfs
->prefix
)))
149 return NULL
; /* shut up stupid gcc */
152 /* Strip known vfs suffixes from a filename (possible improvement: strip
153 suffix from last path component).
154 Returns a malloced string which has to be freed. */
156 vfs_strip_suffix_from_filename (const char *filename
)
163 vfs_die("vfs_strip_suffix_from_path got NULL: impossible");
165 p
= g_strdup (filename
);
166 if (!(semi
= strrchr (p
, '#')))
169 for (vfs
= vfs_list
; vfs
!= &vfs_local_ops
; vfs
= vfs
->next
){
171 if ((*vfs
->which
) (vfs
, semi
+ 1) == -1)
173 *semi
= '\0'; /* Found valid suffix */
176 if (!strncmp (semi
+ 1, vfs
->prefix
, strlen (vfs
->prefix
))) {
177 *semi
= '\0'; /* Found valid suffix */
185 path_magic (const char *path
)
189 if (vfs_flags
& FL_ALWAYS_MAGIC
)
192 if (!stat(path
, &buf
))
199 * Splits path '/p1#op/inpath' into inpath,op; returns which vfs it is.
200 * What is left in path is p1. You still want to g_free(path), you DON'T
201 * want to free neither *inpath nor *op
204 vfs_split (char *path
, char **inpath
, char **op
)
211 vfs_die("Can not split NULL");
213 semi
= strrchr (path
, '#');
214 if (!semi
|| !path_magic(path
))
217 slash
= strchr (semi
, PATH_SEP
);
229 if ((ret
= vfs_type_from_op (semi
+1))){
233 *inpath
= slash
? slash
+ 1 : NULL
;
240 ret
= vfs_split (path
, inpath
, op
);
246 vfs_rosplit (char *path
)
252 g_return_val_if_fail(path
, NULL
);
254 semi
= strrchr (path
, '#');
255 if (!semi
|| !path_magic (path
))
258 slash
= strchr (semi
, PATH_SEP
);
263 ret
= vfs_type_from_op (semi
+1);
264 if (!ret
&& (vfs_flags
& FL_NO_LOCALHASH
))
270 ret
= vfs_rosplit (path
);
277 vfs_type (char *path
)
281 vfs
= vfs_rosplit(path
);
284 vfs
= &vfs_local_ops
;
289 static struct vfs_stamping
*stamps
;
292 * Returns the number of seconds remaining to the vfs timeout
294 * FIXME: currently this is set to 10 seconds. We should compute this.
299 return stamps
? 10 : 0;
303 vfs_addstamp (vfs
*v
, vfsid id
, struct vfs_stamping
*parent
)
305 if (v
!= &vfs_local_ops
&& id
!= (vfsid
)-1){
306 struct vfs_stamping
*stamp
;
307 struct vfs_stamping
*last_stamp
= NULL
;
309 for (stamp
= stamps
; stamp
!= NULL
; stamp
= stamp
->next
) {
310 if (stamp
->v
== v
&& stamp
->id
== id
){
311 gettimeofday(&(stamp
->time
), NULL
);
316 stamp
= g_new (struct vfs_stamping
, 1);
320 struct vfs_stamping
*st
= stamp
;
322 st
->parent
= g_new (struct vfs_stamping
, 1);
323 *st
->parent
= *parent
;
324 parent
= parent
->parent
;
332 gettimeofday (&(stamp
->time
), NULL
);
337 last_stamp
->next
= stamp
;
339 /* Add first element */
346 vfs_stamp (vfs
*v
, vfsid id
)
348 struct vfs_stamping
*stamp
;
350 for (stamp
= stamps
; stamp
!= NULL
; stamp
= stamp
->next
)
351 if (stamp
->v
== v
&& stamp
->id
== id
){
353 gettimeofday (&(stamp
->time
), NULL
);
354 if (stamp
->parent
!= NULL
)
355 vfs_stamp (stamp
->parent
->v
, stamp
->parent
->id
);
362 vfs_rm_parents (struct vfs_stamping
*stamp
)
364 struct vfs_stamping
*parent
;
367 parent
= stamp
->parent
;
374 vfs_rmstamp (vfs
*v
, vfsid id
, int removeparents
)
376 struct vfs_stamping
*stamp
, *st1
;
378 for (stamp
= stamps
, st1
= NULL
; stamp
!= NULL
; st1
= stamp
, stamp
= stamp
->next
)
379 if (stamp
->v
== v
&& stamp
->id
== id
){
380 if (stamp
->parent
!= NULL
){
382 vfs_rmstamp (stamp
->parent
->v
, stamp
->parent
->id
, 1);
383 vfs_rm_parents (stamp
->parent
);
386 stamps
= stamp
->next
;
388 st1
->next
= stamp
->next
;
399 return vfs
->ferrno
? (*vfs
->ferrno
)(vfs
) : E_UNKNOWN
;
400 /* Hope that error message is obscure enough ;-) */
404 mc_open (const char *filename
, int flags
, ...)
411 char *file
= vfs_canon (filename
);
412 vfs
*vfs
= vfs_type (file
);
414 /* Get the mode flag */ /* FIXME: should look if O_CREAT is present */
415 va_start (ap
, flags
);
416 mode
= va_arg (ap
, int);
424 info
= (*vfs
->open
) (vfs
, file
, flags
, mode
); /* open must be supported */
427 errno
= ferrno (vfs
);
430 handle
= get_bucket ();
431 vfs_file_table
[handle
].fs_info
= info
;
432 vfs_file_table
[handle
].operations
= vfs
;
437 #define vfs_op(handle) vfs_file_table [handle].operations
438 #define vfs_info(handle) vfs_file_table [handle].fs_info
439 #define vfs_free_bucket(handle) vfs_info(handle) = 0;
441 #define MC_OP(name, inarg, callarg, pre, post) \
442 int mc_##name inarg \
448 result = vfs->name ? (*vfs->name)callarg : -1; \
451 errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
455 #define MC_NAMEOP(name, inarg, callarg) \
456 MC_OP (name, inarg, callarg, path = vfs_canon (path); vfs = vfs_type (path);, g_free (path); )
457 #define MC_HANDLEOP(name, inarg, callarg) \
458 MC_OP (name, inarg, callarg, if (handle == -1) return -1; vfs = vfs_op (handle);, )
460 MC_HANDLEOP(read
, (int handle
, char *buffer
, int count
), (vfs_info (handle
), buffer
, count
) )
463 mc_ctl (int handle
, int ctlop
, int arg
)
465 vfs
*vfs
= vfs_op (handle
);
467 return vfs
->ctl
? (*vfs
->ctl
)(vfs_info (handle
), ctlop
, arg
) : 0;
471 mc_setctl (char *path
, int ctlop
, char *arg
)
477 vfs_die("You don't want to pass NULL to mc_setctl.");
479 path
= vfs_canon (path
);
480 vfs
= vfs_type (path
);
481 result
= vfs
->setctl
? (*vfs
->setctl
)(vfs
, path
, ctlop
, arg
) : 0;
487 mc_close (int handle
)
492 if (handle
== -1 || !vfs_info (handle
))
495 vfs
= vfs_op (handle
);
497 return close (handle
);
500 vfs_die ("VFS must support close.\n");
501 result
= (*vfs
->close
)(vfs_info (handle
));
502 vfs_free_bucket (handle
);
504 errno
= ferrno (vfs
);
510 mc_opendir (char *dirname
)
512 int handle
, *handlep
;
516 dirname
= vfs_canon (dirname
);
517 vfs
= vfs_type (dirname
);
519 info
= vfs
->opendir
? (*vfs
->opendir
)(vfs
, dirname
) : NULL
;
522 errno
= vfs
->opendir
? ferrno (vfs
) : E_NOTSUPP
;
525 handle
= get_bucket ();
526 vfs_file_table
[handle
].fs_info
= info
;
527 vfs_file_table
[handle
].operations
= vfs
;
529 handlep
= g_new (int, 1);
531 return (DIR *) handlep
;
534 /* This should strip the non needed part of a path name */
535 #define vfs_name(x) x
538 mc_seekdir (DIR *dirp
, int offset
)
547 handle
= *(int *) dirp
;
548 vfs
= vfs_op (handle
);
550 (*vfs
->seekdir
) (vfs_info (handle
), offset
);
555 #define MC_DIROP(name, type, onerr ) \
556 type mc_##name (DIR *dirp) \
566 handle = *(int *) dirp; \
567 vfs = vfs_op (handle); \
568 result = vfs->name ? (*vfs->name) (vfs_info (handle)) : onerr; \
569 if (result == onerr) \
570 errno = vfs->name ? ferrno(vfs) : E_NOTSUPP; \
574 MC_DIROP (readdir
, struct dirent
*, NULL
)
575 MC_DIROP (telldir
, int, -1)
578 mc_closedir (DIR *dirp
)
580 int handle
= *(int *) dirp
;
581 vfs
*vfs
= vfs_op (handle
);
584 result
= vfs
->closedir
? (*vfs
->closedir
)(vfs_info (handle
)) : -1;
585 vfs_free_bucket (handle
);
590 int mc_stat (char *path
, struct stat
*buf
) {
594 path
= vfs_canon (path
); vfs
= vfs_type (path
);
595 result
= vfs
->stat
? (*vfs
->stat
) (vfs
, vfs_name (path
), buf
) : -1;
598 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
602 int mc_lstat (char *path
, struct stat
*buf
) {
606 path
= vfs_canon (path
); vfs
= vfs_type (path
);
607 result
= vfs
->lstat
? (*vfs
->lstat
) (vfs
, vfs_name (path
), buf
) : -1;
610 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
614 int mc_fstat (int handle
, struct stat
*buf
) {
620 vfs
= vfs_op (handle
);
621 result
= vfs
->fstat
? (*vfs
->fstat
) (vfs_info (handle
), buf
) : -1;
623 errno
= vfs
->name
? ferrno (vfs
) : E_NOTSUPP
;
628 * You must g_strdup whatever this function returns, static buffers are in use
635 struct stat my_stat
, my_stat2
;
637 if (!vfs_rosplit (current_dir
)){
638 p
= g_get_current_dir ();
639 if (!p
) /* One of the directories in the path is not readable */
642 /* Otherwise check if it is O.K. to use the current_dir */
643 mc_stat (p
, &my_stat
);
644 mc_stat (current_dir
, &my_stat2
);
645 if (my_stat
.st_ino
!= my_stat2
.st_ino
||
646 my_stat
.st_dev
!= my_stat2
.st_dev
||
648 g_free (current_dir
);
651 } /* Otherwise we return current_dir below */
657 mc_get_current_wd (char *buffer
, int size
)
659 char *cwd
= mc_return_cwd();
661 strncpy (buffer
, cwd
, size
);
665 MC_NAMEOP (chmod
, (char *path
, int mode
), (vfs
, vfs_name (path
), mode
))
666 MC_NAMEOP (chown
, (char *path
, int owner
, int group
), (vfs
, vfs_name (path
), owner
, group
))
667 MC_NAMEOP (utime
, (char *path
, struct utimbuf
*times
), (vfs
, vfs_name (path
), times
))
668 MC_NAMEOP (readlink
, (char *path
, char *buf
, int bufsiz
), (vfs
, vfs_name (path
), buf
, bufsiz
))
669 MC_NAMEOP (unlink
, (char *path
), (vfs
, vfs_name (path
)))
670 MC_NAMEOP (symlink
, (char *name1
, char *path
), (vfs
, vfs_name (name1
), vfs_name (path
)))
672 #define MC_RENAMEOP(name) \
673 int mc_##name (char *name1, char *name2) \
678 name1 = vfs_canon (name1); \
679 vfs = vfs_type (name1); \
680 name2 = vfs_canon (name2); \
681 if (vfs != vfs_type (name2)){ \
688 result = vfs->name ? (*vfs->name)(vfs, vfs_name (name1), vfs_name (name2)) : -1; \
692 errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
699 MC_HANDLEOP (write
, (int handle
, char *buf
, int nbyte
), (vfs_info (handle
), buf
, nbyte
))
701 off_t
mc_lseek (int fd
, off_t offset
, int whence
)
710 result
= vfs
->lseek
? (*vfs
->lseek
)(vfs_info (fd
), offset
, whence
) : -1;
712 errno
= vfs
->lseek
? ferrno (vfs
) : E_NOTSUPP
;
717 * remove //, /./ and /../, local should point to big enough buffer
720 #define ISSLASH(a) (!a || (a == '/'))
723 vfs_canon (const char *path
)
726 vfs_die("Cannot canonicalize NULL");
728 /* Tilde expansion */
730 char *local
, *result
;
732 local
= tilde_expand (path
);
734 result
= vfs_canon (local
);
740 /* Relative to current directory */
741 if (*path
!= PATH_SEP
){
742 char *local
, *result
;
744 local
= concat_dir_and_file (current_dir
, path
);
746 result
= vfs_canon (local
);
752 * So we have path of following form:
753 * /p1/p2#op/.././././p3#op/p4. Good luck.
756 char *result
= g_strdup (path
);
758 mad_check("(pre-canonicalize)", 0);
759 canonicalize_pathname (result
);
760 mad_check("(post-canonicalize)", 0);
767 vfs_ncs_getid (vfs
*nvfs
, char *dir
, struct vfs_stamping
**par
)
771 dir
= concat_dir_and_file (dir
, "");
773 nvfsid
= (*nvfs
->getid
)(nvfs
, dir
, par
);
780 is_parent (vfs
* nvfs
, vfsid nvfsid
, struct vfs_stamping
*parent
)
782 struct vfs_stamping
*stamp
;
784 for (stamp
= parent
; stamp
; stamp
= stamp
->parent
)
785 if (stamp
->v
== nvfs
&& stamp
->id
== nvfsid
)
788 return (stamp
? 1 : 0);
792 vfs_add_noncurrent_stamps (vfs
* oldvfs
, vfsid oldvfsid
, struct vfs_stamping
*parent
)
794 #ifndef VFS_STANDALONE
795 vfs
*nvfs
, *n2vfs
, *n3vfs
;
796 vfsid nvfsid
, n2vfsid
, n3vfsid
;
797 struct vfs_stamping
*par
, *stamp
;
800 /* FIXME: As soon as we convert to multiple panels, this stuff
801 has to change. It works like this: We do not time out the
802 vfs's which are current in any panel and on the other
803 side we add the old directory with all its parents which
804 are not in any panel (if we find such one, we stop adding
805 parents to the time-outing structure. */
807 /* There are three directories we have to take care of: current_dir,
808 cpanel->cwd and opanel->cwd. Athough most of the time either
809 current_dir and cpanel->cwd or current_dir and opanel->cwd are the
810 same, it's possible that all three are different -- Norbert */
815 nvfs
= vfs_type (current_dir
);
816 nvfsid
= vfs_ncs_getid (nvfs
, current_dir
, &par
);
817 vfs_rmstamp (nvfs
, nvfsid
, 1);
819 f
= is_parent (oldvfs
, oldvfsid
, par
);
820 vfs_rm_parents (par
);
821 if ((nvfs
== oldvfs
&& nvfsid
== oldvfsid
) || oldvfsid
== (vfsid
*)-1 || f
){
825 if (get_current_type () == view_listing
){
826 n2vfs
= vfs_type (cpanel
->cwd
);
827 n2vfsid
= vfs_ncs_getid (n2vfs
, cpanel
->cwd
, &par
);
828 f
= is_parent (oldvfs
, oldvfsid
, par
);
829 vfs_rm_parents (par
);
830 if ((n2vfs
== oldvfs
&& n2vfsid
== oldvfsid
) || f
)
834 n2vfsid
= (vfs
*) -1;
837 if (get_other_type () == view_listing
){
838 n3vfs
= vfs_type (opanel
->cwd
);
839 n3vfsid
= vfs_ncs_getid (n3vfs
, opanel
->cwd
, &par
);
840 f
= is_parent (oldvfs
, oldvfsid
, par
);
841 vfs_rm_parents (par
);
842 if ((n3vfs
== oldvfs
&& n3vfsid
== oldvfsid
) || f
)
849 if ((*oldvfs
->nothingisopen
) (oldvfsid
)){
850 if (oldvfs
== &vfs_extfs_ops
&& ((extfs_archive
*) oldvfsid
)->name
== 0){
851 /* Free the resources immediatly when we leave a mtools fs
852 ('cd a:') instead of waiting for the vfs-timeout */
853 (oldvfs
->free
) (oldvfsid
);
855 vfs_addstamp (oldvfs
, oldvfsid
, parent
);
856 for (stamp
= parent
; stamp
!= NULL
; stamp
= stamp
->parent
){
857 if ((stamp
->v
== nvfs
&& stamp
->id
== nvfsid
) ||
858 (stamp
->v
== n2vfs
&& stamp
->id
== n2vfsid
) ||
859 (stamp
->v
== n3vfs
&& stamp
->id
== n3vfsid
) ||
860 stamp
->id
== (vfsid
) - 1 ||
861 !(*stamp
->v
->nothingisopen
) (stamp
->id
))
863 if (stamp
->v
== &vfs_extfs_ops
&& ((extfs_archive
*) stamp
->id
)->name
== 0){
864 (stamp
->v
->free
) (stamp
->id
);
865 vfs_rmstamp (stamp
->v
, stamp
->id
, 0);
867 vfs_addstamp (stamp
->v
, stamp
->id
, stamp
->parent
);
871 vfs_addstamp (oldvfs
, oldvfsid
, parent
);
876 vfs_stamp_path (char *path
)
880 struct vfs_stamping
*par
, *stamp
;
882 vfs
= vfs_type (path
);
883 id
= vfs_ncs_getid (vfs
, path
, &par
);
884 vfs_addstamp (vfs
, id
, par
);
886 for (stamp
= par
; stamp
!= NULL
; stamp
= stamp
->parent
)
887 vfs_addstamp (stamp
->v
, stamp
->id
, stamp
->parent
);
888 vfs_rm_parents (par
);
891 #ifndef VFS_STANDALONE
893 vfs_add_current_stamps (void)
895 vfs_stamp_path (current_dir
);
898 if (get_current_type () == view_listing
)
899 vfs_stamp_path (cpanel
->cwd
);
903 if (get_other_type () == view_listing
)
904 vfs_stamp_path (opanel
->cwd
);
909 /* This function is really broken */
911 mc_chdir (char *path
)
918 struct vfs_stamping
*parent
;
920 a
= current_dir
; /* Save a copy for case of failure */
921 current_dir
= vfs_canon (path
);
922 current_vfs
= vfs_type (current_dir
);
923 b
= g_strdup (current_dir
);
924 result
= (*current_vfs
->chdir
) ? (*current_vfs
->chdir
)(current_vfs
, vfs_name (b
)) : -1;
927 errno
= ferrno (current_vfs
);
928 g_free (current_dir
);
929 current_vfs
= vfs_type (a
);
932 oldvfs
= vfs_type (a
);
933 oldvfsid
= vfs_ncs_getid (oldvfs
, a
, &parent
);
935 vfs_add_noncurrent_stamps (oldvfs
, oldvfsid
, parent
);
936 vfs_rm_parents (parent
);
940 p
= strchr (current_dir
, 0) - 1;
941 if (*p
== PATH_SEP
&& p
> current_dir
)
942 *p
= 0; /* Sometimes we assume no trailing slash on cwd */
948 vfs_current_is_local (void)
950 return current_vfs
== &vfs_local_ops
;
954 /* External world should not do differences between VFS-s */
956 vfs_current_is_extfs (void)
958 return current_vfs
== &vfs_extfs_ops
;
962 vfs_current_is_tarfs (void)
964 return current_vfs
== &vfs_tarfs_ops
;
968 vfs_current_is_cpiofs (void)
970 return current_vfs
== &vfs_cpiofs_ops
;
975 vfs_file_is_local (const char *file
)
977 char *filename
= vfs_canon (file
);
978 vfs
*vfs
= vfs_type (filename
);
981 return vfs
== &vfs_local_ops
;
985 vfs_file_is_ftp (char *filename
)
990 filename
= vfs_canon (filename
);
991 vfs
= vfs_type (filename
);
993 return vfs
== &vfs_ftpfs_ops
;
1000 vfs_file_is_smb (char *filename
)
1006 filename
= vfs_canon (filename
);
1007 vfs
= vfs_type (filename
);
1009 return vfs
== &vfs_smbfs_ops
;
1010 #endif /* USE_NETCODE */
1011 #endif /* WITH_SMBFS */
1015 char *vfs_get_current_dir (void)
1020 static void vfs_setup_wd (void)
1022 current_dir
= g_strdup (PATH_SEP_STR
);
1023 if (!(vfs_flags
& FL_NO_CWDSETUP
))
1026 if (strlen(current_dir
)>MC_MAXPATHLEN
-2)
1027 vfs_die ("Current dir too long.\n");
1030 MC_NAMEOP (mkdir
, (char *path
, mode_t mode
), (vfs
, vfs_name (path
), mode
))
1031 MC_NAMEOP (rmdir
, (char *path
), (vfs
, vfs_name (path
)))
1032 MC_NAMEOP (mknod
, (char *path
, int mode
, int dev
), (vfs
, vfs_name (path
), mode
, dev
))
1035 static struct mc_mmapping
{
1039 struct mc_mmapping
*next
;
1040 } *mc_mmaparray
= NULL
;
1043 mc_mmap (caddr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
1047 struct mc_mmapping
*mcm
;
1050 return (caddr_t
) -1;
1053 result
= vfs
->mmap
? (*vfs
->mmap
)(vfs
, addr
, len
, prot
, flags
, vfs_info (fd
), offset
) : (caddr_t
)-1;
1054 if (result
== (caddr_t
)-1){
1055 errno
= ferrno (vfs
);
1058 mcm
=g_new (struct mc_mmapping
, 1);
1060 mcm
->vfs_info
= vfs_info (fd
);
1062 mcm
->next
= mc_mmaparray
;
1068 mc_munmap (caddr_t addr
, size_t len
)
1070 struct mc_mmapping
*mcm
, *mcm2
= NULL
;
1072 for (mcm
= mc_mmaparray
; mcm
!= NULL
; mcm2
= mcm
, mcm
= mcm
->next
){
1073 if (mcm
->addr
== addr
){
1075 mc_mmaparray
= mcm
->next
;
1077 mcm2
->next
= mcm
->next
;
1078 if (mcm
->vfs
->munmap
)
1079 (*mcm
->vfs
->munmap
)(mcm
->vfs
, addr
, len
, mcm
->vfs_info
);
1090 mc_def_getlocalcopy (vfs
*vfs
, char *filename
)
1097 fdin
= mc_open (filename
, O_RDONLY
);
1101 fdout
= mc_mkstemps (&tmp
, "mclocalcopy", NULL
);
1104 while ((i
= mc_read (fdin
, buffer
, sizeof (buffer
))) > 0){
1105 if (write (fdout
, buffer
, i
) != i
)
1110 i
= mc_close (fdin
);
1114 if (close (fdout
)==-1)
1117 if (mc_stat (filename
, &mystat
) != -1){
1118 chmod (tmp
, mystat
.st_mode
);
1123 if (fdout
) close(fdout
);
1124 if (fdin
) mc_close (fdin
);
1130 mc_getlocalcopy (const char *pathname
)
1133 char *path
= vfs_canon (pathname
);
1134 vfs
*vfs
= vfs_type (path
);
1136 result
= vfs
->getlocalcopy
? (*vfs
->getlocalcopy
)(vfs
, vfs_name (path
)) :
1137 mc_def_getlocalcopy (vfs
, vfs_name (path
));
1140 errno
= ferrno (vfs
);
1145 mc_def_ungetlocalcopy (vfs
*vfs
, char *filename
, char *local
, int has_changed
)
1146 { /* Dijkstra probably hates me... But he should teach me how to do this nicely. */
1147 int fdin
= -1, fdout
= -1, i
;
1151 fdin
= open (local
, O_RDONLY
);
1154 fdout
= mc_open (filename
, O_WRONLY
| O_TRUNC
);
1157 while ((i
= read (fdin
, buffer
, sizeof (buffer
))) > 0){
1158 if (mc_write (fdout
, buffer
, i
) != i
)
1164 if (close (fdin
)==-1) {
1169 if (mc_close (fdout
)==-1) {
1179 message_1s (1, _("Changes to file lost"), filename
);
1180 if (fdout
!=-1) mc_close(fdout
);
1181 if (fdin
!=-1) close(fdin
);
1188 mc_ungetlocalcopy (const char *pathname
, char *local
, int has_changed
)
1190 int return_value
= 0;
1191 char *path
= vfs_canon (pathname
);
1192 vfs
*vfs
= vfs_type (path
);
1194 return_value
= vfs
->ungetlocalcopy
?
1195 (*vfs
->ungetlocalcopy
)(vfs
, vfs_name (path
), local
, has_changed
) :
1196 mc_def_ungetlocalcopy (vfs
, vfs_name (path
), local
, has_changed
);
1198 return return_value
;
1202 * Hmm, as timeout is minute or so, do we need to care about usecs?
1205 timeoutcmp (struct timeval
*t1
, struct timeval
*t2
)
1207 return ((t1
->tv_sec
< t2
->tv_sec
)
1208 || ((t1
->tv_sec
== t2
->tv_sec
) && (t1
->tv_usec
<= t2
->tv_usec
)));
1211 /* This is called from timeout handler with now = 0, or can be called
1212 with now = 1 to force freeing all filesystems that are not in use */
1215 vfs_expire (int now
)
1217 static int locked
= 0;
1218 struct timeval time
;
1219 struct vfs_stamping
*stamp
, *st
;
1221 /* Avoid recursive invocation, e.g. when one of the free functions
1227 gettimeofday (&time
, NULL
);
1228 time
.tv_sec
-= vfs_timeout
;
1230 for (stamp
= stamps
; stamp
!= NULL
;){
1231 if (now
|| (timeoutcmp (&stamp
->time
, &time
))){
1233 (*stamp
->v
->free
) (stamp
->id
);
1234 vfs_rmstamp (stamp
->v
, stamp
->id
, 0);
1237 stamp
= stamp
->next
;
1243 vfs_timeout_handler (void)
1251 time_t current_time
;
1254 memset (vfs_file_table
, 0, sizeof (vfs_file_table
));
1255 current_time
= time (NULL
);
1256 t
= localtime (¤t_time
);
1257 current_mday
= t
->tm_mday
;
1258 current_mon
= t
->tm_mon
;
1259 current_year
= t
->tm_year
;
1261 /* We do not want to register vfs_local_ops */
1265 vfs_register (&vfs_ftpfs_ops
);
1267 vfs_register (&vfs_smbfs_ops
);
1269 vfs_register (&vfs_mcfs_ops
);
1272 vfs_register (&vfs_fish_ops
);
1273 vfs_register (&vfs_extfs_ops
);
1274 vfs_register (&vfs_sfs_ops
);
1275 vfs_register (&vfs_tarfs_ops
);
1276 vfs_register (&vfs_cpiofs_ops
);
1278 #ifdef USE_EXT2FSLIB
1279 vfs_register (&vfs_undelfs_ops
);
1286 vfs_free_resources (char *path
)
1290 struct vfs_stamping
*parent
;
1292 vfs
= vfs_type (path
);
1293 vid
= vfs_ncs_getid (vfs
, path
, &parent
);
1294 if (vid
!= (vfsid
) -1)
1296 vfs_rm_parents (parent
);
1300 /* Shutdown a vfs given a path name */
1302 vfs_shut_path (char *p
)
1305 struct vfs_stamping
*par
;
1307 the_vfs
= vfs_type (p
);
1308 vfs_ncs_getid (the_vfs
, p
, &par
);
1309 (*par
->v
->free
)(par
->id
);
1310 vfs_rm_parents (par
);
1317 struct vfs_stamping
*stamp
, *st
;
1320 for (stamp
= stamps
, stamps
= 0; stamp
!= NULL
;){
1321 (*stamp
->v
->free
)(stamp
->id
);
1328 vfs_rmstamp (stamps
->v
, stamps
->id
, 1);
1331 g_free (current_dir
);
1333 for (vfs
=vfs_list
; vfs
; vfs
=vfs
->next
)
1339 * These ones grab information from the VFS
1340 * and handles them to an upper layer
1343 vfs_fill_names (void (*func
)(char *))
1347 for (vfs
=vfs_list
; vfs
; vfs
=vfs
->next
)
1348 if (vfs
->fill_names
)
1349 (*vfs
->fill_names
) (vfs
, func
);
1352 /* Following stuff (parse_ls_lga) is used by ftpfs and extfs */
1355 static char *columns
[MAXCOLS
]; /* Points to the string in column n */
1356 static int column_ptr
[MAXCOLS
]; /* Index from 0 to the starting positions of the columns */
1359 vfs_split_text (char *p
)
1364 memset (columns
, 0, sizeof (columns
));
1366 for (numcols
= 0; *p
&& numcols
< MAXCOLS
; numcols
++){
1367 while (*p
== ' ' || *p
== '\r' || *p
== '\n'){
1371 columns
[numcols
] = p
;
1372 column_ptr
[numcols
] = p
- original
;
1373 while (*p
&& *p
!= ' ' && *p
!= '\r' && *p
!= '\n')
1382 if (!columns
[idx
] || columns
[idx
][0] < '0' || columns
[idx
][0] > '9')
1388 is_dos_date(char *str
)
1390 if (strlen(str
) == 8 && str
[2] == str
[5] && strchr("\\-/", (int)str
[2]) != NULL
)
1397 is_week (char *str
, struct tm
*tim
)
1399 char *week
= "SunMonTueWedThuFriSat";
1402 if((pos
=strstr(week
, str
)) != NULL
){
1404 tim
->tm_wday
= (pos
- week
)/3;
1411 is_month (char *str
, struct tm
*tim
)
1413 char *month
= "JanFebMarAprMayJunJulAugSepOctNovDec";
1416 if((pos
=strstr(month
, str
)) != NULL
){
1418 tim
->tm_mon
= (pos
- month
)/3;
1425 is_time (char *str
, struct tm
*tim
)
1429 if ((p
=strchr(str
, ':')) && (p2
=strrchr(str
, ':'))) {
1431 if (sscanf (str
, "%2d:%2d:%2d", &tim
->tm_hour
, &tim
->tm_min
, &tim
->tm_sec
) != 3)
1435 if (sscanf (str
, "%2d:%2d", &tim
->tm_hour
, &tim
->tm_min
) != 2)
1445 static int is_year(char *str
, struct tm
*tim
)
1449 if (strchr(str
,':'))
1455 if (sscanf(str
, "%ld", &year
) != 1)
1458 if (year
< 1900 || year
> 3000)
1461 tim
->tm_year
= (int) (year
- 1900);
1467 * FIXME: this is broken. Consider following entry:
1468 * -rwx------ 1 root root 1 Aug 31 10:04 2904 1234
1469 * where "2904 1234" is filename. Well, this code decodes it as year :-(.
1473 vfs_parse_filetype (char c
)
1476 case 'd': return S_IFDIR
;
1477 case 'b': return S_IFBLK
;
1478 case 'c': return S_IFCHR
;
1479 case 'l': return S_IFLNK
;
1480 case 's': /* Socket */
1484 /* If not supported, we fall through to IFIFO */
1487 case 'D': /* Solaris door */
1493 case 'p': return S_IFIFO
;
1494 case 'm': case 'n': /* Don't know what these are :-) */
1495 case '-': case '?': return S_IFREG
;
1500 int vfs_parse_filemode (const char *p
)
1501 { /* converts rw-rw-rw- into 0666 */
1504 case 'r': res
|= 0400; break;
1509 case 'w': res
|= 0200; break;
1514 case 'x': res
|= 0100; break;
1515 case 's': res
|= 0100 | S_ISUID
; break;
1516 case 'S': res
|= S_ISUID
; break;
1521 case 'r': res
|= 0040; break;
1526 case 'w': res
|= 0020; break;
1531 case 'x': res
|= 0010; break;
1532 case 's': res
|= 0010 | S_ISGID
; break;
1533 case 'l': /* Solaris produces these */
1534 case 'S': res
|= S_ISGID
; break;
1539 case 'r': res
|= 0004; break;
1544 case 'w': res
|= 0002; break;
1549 case 'x': res
|= 0001; break;
1550 case 't': res
|= 0001 | S_ISVTX
; break;
1551 case 'T': res
|= S_ISVTX
; break;
1558 int vfs_parse_filedate(int idx
, time_t *t
)
1559 { /* This thing parses from idx in columns[] array */
1566 /* Let's setup default time values */
1567 tim
.tm_year
= current_year
;
1568 tim
.tm_mon
= current_mon
;
1569 tim
.tm_mday
= current_mday
;
1573 tim
.tm_isdst
= -1; /* Let mktime() try to guess correct dst offset */
1575 p
= columns
[idx
++];
1577 /* We eat weekday name in case of extfs */
1578 if(is_week(p
, &tim
))
1579 p
= columns
[idx
++];
1582 if(is_month(p
, &tim
)){
1583 /* And we expect, it followed by day number */
1585 tim
.tm_mday
= (int)atol (columns
[idx
++]);
1587 return 0; /* No day */
1590 /* We usually expect:
1593 But in case of extfs we allow these date formats:
1596 Wek Mon DD hh:mm:ss YYYY
1598 where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
1599 YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
1601 /* Here just this special case with MM-DD-YY */
1602 if (is_dos_date(p
)){
1605 if(sscanf(p
, "%2d-%2d-%2d", &d
[0], &d
[1], &d
[2]) == 3){
1606 /* We expect to get:
1612 /* Hmm... maybe, next time :)*/
1614 /* At last, MM-DD-YY */
1615 d
[0]--; /* Months are zerobased */
1625 return 0; /* sscanf failed */
1627 return 0; /* unsupported format */
1630 /* Here we expect to find time and/or year */
1633 if(is_time(columns
[idx
], &tim
) || (got_year
= is_year(columns
[idx
], &tim
))) {
1636 /* This is a special case for ctime() or Mon DD YYYY hh:mm */
1637 if(is_num (idx
) && (columns
[idx
+1][0]) &&
1638 ((got_year
|= is_year(columns
[idx
], &tim
)) || is_time(columns
[idx
], &tim
)))
1639 idx
++; /* time & year or reverse */
1640 } /* only time or date */
1643 return 0; /* Nor time or date */
1646 * If the date is less than 6 months in the past, it is shown without year
1647 * other dates in the past or future are shown with year but without time
1648 * This does not check for years before 1900 ... I don't know, how
1649 * to represent them at all
1652 current_mon
< 6 && current_mon
< tim
.tm_mon
&&
1653 tim
.tm_mon
- current_mon
>= 6)
1657 if ((*t
= mktime(&tim
)) < 0)
1663 vfs_parse_ls_lga (const char *p
, struct stat
*s
, char **filename
, char **linkname
)
1665 int idx
, idx2
, num_cols
;
1667 char *p_copy
= NULL
;
1669 const char *line
= p
;
1671 if (strncmp (p
, "total", 5) == 0)
1674 if ((i
= vfs_parse_filetype(*(p
++))) == -1)
1678 if (*p
== ' ') /* Notwell 4 */
1681 if (strlen (p
) <= 8 || p
[8] != ']')
1683 /* Should parse here the Notwell permissions :) */
1684 if (S_ISDIR (s
->st_mode
))
1685 s
->st_mode
|= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IXUSR
| S_IXGRP
| S_IXOTH
);
1687 s
->st_mode
|= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
);
1690 if ((i
= vfs_parse_filemode(p
)) == -1)
1695 /* This is for an extra ACL attribute (HP-UX) */
1700 p_copy
= g_strdup(p
);
1701 num_cols
= vfs_split_text (p_copy
);
1703 s
->st_nlink
= atol (columns
[0]);
1704 if (s
->st_nlink
<= 0)
1708 s
->st_uid
= finduid (columns
[1]);
1710 s
->st_uid
= (uid_t
) atol (columns
[1]);
1712 /* Mhm, the ls -lg did not produce a group field */
1713 for (idx
= 3; idx
<= 5; idx
++)
1714 if (is_month(columns
[idx
], NULL
) || is_week(columns
[idx
], NULL
) || is_dos_date(columns
[idx
]))
1717 if (idx
== 6 || (idx
== 5 && !S_ISCHR (s
->st_mode
) && !S_ISBLK (s
->st_mode
)))
1720 /* We don't have gid */
1721 if (idx
== 3 || (idx
== 4 && (S_ISCHR(s
->st_mode
) || S_ISBLK (s
->st_mode
))))
1724 /* We have gid field */
1726 s
->st_gid
= (gid_t
) atol (columns
[2]);
1728 s
->st_gid
= findgid (columns
[2]);
1732 /* This is device */
1733 if (S_ISCHR (s
->st_mode
) || S_ISBLK (s
->st_mode
)){
1736 if (!is_num (idx2
) || sscanf(columns
[idx2
], " %d,", &maj
) != 1)
1739 if (!is_num (++idx2
) || sscanf(columns
[idx2
], " %d", &min
) != 1)
1743 s
->st_rdev
= ((maj
& 0xff) << 8) | (min
& 0xffff00ff);
1748 /* Common file size */
1752 s
->st_size
= (size_t) atol (columns
[idx2
]);
1758 idx
= vfs_parse_filedate(idx
, &s
->st_mtime
);
1761 /* Use resulting time value */
1762 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
1764 /* These variables must be initialized by vfs_s_new_inode () */
1768 #ifdef HAVE_ST_BLKSIZE
1769 s
->st_blksize
= 512;
1771 #ifdef HAVE_ST_BLOCKS
1772 s
->st_blocks
= (s
->st_size
+ 511) / 512;
1775 for (i
= idx
+ 1, idx2
= 0; i
< num_cols
; i
++ )
1776 if (strcmp (columns
[i
], "->") == 0){
1781 if (((S_ISLNK (s
->st_mode
) ||
1782 (num_cols
== idx
+ 3 && s
->st_nlink
> 1))) /* Maybe a hardlink? (in extfs) */
1786 *filename
= g_strndup (p
+ column_ptr
[idx
], column_ptr
[idx2
] - column_ptr
[idx
] - 1);
1789 t
= g_strdup (p
+ column_ptr
[idx2
+1]);
1793 /* Extract the filename from the string copy, not from the columns
1794 * this way we have a chance of entering hidden directories like ". ."
1798 *filename = g_strdup (columns [idx++]);
1801 t
= g_strdup (p
+ column_ptr
[idx
]);
1810 if ((--p
> 0) && (t
[p
] == '\r' || t
[p
] == '\n'))
1812 if ((--p
> 0) && (t
[p
] == '\r' || t
[p
] == '\n'))
1821 static int errorcount
= 0;
1823 if (++errorcount
< 5) {
1824 message_1s (1, _("Could not parse:"), p_copy
? p_copy
: line
);
1825 } else if (errorcount
== 5)
1826 message_1s (1, _("More parsing errors will be ignored."), _("(sorry)"));
1837 message_1s (1, _("Internal error:"), m
);
1842 vfs_print_stats (char *fs_name
, char *action
, char *file_name
, int have
, int need
)
1844 static char *i18n_percent_transf_format
= NULL
, *i18n_transf_format
= NULL
;
1846 if (i18n_percent_transf_format
== NULL
) {
1847 i18n_percent_transf_format
= _("%s: %s: %s %3d%% (%ld bytes transfered)");
1848 i18n_transf_format
= _("%s: %s: %s %ld bytes transfered");
1852 print_vfs_message (i18n_percent_transf_format
,
1853 fs_name
, action
, file_name
, have
*100/need
, have
);
1855 print_vfs_message (i18n_transf_format
,
1856 fs_name
, action
, file_name
, have
);
1859 #ifndef VFS_STANDALONE
1861 vfs_get_password (char *msg
)
1863 return (char *) input_dialog (msg
, _("Password:"), "");
1868 * Returns vfs path corresponding to given url. If passed string is
1869 * not recognized as url, g_strdup(url) is returned.
1872 vfs_translate_url (char *url
)
1874 if (strncmp (url
, "ftp://", 6) == 0)
1875 return g_strconcat ("/#ftp:", url
+ 6, NULL
);
1876 else if (strncmp (url
, "a:", 2) == 0)
1877 return g_strdup ("/#a");
1879 return g_strdup (url
);