2 * \brief Source: directory cache support
4 * So that you do not have copy of this in each and every filesystem.
6 * Very loosely based on tar.c from midnight and archives.[ch] from
7 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
9 * Unfortunately, I was unable to keep all filesystems
10 * uniform. tar-like filesystems use tree structure where each
11 * directory has pointers to its subdirectories. We can do this
12 * because we have full information about our archive.
14 * At ftp-like filesystems, situation is a little bit different. When
15 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
16 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
17 * listed. That means that we do not have complete information, and if
18 * /usr is symlink to /4, we will not know. Also we have to time out
19 * entries and things would get messy with tree-like approach. So we
20 * do different trick: root directory is completely special and
21 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
22 * and we'll try to use custom find_entry function.
24 * \author Pavel Machek <pavel@ucw.cz>, distribute under LGPL.
27 * \warning Paths here do _not_ begin with '/', so root directory of
28 * archive/site is simply "".
34 #include <fcntl.h> /* include fcntl.h -> sys/fcntl.h only */
35 /* includes fcntl.h see IEEE Std 1003.1-2008 */
37 #include <sys/time.h> /* gettimeofday() */
39 #include "lib/global.h"
41 #include "lib/tty/tty.h" /* enable/disable interrupt key */
43 #include "src/wtools.h" /* message() */
44 #include "src/main.h" /* print_vfs_message */
49 #include "gc.h" /* vfs_rmstamp */
50 #include "xdirentry.h"
52 #define CALL(x) if (MEDATA->x) MEDATA->x
54 static volatile int total_inodes
= 0, total_entries
= 0;
57 vfs_s_new_inode (struct vfs_class
*me
, struct vfs_s_super
*super
, struct stat
*initstat
)
59 struct vfs_s_inode
*ino
;
61 ino
= g_try_new0 (struct vfs_s_inode
, 1);
69 ino
->st
.st_ino
= MEDATA
->inode_counter
++;
70 ino
->st
.st_dev
= MEDATA
->rdev
;
75 CALL (init_inode
) (me
, ino
);
81 vfs_s_new_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*inode
)
83 struct vfs_s_entry
*entry
;
85 entry
= g_new0 (struct vfs_s_entry
, 1);
89 entry
->name
= g_strdup (name
);
92 entry
->ino
->ent
= entry
;
93 CALL (init_entry
) (me
, entry
);
99 vfs_s_free_inode (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
102 vfs_die ("Don't pass NULL to me");
104 /* ==0 can happen if freshly created entry is deleted */
105 if (ino
->st
.st_nlink
<= 1){
107 vfs_s_free_entry (me
, ino
->subdir
);
110 CALL (free_inode
) (me
, ino
);
111 g_free (ino
->linkname
);
113 unlink (ino
->localname
);
114 g_free(ino
->localname
);
117 ino
->super
->ino_usage
--;
119 } else ino
->st
.st_nlink
--;
123 vfs_s_free_entry (struct vfs_class
*me
, struct vfs_s_entry
*ent
)
125 if (ent
->prevp
){ /* It is possible that we are deleting freshly created entry */
126 *ent
->prevp
= ent
->next
;
128 ent
->next
->prevp
= ent
->prevp
;
135 ent
->ino
->ent
= NULL
;
136 vfs_s_free_inode (me
, ent
->ino
);
145 vfs_s_insert_entry (struct vfs_class
*me
, struct vfs_s_inode
*dir
, struct vfs_s_entry
*ent
)
147 struct vfs_s_entry
**ep
;
151 for (ep
= &dir
->subdir
; *ep
!= NULL
; ep
= &((*ep
)->next
))
158 ent
->ino
->st
.st_nlink
++;
162 vfs_s_default_stat (struct vfs_class
*me
, mode_t mode
)
164 static struct stat st
;
169 myumask
= umask (022);
177 st
.st_uid
= getuid ();
178 st
.st_gid
= getgid ();
180 st
.st_mtime
= st
.st_atime
= st
.st_ctime
= time (NULL
);
186 vfs_s_generate_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*parent
, mode_t mode
)
188 struct vfs_s_inode
*inode
;
191 st
= vfs_s_default_stat (me
, mode
);
192 inode
= vfs_s_new_inode (me
, parent
->super
, st
);
194 return vfs_s_new_entry (me
, name
, inode
);
197 /* We were asked to create entries automagically */
198 static struct vfs_s_entry
*
199 vfs_s_automake (struct vfs_class
*me
, struct vfs_s_inode
*dir
, char *path
, int flags
)
201 struct vfs_s_entry
*res
;
202 char *sep
= strchr (path
, PATH_SEP
);
206 res
= vfs_s_generate_entry (me
, path
, dir
, flags
& FL_MKDIR
? (0777 | S_IFDIR
) : 0777);
207 vfs_s_insert_entry (me
, dir
, res
);
215 /* If the entry is a symlink, find the entry for its target */
216 static struct vfs_s_entry
*
217 vfs_s_resolve_symlink (struct vfs_class
*me
, struct vfs_s_entry
*entry
,
221 char *fullname
= NULL
;
222 struct vfs_s_entry
*target
;
224 if (follow
== LINK_NO_FOLLOW
)
227 ERRNOR (ELOOP
, NULL
);
229 ERRNOR (ENOENT
, NULL
);
230 if (!S_ISLNK (entry
->ino
->st
.st_mode
))
233 linkname
= entry
->ino
->linkname
;
234 if (linkname
== NULL
)
235 ERRNOR (EFAULT
, NULL
);
237 /* make full path from relative */
238 if (*linkname
!= PATH_SEP
) {
239 char *fullpath
= vfs_s_fullpath (me
, entry
->dir
);
241 fullname
= g_strconcat (fullpath
, "/", linkname
, (char *) NULL
);
248 (MEDATA
->find_entry
) (me
, entry
->dir
->super
->root
, linkname
,
255 * Follow > 0: follow links, serves as loop protect,
256 * == -1: do not follow links
258 static struct vfs_s_entry
*
259 vfs_s_find_entry_tree (struct vfs_class
*me
, struct vfs_s_inode
*root
,
260 const char *a_path
, int follow
, int flags
)
263 struct vfs_s_entry
*ent
= NULL
;
264 char * const pathref
= g_strdup (a_path
);
265 char *path
= pathref
;
267 /* canonicalize as well, but don't remove '../' from path */
268 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
271 while (*path
== PATH_SEP
) /* Strip leading '/' */
279 for (pseg
= 0; path
[pseg
] && path
[pseg
] != PATH_SEP
; pseg
++);
281 for (ent
= root
->subdir
; ent
!= NULL
; ent
= ent
->next
)
282 if (strlen (ent
->name
) == pseg
283 && (!strncmp (ent
->name
, path
, pseg
)))
287 if (!ent
&& (flags
& (FL_MKFILE
| FL_MKDIR
)))
288 ent
= vfs_s_automake (me
, root
, path
, flags
);
294 /* here we must follow leading directories always;
295 only the actual file is optional */
297 vfs_s_resolve_symlink (me
, ent
,
299 PATH_SEP
) ? LINK_FOLLOW
:
311 split_dir_name (struct vfs_class
*me
, char *path
, char **dir
, char **name
, char **save
)
317 s
= strrchr (path
, PATH_SEP
);
321 *dir
= path
+ strlen(path
); /* an empty string */
330 static struct vfs_s_entry
*
331 vfs_s_find_entry_linear (struct vfs_class
*me
, struct vfs_s_inode
*root
,
332 const char *a_path
, int follow
, int flags
)
334 struct vfs_s_entry
*ent
= NULL
;
335 char * const path
= g_strdup (a_path
);
336 struct vfs_s_entry
*retval
= NULL
;
338 if (root
->super
->root
!= root
)
339 vfs_die ("We have to use _real_ root. Always. Sorry.");
341 /* canonicalize as well, but don't remove '../' from path */
342 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
344 if (!(flags
& FL_DIR
)) {
345 char *dirname
, *name
, *save
;
346 struct vfs_s_inode
*ino
;
347 split_dir_name (me
, path
, &dirname
, &name
, &save
);
349 vfs_s_find_inode (me
, root
->super
, dirname
, follow
,
353 retval
= vfs_s_find_entry_tree (me
, ino
, name
, follow
, flags
);
358 for (ent
= root
->subdir
; ent
!= NULL
; ent
= ent
->next
)
359 if (!strcmp (ent
->name
, path
))
362 if (ent
&& (!(MEDATA
->dir_uptodate
) (me
, ent
->ino
))) {
364 print_vfs_message (_("Directory cache expired for %s"), path
);
366 vfs_s_free_entry (me
, ent
);
371 struct vfs_s_inode
*ino
;
374 vfs_s_new_inode (me
, root
->super
,
375 vfs_s_default_stat (me
, S_IFDIR
| 0755));
376 ent
= vfs_s_new_entry (me
, path
, ino
);
377 if ((MEDATA
->dir_load
) (me
, ino
, path
) == -1) {
378 vfs_s_free_entry (me
, ent
);
382 vfs_s_insert_entry (me
, root
, ent
);
384 for (ent
= root
->subdir
; ent
!= NULL
; ent
= ent
->next
)
385 if (!strcmp (ent
->name
, path
))
389 vfs_die ("find_linear: success but directory is not there\n");
392 if (!vfs_s_resolve_symlink (me
, ent
, follow
)) {
402 vfs_s_find_inode (struct vfs_class
*me
, const struct vfs_s_super
*super
,
403 const char *path
, int follow
, int flags
)
405 struct vfs_s_entry
*ent
;
407 if (((MEDATA
->flags
& VFS_S_REMOTE
) == 0) && (*path
== '\0'))
410 ent
= (MEDATA
->find_entry
) (me
, super
->root
, path
, follow
, flags
);
411 return (ent
!= NULL
) ? ent
->ino
: NULL
;
414 /* Ook, these were functions around directory entries / inodes */
415 /* -------------------------------- superblock games -------------------------- */
417 static struct vfs_s_super
*
418 vfs_s_new_super (struct vfs_class
*me
)
420 struct vfs_s_super
*super
;
422 super
= g_new0 (struct vfs_s_super
, 1);
428 vfs_s_insert_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
430 super
->next
= MEDATA
->supers
;
431 super
->prevp
= &MEDATA
->supers
;
433 if (MEDATA
->supers
!= NULL
)
434 MEDATA
->supers
->prevp
= &super
->next
;
435 MEDATA
->supers
= super
;
439 vfs_s_free_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
442 vfs_s_free_inode (me
, super
->root
);
447 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
448 if (super
->ino_usage
)
449 message (D_ERROR
, " Direntry warning ",
450 "Super ino_usage is %d, memory leak",
453 if (super
->want_stale
)
454 message (D_ERROR
, " Direntry warning ", "Super has want_stale set");
458 *super
->prevp
= super
->next
;
460 super
->next
->prevp
= super
->prevp
;
463 CALL (free_archive
) (me
, super
);
464 g_free (super
->name
);
470 * Dissect the path and create corresponding superblock. Note that inname
471 * can be changed and the result may point inside the original string.
474 vfs_s_get_path_mangle (struct vfs_class
*me
, char *inname
,
475 struct vfs_s_super
**archive
, int flags
)
479 const char *archive_name
;
481 struct vfs_s_super
*super
;
484 archive_name
= inname
;
485 vfs_split (inname
, &local
, &op
);
486 retval
= (local
) ? local
: "";
488 if (MEDATA
->archive_check
)
489 if (!(cookie
= MEDATA
->archive_check (me
, archive_name
, op
)))
492 for (super
= MEDATA
->supers
; super
!= NULL
; super
= super
->next
) {
493 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
494 int i
= MEDATA
->archive_same (me
, super
, archive_name
, op
, cookie
);
503 if (flags
& FL_NO_OPEN
)
506 super
= vfs_s_new_super (me
);
507 result
= MEDATA
->open_archive (me
, super
, archive_name
, op
);
509 vfs_s_free_super (me
, super
);
513 vfs_die ("You have to fill name\n");
515 vfs_die ("You have to fill root inode\n");
517 vfs_s_insert_super (me
, super
);
518 vfs_stamp_create (me
, super
);
527 * Dissect the path and create corresponding superblock.
528 * The result should be freed.
531 vfs_s_get_path (struct vfs_class
*me
, const char *inname
,
532 struct vfs_s_super
**archive
, int flags
)
536 buf
= g_strdup (inname
);
537 retval
= g_strdup (vfs_s_get_path_mangle (me
, buf
, archive
, flags
));
543 vfs_s_invalidate (struct vfs_class
*me
, struct vfs_s_super
*super
)
545 if (!super
->want_stale
){
546 vfs_s_free_inode (me
, super
->root
);
547 super
->root
= vfs_s_new_inode (me
, super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
552 vfs_s_fullpath (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
555 ERRNOR (EAGAIN
, NULL
);
557 if (!(MEDATA
->flags
& VFS_S_REMOTE
)) {
560 char *path
= g_strdup (ino
->ent
->name
);
563 if (ino
== ino
->super
->root
)
565 newpath
= g_strconcat (ino
->ent
->name
, "/", path
, (char *) NULL
);
573 if ((!ino
->ent
->dir
) || (!ino
->ent
->dir
->ent
))
574 return g_strdup (ino
->ent
->name
);
576 return g_strconcat (ino
->ent
->dir
->ent
->name
, PATH_SEP_STR
,
577 ino
->ent
->name
, (char *) NULL
);
580 /* Support of archives */
581 /* ------------------------ readdir & friends ----------------------------- */
583 static struct vfs_s_inode
*
584 vfs_s_inode_from_path (struct vfs_class
*me
, const char *name
, int flags
)
586 struct vfs_s_super
*super
;
587 struct vfs_s_inode
*ino
;
590 if (!(q
= vfs_s_get_path (me
, name
, &super
, 0)))
594 vfs_s_find_inode (me
, super
, q
,
595 flags
& FL_FOLLOW
? LINK_FOLLOW
: LINK_NO_FOLLOW
,
598 /* We are asking about / directory of ftp server: assume it exists */
600 vfs_s_find_inode (me
, super
, q
,
601 flags
& FL_FOLLOW
? LINK_FOLLOW
:
603 FL_DIR
| (flags
& ~FL_FOLLOW
));
609 struct vfs_s_entry
*cur
;
610 struct vfs_s_inode
*dir
;
614 vfs_s_opendir (struct vfs_class
*me
, const char *dirname
)
616 struct vfs_s_inode
*dir
;
617 struct dirhandle
*info
;
619 dir
= vfs_s_inode_from_path (me
, dirname
, FL_DIR
| FL_FOLLOW
);
622 if (!S_ISDIR (dir
->st
.st_mode
))
623 ERRNOR (ENOTDIR
, NULL
);
627 if (!dir
->subdir
) /* This can actually happen if we allow empty directories */
628 ERRNOR (EAGAIN
, NULL
);
630 info
= g_new (struct dirhandle
, 1);
631 info
->cur
= dir
->subdir
;
638 vfs_s_readdir(void *data
)
640 static union vfs_dirent dir
;
641 struct dirhandle
*info
= (struct dirhandle
*) data
;
646 if (info
->cur
->name
) {
647 g_strlcpy (dir
.dent
.d_name
, info
->cur
->name
, MC_MAXPATHLEN
);
649 vfs_die("Null in structure-cannot happen");
652 compute_namelen(&dir
.dent
);
653 info
->cur
= info
->cur
->next
;
655 return (void *) &dir
;
659 vfs_s_closedir (void *data
)
661 struct dirhandle
*info
= (struct dirhandle
*) data
;
662 struct vfs_s_inode
*dir
= info
->dir
;
664 vfs_s_free_inode (dir
->super
->me
, dir
);
670 vfs_s_chdir (struct vfs_class
*me
, const char *path
)
673 if (!(data
= vfs_s_opendir (me
, path
)))
675 vfs_s_closedir (data
);
679 /* --------------------------- stat and friends ---------------------------- */
682 vfs_s_internal_stat (struct vfs_class
*me
, const char *path
, struct stat
*buf
, int flag
)
684 struct vfs_s_inode
*ino
;
686 if (!(ino
= vfs_s_inode_from_path (me
, path
, flag
)))
693 vfs_s_stat (struct vfs_class
*me
, const char *path
, struct stat
*buf
)
695 return vfs_s_internal_stat (me
, path
, buf
, FL_FOLLOW
);
699 vfs_s_lstat (struct vfs_class
*me
, const char *path
, struct stat
*buf
)
701 return vfs_s_internal_stat (me
, path
, buf
, FL_NONE
);
705 vfs_s_fstat (void *fh
, struct stat
*buf
)
712 vfs_s_readlink (struct vfs_class
*me
, const char *path
, char *buf
, size_t size
)
714 struct vfs_s_inode
*ino
;
717 ino
= vfs_s_inode_from_path (me
, path
, 0);
721 if (!S_ISLNK (ino
->st
.st_mode
))
724 if (ino
->linkname
== NULL
)
727 len
= strlen (ino
->linkname
);
730 /* readlink() does not append a NUL character to buf */
731 memcpy (buf
, ino
->linkname
, len
);
736 vfs_s_open (struct vfs_class
*me
, const char *file
, int flags
, int mode
)
740 struct vfs_s_super
*super
;
742 struct vfs_s_inode
*ino
;
744 if ((q
= vfs_s_get_path (me
, file
, &super
, 0)) == NULL
)
746 ino
= vfs_s_find_inode (me
, super
, q
, LINK_FOLLOW
, FL_NONE
);
747 if (ino
&& ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))) {
749 ERRNOR (EEXIST
, NULL
);
752 char *dirname
, *name
, *save
;
753 struct vfs_s_entry
*ent
;
754 struct vfs_s_inode
*dir
;
757 /* If the filesystem is read-only, disable file creation */
758 if (!(flags
& O_CREAT
) || !(me
->write
)) {
763 split_dir_name (me
, q
, &dirname
, &name
, &save
);
764 /* FIXME: check if vfs_s_find_inode returns NULL */
765 dir
= vfs_s_find_inode (me
, super
, dirname
, LINK_FOLLOW
, FL_DIR
);
768 ent
= vfs_s_generate_entry (me
, name
, dir
, 0755);
770 vfs_s_insert_entry (me
, dir
, ent
);
771 tmp_handle
= vfs_mkstemps (&ino
->localname
, me
->name
, name
);
772 if (tmp_handle
== -1) {
782 if (S_ISDIR (ino
->st
.st_mode
))
783 ERRNOR (EISDIR
, NULL
);
785 fh
= g_new (struct vfs_s_fh
, 1);
789 fh
->changed
= was_changed
;
792 if (IS_LINEAR (flags
)) {
793 if (MEDATA
->linear_start
) {
794 print_vfs_message (_("Starting linear transfer..."));
795 fh
->linear
= LS_LINEAR_PREOPEN
;
797 } else if ((MEDATA
->fh_open
)
798 && (MEDATA
->fh_open (me
, fh
, flags
, mode
))) {
803 if (fh
->ino
->localname
) {
804 fh
->handle
= open (fh
->ino
->localname
, NO_LINEAR (flags
), mode
);
805 if (fh
->handle
== -1) {
807 ERRNOR (errno
, NULL
);
811 /* i.e. we had no open files and now we have one */
812 vfs_rmstamp (me
, (vfsid
) super
);
814 fh
->ino
->st
.st_nlink
++;
819 vfs_s_read (void *fh
, char *buffer
, int count
)
822 struct vfs_class
*me
= FH_SUPER
->me
;
824 if (FH
->linear
== LS_LINEAR_PREOPEN
) {
825 if (!MEDATA
->linear_start (me
, FH
, FH
->pos
))
829 if (FH
->linear
== LS_LINEAR_CLOSED
)
830 vfs_die ("linear_start() did not set linear_state!");
832 if (FH
->linear
== LS_LINEAR_OPEN
)
833 return MEDATA
->linear_read (me
, FH
, buffer
, count
);
835 if (FH
->handle
!= -1){
836 n
= read (FH
->handle
, buffer
, count
);
841 vfs_die ("vfs_s_read: This should not happen\n");
846 vfs_s_write (void *fh
, const char *buffer
, int count
)
849 struct vfs_class
*me
= FH_SUPER
->me
;
852 vfs_die ("no writing to linear files, please");
855 if (FH
->handle
!= -1){
856 n
= write (FH
->handle
, buffer
, count
);
861 vfs_die ("vfs_s_write: This should not happen\n");
866 vfs_s_lseek (void *fh
, off_t offset
, int whence
)
868 off_t size
= FH
->ino
->st
.st_size
;
870 if (FH
->linear
== LS_LINEAR_OPEN
)
871 vfs_die ("cannot lseek() after linear_read!");
873 if (FH
->handle
!= -1){ /* If we have local file opened, we want to work with it */
874 int retval
= lseek (FH
->handle
, offset
, whence
);
876 FH
->ino
->super
->me
->verrno
= errno
;
882 offset
+= FH
->pos
; break;
884 offset
+= size
; break;
888 else if (offset
< size
)
896 vfs_s_close (void *fh
)
899 struct vfs_class
*me
= FH_SUPER
->me
;
901 FH_SUPER
->fd_usage
--;
902 if (!FH_SUPER
->fd_usage
)
903 vfs_stamp_create (me
, FH_SUPER
);
905 if (FH
->linear
== LS_LINEAR_OPEN
)
906 MEDATA
->linear_close (me
, fh
);
907 if (MEDATA
->fh_close
)
908 res
= MEDATA
->fh_close (me
, fh
);
909 if (FH
->changed
&& MEDATA
->file_store
){
910 char *s
= vfs_s_fullpath (me
, FH
->ino
);
914 res
= MEDATA
->file_store (me
, fh
, s
, FH
->ino
->localname
);
917 vfs_s_invalidate (me
, FH_SUPER
);
919 if (FH
->handle
!= -1)
922 vfs_s_free_inode (me
, FH
->ino
);
928 vfs_s_print_stats (const char *fs_name
, const char *action
,
929 const char *file_name
, off_t have
, off_t need
)
931 static const char *i18n_percent_transf_format
= NULL
;
932 static const char *i18n_transf_format
= NULL
;
934 if (i18n_percent_transf_format
== NULL
) {
935 i18n_percent_transf_format
=
936 _("%s: %s: %s %3d%% (%lu bytes transferred)");
937 i18n_transf_format
= _("%s: %s: %s %lu bytes transferred");
941 print_vfs_message (i18n_percent_transf_format
, fs_name
, action
,
942 file_name
, (int) ((double) have
* 100 / need
),
943 (unsigned long) have
);
945 print_vfs_message (i18n_transf_format
, fs_name
, action
, file_name
,
946 (unsigned long) have
);
950 vfs_s_retrieve_file (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
952 /* If you want reget, you'll have to open file with O_LINEAR */
956 off_t stat_size
= ino
->st
.st_size
;
959 memset (&fh
, 0, sizeof (fh
));
964 handle
= vfs_mkstemps (&ino
->localname
, me
->name
, ino
->ent
->name
);
970 if (!MEDATA
->linear_start (me
, &fh
, 0))
973 /* Clear the interrupt status */
974 tty_got_interrupt ();
975 tty_enable_interrupt_key ();
977 while ((n
= MEDATA
->linear_read (me
, &fh
, buffer
, sizeof (buffer
)))) {
983 vfs_s_print_stats (me
->name
, _("Getting file"), ino
->ent
->name
,
986 if (tty_got_interrupt ())
989 t
= write (handle
, buffer
, n
);
996 MEDATA
->linear_close (me
, &fh
);
999 tty_disable_interrupt_key ();
1003 MEDATA
->linear_close (me
, &fh
);
1005 tty_disable_interrupt_key ();
1007 unlink (ino
->localname
);
1009 g_free (ino
->localname
);
1010 ino
->localname
= NULL
;
1014 /* ------------------------------- mc support ---------------------------- */
1017 vfs_s_fill_names (struct vfs_class
*me
, fill_names_f func
)
1019 struct vfs_s_super
*a
= MEDATA
->supers
;
1023 name
= g_strconcat ( a
->name
, "#", me
->prefix
, "/",
1024 /* a->current_dir->name, */ (char *) NULL
);
1032 vfs_s_ferrno (struct vfs_class
*me
)
1038 * Get local copy of the given file. We reuse the existing file cache
1039 * for remote filesystems. Archives use standard VFS facilities.
1042 vfs_s_getlocalcopy (struct vfs_class
*me
, const char *path
)
1044 struct vfs_s_fh
*fh
;
1047 fh
= vfs_s_open (me
, path
, O_RDONLY
, 0);
1048 if (!fh
|| !fh
->ino
|| !fh
->ino
->localname
)
1051 local
= g_strdup (fh
->ino
->localname
);
1057 * Return the local copy. Since we are using our cache, we do nothing -
1058 * the cache will be removed when the archive is closed.
1061 vfs_s_ungetlocalcopy (struct vfs_class
*me
, const char *path
,
1062 const char *local
, int has_changed
)
1072 vfs_s_setctl (struct vfs_class
*me
, const char *path
, int ctlop
, void *arg
)
1075 case VFS_SETCTL_STALE_DATA
:
1077 struct vfs_s_inode
*ino
= vfs_s_inode_from_path (me
, path
, 0);
1082 ino
->super
->want_stale
= 1;
1084 ino
->super
->want_stale
= 0;
1085 vfs_s_invalidate (me
, ino
->super
);
1089 case VFS_SETCTL_LOGFILE
:
1090 MEDATA
->logfile
= fopen ((char *) arg
, "w");
1092 case VFS_SETCTL_FLUSH
:
1100 /* ----------------------------- Stamping support -------------------------- */
1103 vfs_s_getid (struct vfs_class
*me
, const char *path
)
1105 struct vfs_s_super
*archive
;
1108 if (!(p
= vfs_s_get_path (me
, path
, &archive
, FL_NO_OPEN
)))
1111 return (vfsid
) archive
;
1115 vfs_s_nothingisopen (vfsid id
)
1118 /* Our data structures should survive free of superblock at any time */
1123 vfs_s_free (vfsid id
)
1125 vfs_s_free_super (((struct vfs_s_super
*)id
)->me
, (struct vfs_s_super
*)id
);
1129 vfs_s_dir_uptodate (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1133 if (MEDATA
->flush
) {
1138 gettimeofday(&tim
, NULL
);
1139 if (tim
.tv_sec
< ino
->timestamp
.tv_sec
)
1144 /* Initialize one of our subclasses - fill common functions */
1146 vfs_s_init_class (struct vfs_class
*vclass
, struct vfs_s_subclass
*sub
)
1149 vclass
->fill_names
= vfs_s_fill_names
;
1150 vclass
->open
= vfs_s_open
;
1151 vclass
->close
= vfs_s_close
;
1152 vclass
->read
= vfs_s_read
;
1153 if (!(sub
->flags
& VFS_S_READONLY
)) {
1154 vclass
->write
= vfs_s_write
;
1156 vclass
->opendir
= vfs_s_opendir
;
1157 vclass
->readdir
= vfs_s_readdir
;
1158 vclass
->closedir
= vfs_s_closedir
;
1159 vclass
->stat
= vfs_s_stat
;
1160 vclass
->lstat
= vfs_s_lstat
;
1161 vclass
->fstat
= vfs_s_fstat
;
1162 vclass
->readlink
= vfs_s_readlink
;
1163 vclass
->chdir
= vfs_s_chdir
;
1164 vclass
->ferrno
= vfs_s_ferrno
;
1165 vclass
->lseek
= vfs_s_lseek
;
1166 vclass
->getid
= vfs_s_getid
;
1167 vclass
->nothingisopen
= vfs_s_nothingisopen
;
1168 vclass
->free
= vfs_s_free
;
1169 if (sub
->flags
& VFS_S_REMOTE
) {
1170 vclass
->getlocalcopy
= vfs_s_getlocalcopy
;
1171 vclass
->ungetlocalcopy
= vfs_s_ungetlocalcopy
;
1172 sub
->find_entry
= vfs_s_find_entry_linear
;
1174 sub
->find_entry
= vfs_s_find_entry_tree
;
1176 vclass
->setctl
= vfs_s_setctl
;
1177 sub
->dir_uptodate
= vfs_s_dir_uptodate
;
1180 /* ----------- Utility functions for networked filesystems -------------- */
1184 vfs_s_select_on_two (int fd1
, int fd2
)
1187 struct timeval timeout
;
1189 int maxfd
= (fd1
> fd2
? fd1
: fd2
) + 1;
1192 timeout
.tv_usec
= 0;
1196 v
= select (maxfd
, &set
, 0, 0, &timeout
);
1199 if (FD_ISSET (fd1
, &set
))
1201 if (FD_ISSET (fd2
, &set
))
1207 vfs_s_get_line (struct vfs_class
*me
, int sock
, char *buf
, int buf_len
, char term
)
1209 FILE *logfile
= MEDATA
->logfile
;
1213 for (i
= 0; i
< buf_len
- 1; i
++, buf
++){
1214 if (read (sock
, buf
, sizeof(char)) <= 0)
1217 fwrite (buf
, 1, 1, logfile
);
1226 /* Line is too long - terminate buffer and discard the rest of line */
1228 while (read (sock
, &c
, sizeof (c
)) > 0) {
1230 fwrite (&c
, 1, 1, logfile
);
1240 vfs_s_get_line_interruptible (struct vfs_class
*me
, char *buffer
, int size
, int fd
)
1247 tty_enable_interrupt_key ();
1248 for (i
= 0; i
< size
-1; i
++){
1249 n
= read (fd
, buffer
+i
, 1);
1250 tty_disable_interrupt_key ();
1251 if (n
== -1 && errno
== EINTR
){
1259 if (buffer
[i
] == '\n'){
1264 buffer
[size
-1] = 0;
1267 #endif /* USE_NETCODE */