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() */
38 #include <inttypes.h> /* uintmax_t */
41 #include "lib/global.h"
43 #include "lib/tty/tty.h" /* enable/disable interrupt key */
44 #include "lib/util.h" /* concat_dir_and_file */
46 #include "lib/widget.h" /* message() */
51 #include "xdirentry.h"
52 #include "gc.h" /* vfs_rmstamp */
54 /*** global variables ****************************************************************************/
56 /*** file scope macro definitions ****************************************************************/
58 #define CALL(x) if (MEDATA->x) MEDATA->x
60 /*** file scope type declarations ****************************************************************/
65 struct vfs_s_inode
*dir
;
68 /*** file scope variables ************************************************************************/
70 static volatile int total_inodes
= 0, total_entries
= 0;
72 /*** file scope functions ************************************************************************/
73 /* --------------------------------------------------------------------------------------------- */
76 vfs_s_entry_compare (const void *a
, const void *b
)
78 const struct vfs_s_entry
*e
= (const struct vfs_s_entry
*) a
;
79 const char *name
= (const char *) b
;
81 return strcmp (e
->name
, name
);
84 /* --------------------------------------------------------------------------------------------- */
87 vfs_s_free_inode (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
90 vfs_die ("Don't pass NULL to me");
92 /* ==0 can happen if freshly created entry is deleted */
93 if (ino
->st
.st_nlink
> 1)
99 while (ino
->subdir
!= NULL
)
100 vfs_s_free_entry (me
, (struct vfs_s_entry
*) ino
->subdir
->data
);
102 CALL (free_inode
) (me
, ino
);
103 g_free (ino
->linkname
);
104 if (ino
->localname
!= NULL
)
106 unlink (ino
->localname
);
107 g_free (ino
->localname
);
110 ino
->super
->ino_usage
--;
114 /* --------------------------------------------------------------------------------------------- */
115 /* We were asked to create entries automagically */
117 static struct vfs_s_entry
*
118 vfs_s_automake (struct vfs_class
*me
, struct vfs_s_inode
*dir
, char *path
, int flags
)
120 struct vfs_s_entry
*res
;
123 sep
= strchr (path
, PATH_SEP
);
127 res
= vfs_s_generate_entry (me
, path
, dir
, flags
& FL_MKDIR
? (0777 | S_IFDIR
) : 0777);
128 vfs_s_insert_entry (me
, dir
, res
);
136 /* --------------------------------------------------------------------------------------------- */
137 /* If the entry is a symlink, find the entry for its target */
139 static struct vfs_s_entry
*
140 vfs_s_resolve_symlink (struct vfs_class
*me
, struct vfs_s_entry
*entry
, int follow
)
143 char *fullname
= NULL
;
144 struct vfs_s_entry
*target
;
146 if (follow
== LINK_NO_FOLLOW
)
149 ERRNOR (ELOOP
, NULL
);
151 ERRNOR (ENOENT
, NULL
);
152 if (!S_ISLNK (entry
->ino
->st
.st_mode
))
155 linkname
= entry
->ino
->linkname
;
156 if (linkname
== NULL
)
157 ERRNOR (EFAULT
, NULL
);
159 /* make full path from relative */
160 if (*linkname
!= PATH_SEP
)
162 char *fullpath
= vfs_s_fullpath (me
, entry
->dir
);
165 fullname
= g_strconcat (fullpath
, "/", linkname
, (char *) NULL
);
171 target
= (MEDATA
->find_entry
) (me
, entry
->dir
->super
->root
, linkname
, follow
- 1, 0);
176 /* --------------------------------------------------------------------------------------------- */
178 * Follow > 0: follow links, serves as loop protect,
179 * == -1: do not follow links
182 static struct vfs_s_entry
*
183 vfs_s_find_entry_tree (struct vfs_class
*me
, struct vfs_s_inode
*root
,
184 const char *a_path
, int follow
, int flags
)
187 struct vfs_s_entry
*ent
= NULL
;
188 char *const pathref
= g_strdup (a_path
);
189 char *path
= pathref
;
191 /* canonicalize as well, but don't remove '../' from path */
192 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
198 while (*path
== PATH_SEP
) /* Strip leading '/' */
207 for (pseg
= 0; path
[pseg
] != '\0' && path
[pseg
] != PATH_SEP
; pseg
++)
210 for (iter
= root
->subdir
; iter
!= NULL
; iter
= g_list_next (iter
))
212 ent
= (struct vfs_s_entry
*) iter
->data
;
213 if (strlen (ent
->name
) == pseg
&& strncmp (ent
->name
, path
, pseg
) == 0)
218 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
220 if (ent
== NULL
&& (flags
& (FL_MKFILE
| FL_MKDIR
)) != 0)
221 ent
= vfs_s_automake (me
, root
, path
, flags
);
229 /* here we must follow leading directories always;
230 only the actual file is optional */
231 ent
= vfs_s_resolve_symlink (me
, ent
,
232 strchr (path
, PATH_SEP
) != NULL
? LINK_FOLLOW
: follow
);
242 /* --------------------------------------------------------------------------------------------- */
245 split_dir_name (struct vfs_class
*me
, char *path
, char **dir
, char **name
, char **save
)
251 s
= strrchr (path
, PATH_SEP
);
256 *dir
= path
+ strlen (path
); /* an empty string */
267 /* --------------------------------------------------------------------------------------------- */
269 static struct vfs_s_entry
*
270 vfs_s_find_entry_linear (struct vfs_class
*me
, struct vfs_s_inode
*root
,
271 const char *a_path
, int follow
, int flags
)
273 struct vfs_s_entry
*ent
= NULL
;
274 char *const path
= g_strdup (a_path
);
275 struct vfs_s_entry
*retval
= NULL
;
278 if (root
->super
->root
!= root
)
279 vfs_die ("We have to use _real_ root. Always. Sorry.");
281 /* canonicalize as well, but don't remove '../' from path */
282 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
284 if ((flags
& FL_DIR
) == 0)
286 char *dirname
, *name
, *save
;
287 struct vfs_s_inode
*ino
;
288 split_dir_name (me
, path
, &dirname
, &name
, &save
);
289 ino
= vfs_s_find_inode (me
, root
->super
, dirname
, follow
, flags
| FL_DIR
);
292 retval
= vfs_s_find_entry_tree (me
, ino
, name
, follow
, flags
);
297 iter
= g_list_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
298 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
300 if (ent
!= NULL
&& !MEDATA
->dir_uptodate (me
, ent
->ino
))
303 vfs_print_message (_("Directory cache expired for %s"), path
);
305 vfs_s_free_entry (me
, ent
);
311 struct vfs_s_inode
*ino
;
313 ino
= vfs_s_new_inode (me
, root
->super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
314 ent
= vfs_s_new_entry (me
, path
, ino
);
315 if (MEDATA
->dir_load (me
, ino
, path
) == -1)
317 vfs_s_free_entry (me
, ent
);
322 vfs_s_insert_entry (me
, root
, ent
);
324 iter
= g_list_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
325 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
328 vfs_die ("find_linear: success but directory is not there\n");
331 if (!vfs_s_resolve_symlink (me
, ent
, follow
))
341 /* --------------------------------------------------------------------------------------------- */
342 /* Ook, these were functions around directory entries / inodes */
343 /* -------------------------------- superblock games -------------------------- */
345 static struct vfs_s_super
*
346 vfs_s_new_super (struct vfs_class
*me
)
348 struct vfs_s_super
*super
;
350 super
= g_new0 (struct vfs_s_super
, 1);
355 /* --------------------------------------------------------------------------------------------- */
358 vfs_s_insert_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
360 MEDATA
->supers
= g_list_prepend (MEDATA
->supers
, super
);
363 /* --------------------------------------------------------------------------------------------- */
366 vfs_s_free_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
368 if (super
->root
!= NULL
)
370 vfs_s_free_inode (me
, super
->root
);
375 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
376 if (super
->ino_usage
)
377 message (D_ERROR
, "Direntry warning",
378 "Super ino_usage is %d, memory leak", super
->ino_usage
);
380 if (super
->want_stale
)
381 message (D_ERROR
, "Direntry warning", "%s", "Super has want_stale set");
384 MEDATA
->supers
= g_list_remove (MEDATA
->supers
, super
);
386 CALL (free_archive
) (me
, super
);
387 #ifdef ENABLE_VFS_NET
388 vfs_url_free (super
->url
);
390 g_free (super
->name
);
394 /* --------------------------------------------------------------------------------------------- */
396 * Dissect the path and create corresponding superblock.
397 * The result should be freed.
401 vfs_s_get_path (struct vfs_class
*me
, const char *inname
, struct vfs_s_super
**archive
, int flags
)
405 buf
= g_strdup (inname
);
406 retval
= g_strdup (vfs_s_get_path_mangle (me
, buf
, archive
, flags
));
411 /* --------------------------------------------------------------------------------------------- */
412 /* Support of archives */
413 /* ------------------------ readdir & friends ----------------------------- */
415 static struct vfs_s_inode
*
416 vfs_s_inode_from_path (struct vfs_class
*me
, const char *name
, int flags
)
418 struct vfs_s_super
*super
;
419 struct vfs_s_inode
*ino
;
422 if (!(q
= vfs_s_get_path (me
, name
, &super
, 0)))
426 vfs_s_find_inode (me
, super
, q
,
427 flags
& FL_FOLLOW
? LINK_FOLLOW
: LINK_NO_FOLLOW
, flags
& ~FL_FOLLOW
);
429 /* We are asking about / directory of ftp server: assume it exists */
431 vfs_s_find_inode (me
, super
, q
,
432 flags
& FL_FOLLOW
? LINK_FOLLOW
:
433 LINK_NO_FOLLOW
, FL_DIR
| (flags
& ~FL_FOLLOW
));
438 /* --------------------------------------------------------------------------------------------- */
441 vfs_s_opendir (const vfs_path_t
* vpath
)
443 struct vfs_s_inode
*dir
;
444 struct dirhandle
*info
;
445 vfs_path_element_t
*path_element
;
447 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
448 dir
= vfs_s_inode_from_path (path_element
->class, vpath
->unparsed
, FL_DIR
| FL_FOLLOW
);
451 if (!S_ISDIR (dir
->st
.st_mode
))
453 path_element
->class->verrno
= ENOTDIR
;
459 if (dir
->subdir
== NULL
) /* This can actually happen if we allow empty directories */
461 path_element
->class->verrno
= EAGAIN
;
465 info
= g_new (struct dirhandle
, 1);
466 info
->cur
= dir
->subdir
;
472 /* --------------------------------------------------------------------------------------------- */
475 vfs_s_readdir (void *data
)
477 static union vfs_dirent dir
;
478 struct dirhandle
*info
= (struct dirhandle
*) data
;
481 if (info
->cur
== NULL
|| info
->cur
->data
== NULL
)
484 name
= ((struct vfs_s_entry
*) info
->cur
->data
)->name
;
486 g_strlcpy (dir
.dent
.d_name
, name
, MC_MAXPATHLEN
);
488 vfs_die ("Null in structure-cannot happen");
490 compute_namelen (&dir
.dent
);
491 info
->cur
= g_list_next (info
->cur
);
493 return (void *) &dir
;
496 /* --------------------------------------------------------------------------------------------- */
499 vfs_s_closedir (void *data
)
501 struct dirhandle
*info
= (struct dirhandle
*) data
;
502 struct vfs_s_inode
*dir
= info
->dir
;
504 vfs_s_free_inode (dir
->super
->me
, dir
);
509 /* --------------------------------------------------------------------------------------------- */
512 vfs_s_chdir (const vfs_path_t
* vpath
)
516 data
= vfs_s_opendir (vpath
);
519 vfs_s_closedir (data
);
523 /* --------------------------------------------------------------------------------------------- */
524 /* --------------------------- stat and friends ---------------------------- */
527 vfs_s_internal_stat (const vfs_path_t
* vpath
, struct stat
*buf
, int flag
)
529 struct vfs_s_inode
*ino
;
530 vfs_path_element_t
*path_element
;
532 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
533 ino
= vfs_s_inode_from_path (path_element
->class, vpath
->unparsed
, flag
);
540 /* --------------------------------------------------------------------------------------------- */
543 vfs_s_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
545 return vfs_s_internal_stat (vpath
, buf
, FL_FOLLOW
);
548 /* --------------------------------------------------------------------------------------------- */
551 vfs_s_lstat (const vfs_path_t
* vpath
, struct stat
*buf
)
553 return vfs_s_internal_stat (vpath
, buf
, FL_NONE
);
556 /* --------------------------------------------------------------------------------------------- */
559 vfs_s_fstat (void *fh
, struct stat
*buf
)
565 /* --------------------------------------------------------------------------------------------- */
568 vfs_s_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
570 struct vfs_s_inode
*ino
;
572 vfs_path_element_t
*path_element
;
574 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
576 ino
= vfs_s_inode_from_path (path_element
->class, vpath
->unparsed
, 0);
580 if (!S_ISLNK (ino
->st
.st_mode
))
582 path_element
->class->verrno
= EINVAL
;
586 if (ino
->linkname
== NULL
)
588 path_element
->class->verrno
= EFAULT
;
592 len
= strlen (ino
->linkname
);
595 /* readlink() does not append a NUL character to buf */
596 memcpy (buf
, ino
->linkname
, len
);
600 /* --------------------------------------------------------------------------------------------- */
603 vfs_s_read (void *fh
, char *buffer
, size_t count
)
606 struct vfs_class
*me
= FH_SUPER
->me
;
608 if (FH
->linear
== LS_LINEAR_PREOPEN
)
610 if (!MEDATA
->linear_start (me
, FH
, FH
->pos
))
614 if (FH
->linear
== LS_LINEAR_CLOSED
)
615 vfs_die ("linear_start() did not set linear_state!");
617 if (FH
->linear
== LS_LINEAR_OPEN
)
618 return MEDATA
->linear_read (me
, FH
, buffer
, count
);
620 if (FH
->handle
!= -1)
622 n
= read (FH
->handle
, buffer
, count
);
627 vfs_die ("vfs_s_read: This should not happen\n");
631 /* --------------------------------------------------------------------------------------------- */
634 vfs_s_write (void *fh
, const char *buffer
, size_t count
)
637 struct vfs_class
*me
= FH_SUPER
->me
;
640 vfs_die ("no writing to linear files, please");
643 if (FH
->handle
!= -1)
645 n
= write (FH
->handle
, buffer
, count
);
650 vfs_die ("vfs_s_write: This should not happen\n");
654 /* --------------------------------------------------------------------------------------------- */
657 vfs_s_lseek (void *fh
, off_t offset
, int whence
)
659 off_t size
= FH
->ino
->st
.st_size
;
661 if (FH
->linear
== LS_LINEAR_OPEN
)
662 vfs_die ("cannot lseek() after linear_read!");
664 if (FH
->handle
!= -1)
665 { /* If we have local file opened, we want to work with it */
666 off_t retval
= lseek (FH
->handle
, offset
, whence
);
668 FH
->ino
->super
->me
->verrno
= errno
;
683 else if (offset
< size
)
690 /* --------------------------------------------------------------------------------------------- */
693 vfs_s_close (void *fh
)
696 struct vfs_class
*me
= FH_SUPER
->me
;
698 FH_SUPER
->fd_usage
--;
699 if (!FH_SUPER
->fd_usage
)
700 vfs_stamp_create (me
, FH_SUPER
);
702 if (FH
->linear
== LS_LINEAR_OPEN
)
703 MEDATA
->linear_close (me
, fh
);
704 if (MEDATA
->fh_close
)
705 res
= MEDATA
->fh_close (me
, fh
);
706 if (FH
->changed
&& MEDATA
->file_store
)
708 char *s
= vfs_s_fullpath (me
, FH
->ino
);
713 res
= MEDATA
->file_store (me
, fh
, s
, FH
->ino
->localname
);
716 vfs_s_invalidate (me
, FH_SUPER
);
718 if (FH
->handle
!= -1)
721 vfs_s_free_inode (me
, FH
->ino
);
726 /* --------------------------------------------------------------------------------------------- */
729 vfs_s_print_stats (const char *fs_name
, const char *action
,
730 const char *file_name
, off_t have
, off_t need
)
732 static const char *i18n_percent_transf_format
= NULL
;
733 static const char *i18n_transf_format
= NULL
;
735 if (i18n_percent_transf_format
== NULL
)
737 i18n_percent_transf_format
= "%s: %s: %s %3d%% (%" PRIuMAX
" %s";
738 i18n_transf_format
= "%s: %s: %s %" PRIuMAX
" %s";
742 vfs_print_message (i18n_percent_transf_format
, fs_name
, action
,
743 file_name
, (int) ((double) have
* 100 / need
), (uintmax_t) have
,
744 _("bytes transferred"));
746 vfs_print_message (i18n_transf_format
, fs_name
, action
, file_name
, (uintmax_t) have
,
747 _("bytes transferred"));
750 /* --------------------------------------------------------------------------------------------- */
751 /* ------------------------------- mc support ---------------------------- */
754 vfs_s_fill_names (struct vfs_class
*me
, fill_names_f func
)
758 for (iter
= MEDATA
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
760 const struct vfs_s_super
*super
= (const struct vfs_s_super
*) iter
->data
;
763 name
= g_strconcat (super
->name
, "#", me
->prefix
, "/",
764 /* super->current_dir->name, */ (char *) NULL
);
770 /* --------------------------------------------------------------------------------------------- */
773 vfs_s_ferrno (struct vfs_class
*me
)
778 /* --------------------------------------------------------------------------------------------- */
780 * Get local copy of the given file. We reuse the existing file cache
781 * for remote filesystems. Archives use standard VFS facilities.
785 vfs_s_getlocalcopy (const vfs_path_t
* vpath
)
787 vfs_file_handler_t
*fh
;
790 fh
= vfs_s_open (vpath
, O_RDONLY
, 0);
794 if ((fh
->ino
!= NULL
) && (fh
->ino
->localname
!= NULL
))
795 local
= g_strdup (fh
->ino
->localname
);
803 /* --------------------------------------------------------------------------------------------- */
805 * Return the local copy. Since we are using our cache, we do nothing -
806 * the cache will be removed when the archive is closed.
810 vfs_s_ungetlocalcopy (const vfs_path_t
* vpath
, const char *local
, int has_changed
)
818 /* --------------------------------------------------------------------------------------------- */
821 vfs_s_setctl (const vfs_path_t
* vpath
, int ctlop
, void *arg
)
823 vfs_path_element_t
*path_element
;
825 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
828 case VFS_SETCTL_STALE_DATA
:
830 struct vfs_s_inode
*ino
=
831 vfs_s_inode_from_path (path_element
->class, vpath
->unparsed
, 0);
836 ino
->super
->want_stale
= 1;
839 ino
->super
->want_stale
= 0;
840 vfs_s_invalidate (path_element
->class, ino
->super
);
844 case VFS_SETCTL_LOGFILE
:
845 ((struct vfs_s_subclass
*) path_element
->class->data
)->logfile
= fopen ((char *) arg
, "w");
847 case VFS_SETCTL_FLUSH
:
848 ((struct vfs_s_subclass
*) path_element
->class->data
)->flush
= 1;
854 /* --------------------------------------------------------------------------------------------- */
855 /* ----------------------------- Stamping support -------------------------- */
858 vfs_s_getid (const vfs_path_t
* vpath
)
860 struct vfs_s_super
*archive
= NULL
;
862 vfs_path_element_t
*path_element
;
864 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
866 p
= vfs_s_get_path (path_element
->class, vpath
->unparsed
, &archive
, FL_NO_OPEN
);
870 return (vfsid
) archive
;
873 /* --------------------------------------------------------------------------------------------- */
876 vfs_s_nothingisopen (vfsid id
)
879 /* Our data structures should survive free of superblock at any time */
883 /* --------------------------------------------------------------------------------------------- */
886 vfs_s_free (vfsid id
)
888 vfs_s_free_super (((struct vfs_s_super
*) id
)->me
, (struct vfs_s_super
*) id
);
891 /* --------------------------------------------------------------------------------------------- */
894 vfs_s_dir_uptodate (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
904 gettimeofday (&tim
, NULL
);
905 if (tim
.tv_sec
< ino
->timestamp
.tv_sec
)
911 /* --------------------------------------------------------------------------------------------- */
912 /*** public functions ****************************************************************************/
913 /* --------------------------------------------------------------------------------------------- */
916 vfs_s_new_inode (struct vfs_class
*me
, struct vfs_s_super
*super
, struct stat
*initstat
)
918 struct vfs_s_inode
*ino
;
920 ino
= g_try_new0 (struct vfs_s_inode
, 1);
927 ino
->st
.st_nlink
= 0;
928 ino
->st
.st_ino
= MEDATA
->inode_counter
++;
929 ino
->st
.st_dev
= MEDATA
->rdev
;
934 CALL (init_inode
) (me
, ino
);
939 /* --------------------------------------------------------------------------------------------- */
942 vfs_s_new_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*inode
)
944 struct vfs_s_entry
*entry
;
946 entry
= g_new0 (struct vfs_s_entry
, 1);
949 entry
->name
= g_strdup (name
);
951 entry
->ino
->ent
= entry
;
952 CALL (init_entry
) (me
, entry
);
958 /* --------------------------------------------------------------------------------------------- */
961 vfs_s_free_entry (struct vfs_class
*me
, struct vfs_s_entry
*ent
)
963 if (ent
->dir
!= NULL
)
964 ent
->dir
->subdir
= g_list_remove (ent
->dir
->subdir
, ent
);
967 /* ent->name = NULL; */
969 if (ent
->ino
!= NULL
)
971 ent
->ino
->ent
= NULL
;
972 vfs_s_free_inode (me
, ent
->ino
);
979 /* --------------------------------------------------------------------------------------------- */
982 vfs_s_insert_entry (struct vfs_class
*me
, struct vfs_s_inode
*dir
, struct vfs_s_entry
*ent
)
988 ent
->ino
->st
.st_nlink
++;
989 dir
->subdir
= g_list_append (dir
->subdir
, ent
);
992 /* --------------------------------------------------------------------------------------------- */
995 vfs_s_default_stat (struct vfs_class
*me
, mode_t mode
)
997 static struct stat st
;
1002 myumask
= umask (022);
1010 st
.st_uid
= getuid ();
1011 st
.st_gid
= getgid ();
1013 st
.st_mtime
= st
.st_atime
= st
.st_ctime
= time (NULL
);
1018 /* --------------------------------------------------------------------------------------------- */
1020 struct vfs_s_entry
*
1021 vfs_s_generate_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*parent
,
1024 struct vfs_s_inode
*inode
;
1027 st
= vfs_s_default_stat (me
, mode
);
1028 inode
= vfs_s_new_inode (me
, parent
->super
, st
);
1030 return vfs_s_new_entry (me
, name
, inode
);
1033 /* --------------------------------------------------------------------------------------------- */
1035 struct vfs_s_inode
*
1036 vfs_s_find_inode (struct vfs_class
*me
, const struct vfs_s_super
*super
,
1037 const char *path
, int follow
, int flags
)
1039 struct vfs_s_entry
*ent
;
1041 if (((MEDATA
->flags
& VFS_S_REMOTE
) == 0) && (*path
== '\0'))
1044 ent
= (MEDATA
->find_entry
) (me
, super
->root
, path
, follow
, flags
);
1045 return (ent
!= NULL
) ? ent
->ino
: NULL
;
1048 /* --------------------------------------------------------------------------------------------- */
1049 /* Ook, these were functions around directory entries / inodes */
1050 /* -------------------------------- superblock games -------------------------- */
1053 * Dissect the path and create corresponding superblock. Note that inname
1054 * can be changed and the result may point inside the original string.
1057 vfs_s_get_path_mangle (struct vfs_class
*me
, char *inname
, struct vfs_s_super
**archive
, int flags
)
1062 const char *archive_name
;
1064 struct vfs_s_super
*super
;
1065 void *cookie
= NULL
;
1067 archive_name
= inname
;
1068 vfs_split (inname
, &local
, &op
);
1069 retval
= (local
!= NULL
) ? local
: "";
1071 if (MEDATA
->archive_check
!= NULL
)
1073 cookie
= MEDATA
->archive_check (me
, archive_name
, op
);
1078 for (iter
= MEDATA
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
1082 super
= (struct vfs_s_super
*) iter
->data
;
1084 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1085 i
= MEDATA
->archive_same (me
, super
, archive_name
, op
, cookie
);
1089 goto return_success
;
1094 if (flags
& FL_NO_OPEN
)
1097 super
= vfs_s_new_super (me
);
1098 if (MEDATA
->open_archive
!= NULL
)
1099 result
= MEDATA
->open_archive (me
, super
, archive_name
, op
);
1102 vfs_s_free_super (me
, super
);
1106 vfs_die ("You have to fill name\n");
1108 vfs_die ("You have to fill root inode\n");
1110 vfs_s_insert_super (me
, super
);
1111 vfs_stamp_create (me
, super
);
1118 /* --------------------------------------------------------------------------------------------- */
1121 vfs_s_invalidate (struct vfs_class
*me
, struct vfs_s_super
*super
)
1123 if (!super
->want_stale
)
1125 vfs_s_free_inode (me
, super
->root
);
1126 super
->root
= vfs_s_new_inode (me
, super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
1130 /* --------------------------------------------------------------------------------------------- */
1133 vfs_s_fullpath (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1136 ERRNOR (EAGAIN
, NULL
);
1138 if (!(MEDATA
->flags
& VFS_S_REMOTE
))
1142 char *path
= g_strdup (ino
->ent
->name
);
1145 ino
= ino
->ent
->dir
;
1146 if (ino
== ino
->super
->root
)
1148 newpath
= g_strconcat (ino
->ent
->name
, "/", path
, (char *) NULL
);
1155 /* remote systems */
1156 if ((!ino
->ent
->dir
) || (!ino
->ent
->dir
->ent
))
1157 return g_strdup (ino
->ent
->name
);
1159 return g_strconcat (ino
->ent
->dir
->ent
->name
, PATH_SEP_STR
, ino
->ent
->name
, (char *) NULL
);
1162 /* --------------------------------------------------------------------------------------------- */
1163 /* --------------------------- stat and friends ---------------------------- */
1166 vfs_s_open (const vfs_path_t
* vpath
, int flags
, mode_t mode
)
1168 int was_changed
= 0;
1169 vfs_file_handler_t
*fh
;
1170 struct vfs_s_super
*super
;
1172 struct vfs_s_inode
*ino
;
1173 vfs_path_element_t
*path_element
;
1175 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
1177 q
= vfs_s_get_path (path_element
->class, vpath
->unparsed
, &super
, 0);
1180 ino
= vfs_s_find_inode (path_element
->class, super
, q
, LINK_FOLLOW
, FL_NONE
);
1181 if (ino
&& ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
)))
1184 path_element
->class->verrno
= EEXIST
;
1189 char *dirname
, *name
, *save
;
1190 struct vfs_s_entry
*ent
;
1191 struct vfs_s_inode
*dir
;
1194 /* If the filesystem is read-only, disable file creation */
1195 if (!(flags
& O_CREAT
) || !(path_element
->class->write
))
1201 split_dir_name (path_element
->class, q
, &dirname
, &name
, &save
);
1202 dir
= vfs_s_find_inode (path_element
->class, super
, dirname
, LINK_FOLLOW
, FL_DIR
);
1210 ent
= vfs_s_generate_entry (path_element
->class, name
, dir
, 0755);
1212 vfs_s_insert_entry (path_element
->class, dir
, ent
);
1213 tmp_handle
= vfs_mkstemps (&ino
->localname
, path_element
->class->name
, name
);
1214 if (tmp_handle
== -1)
1225 if (S_ISDIR (ino
->st
.st_mode
))
1227 path_element
->class->verrno
= EISDIR
;
1231 fh
= g_new (vfs_file_handler_t
, 1);
1235 fh
->changed
= was_changed
;
1239 if (IS_LINEAR (flags
))
1241 if (VFSDATA (path_element
)->linear_start
)
1243 vfs_print_message (_("Starting linear transfer..."));
1244 fh
->linear
= LS_LINEAR_PREOPEN
;
1247 else if ((VFSDATA (path_element
)->fh_open
!= NULL
)
1248 && (VFSDATA (path_element
)->fh_open (path_element
->class, fh
, flags
, mode
) != 0))
1254 if (fh
->ino
->localname
)
1256 fh
->handle
= open (fh
->ino
->localname
, NO_LINEAR (flags
), mode
);
1257 if (fh
->handle
== -1)
1260 path_element
->class->verrno
= errno
;
1265 /* i.e. we had no open files and now we have one */
1266 vfs_rmstamp (path_element
->class, (vfsid
) super
);
1268 fh
->ino
->st
.st_nlink
++;
1272 /* --------------------------------------------------------------------------------------------- */
1275 vfs_s_retrieve_file (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1277 /* If you want reget, you'll have to open file with O_LINEAR */
1281 off_t stat_size
= ino
->st
.st_size
;
1282 vfs_file_handler_t fh
;
1284 memset (&fh
, 0, sizeof (fh
));
1289 handle
= vfs_mkstemps (&ino
->localname
, me
->name
, ino
->ent
->name
);
1296 if (!MEDATA
->linear_start (me
, &fh
, 0))
1299 /* Clear the interrupt status */
1300 tty_got_interrupt ();
1301 tty_enable_interrupt_key ();
1303 while ((n
= MEDATA
->linear_read (me
, &fh
, buffer
, sizeof (buffer
))))
1310 vfs_s_print_stats (me
->name
, _("Getting file"), ino
->ent
->name
, total
, stat_size
);
1312 if (tty_got_interrupt ())
1315 t
= write (handle
, buffer
, n
);
1323 MEDATA
->linear_close (me
, &fh
);
1326 tty_disable_interrupt_key ();
1331 MEDATA
->linear_close (me
, &fh
);
1333 tty_disable_interrupt_key ();
1335 unlink (ino
->localname
);
1337 g_free (ino
->localname
);
1338 ino
->localname
= NULL
;
1343 /* --------------------------------------------------------------------------------------------- */
1344 /* ----------------------------- Stamping support -------------------------- */
1346 /* Initialize one of our subclasses - fill common functions */
1348 vfs_s_init_class (struct vfs_class
*vclass
, struct vfs_s_subclass
*sub
)
1351 vclass
->fill_names
= vfs_s_fill_names
;
1352 vclass
->open
= vfs_s_open
;
1353 vclass
->close
= vfs_s_close
;
1354 vclass
->read
= vfs_s_read
;
1355 if (!(sub
->flags
& VFS_S_READONLY
))
1357 vclass
->write
= vfs_s_write
;
1359 vclass
->opendir
= vfs_s_opendir
;
1360 vclass
->readdir
= vfs_s_readdir
;
1361 vclass
->closedir
= vfs_s_closedir
;
1362 vclass
->stat
= vfs_s_stat
;
1363 vclass
->lstat
= vfs_s_lstat
;
1364 vclass
->fstat
= vfs_s_fstat
;
1365 vclass
->readlink
= vfs_s_readlink
;
1366 vclass
->chdir
= vfs_s_chdir
;
1367 vclass
->ferrno
= vfs_s_ferrno
;
1368 vclass
->lseek
= vfs_s_lseek
;
1369 vclass
->getid
= vfs_s_getid
;
1370 vclass
->nothingisopen
= vfs_s_nothingisopen
;
1371 vclass
->free
= vfs_s_free
;
1372 if (sub
->flags
& VFS_S_REMOTE
)
1374 vclass
->getlocalcopy
= vfs_s_getlocalcopy
;
1375 vclass
->ungetlocalcopy
= vfs_s_ungetlocalcopy
;
1376 sub
->find_entry
= vfs_s_find_entry_linear
;
1380 sub
->find_entry
= vfs_s_find_entry_tree
;
1382 vclass
->setctl
= vfs_s_setctl
;
1383 sub
->dir_uptodate
= vfs_s_dir_uptodate
;
1386 /* --------------------------------------------------------------------------------------------- */
1387 /** Find VFS id for given directory name */
1390 vfs_getid (const vfs_path_t
* vpath
)
1392 vfs_path_element_t
*path_element
;
1394 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
1395 if (path_element
== NULL
|| path_element
->class->getid
== NULL
)
1398 return (*path_element
->class->getid
) (vpath
);
1401 /* --------------------------------------------------------------------------------------------- */
1402 /* ----------- Utility functions for networked filesystems -------------- */
1404 #ifdef ENABLE_VFS_NET
1406 vfs_s_select_on_two (int fd1
, int fd2
)
1409 struct timeval time_out
;
1411 int maxfd
= (fd1
> fd2
? fd1
: fd2
) + 1;
1413 time_out
.tv_sec
= 1;
1414 time_out
.tv_usec
= 0;
1418 v
= select (maxfd
, &set
, 0, 0, &time_out
);
1421 if (FD_ISSET (fd1
, &set
))
1423 if (FD_ISSET (fd2
, &set
))
1428 /* --------------------------------------------------------------------------------------------- */
1431 vfs_s_get_line (struct vfs_class
*me
, int sock
, char *buf
, int buf_len
, char term
)
1433 FILE *logfile
= MEDATA
->logfile
;
1437 for (i
= 0; i
< buf_len
- 1; i
++, buf
++)
1439 if (read (sock
, buf
, sizeof (char)) <= 0)
1445 ret1
= fwrite (buf
, 1, 1, logfile
);
1446 ret2
= fflush (logfile
);
1455 /* Line is too long - terminate buffer and discard the rest of line */
1457 while (read (sock
, &c
, sizeof (c
)) > 0)
1463 ret1
= fwrite (&c
, 1, 1, logfile
);
1464 ret2
= fflush (logfile
);
1472 /* --------------------------------------------------------------------------------------------- */
1475 vfs_s_get_line_interruptible (struct vfs_class
*me
, char *buffer
, int size
, int fd
)
1482 tty_enable_interrupt_key ();
1483 for (i
= 0; i
< size
- 1; i
++)
1485 n
= read (fd
, buffer
+ i
, 1);
1486 tty_disable_interrupt_key ();
1487 if (n
== -1 && errno
== EINTR
)
1497 if (buffer
[i
] == '\n')
1503 buffer
[size
- 1] = 0;
1506 #endif /* ENABLE_VFS_NET */
1508 /* --------------------------------------------------------------------------------------------- */