2 Directory cache support
4 Copyright (C) 1998, 2011
5 The Free Software Foundation, Inc.
8 Pavel Machek <pavel@ucw.cz>, 1998
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 \warning Paths here do _not_ begin with '/', so root directory of
26 archive/site is simply "".
30 * \brief Source: directory cache support
32 * So that you do not have copy of this in each and every filesystem.
34 * Very loosely based on tar.c from midnight and archives.[ch] from
35 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
37 * Unfortunately, I was unable to keep all filesystems
38 * uniform. tar-like filesystems use tree structure where each
39 * directory has pointers to its subdirectories. We can do this
40 * because we have full information about our archive.
42 * At ftp-like filesystems, situation is a little bit different. When
43 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
44 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
45 * listed. That means that we do not have complete information, and if
46 * /usr is symlink to /4, we will not know. Also we have to time out
47 * entries and things would get messy with tree-like approach. So we
48 * do different trick: root directory is completely special and
49 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
50 * and we'll try to use custom find_entry function.
52 * \author Pavel Machek <pavel@ucw.cz>
60 #include <fcntl.h> /* include fcntl.h -> sys/fcntl.h only */
61 /* includes fcntl.h see IEEE Std 1003.1-2008 */
63 #include <sys/time.h> /* gettimeofday() */
64 #include <inttypes.h> /* uintmax_t */
67 #include "lib/global.h"
69 #include "lib/tty/tty.h" /* enable/disable interrupt key */
70 #include "lib/util.h" /* concat_dir_and_file */
72 #include "lib/widget.h" /* message() */
77 #include "xdirentry.h"
78 #include "gc.h" /* vfs_rmstamp */
80 /*** global variables ****************************************************************************/
82 /*** file scope macro definitions ****************************************************************/
84 #define CALL(x) if (MEDATA->x) MEDATA->x
86 /*** file scope type declarations ****************************************************************/
91 struct vfs_s_inode
*dir
;
94 /*** file scope variables ************************************************************************/
96 static volatile int total_inodes
= 0, total_entries
= 0;
98 /*** file scope functions ************************************************************************/
99 /* --------------------------------------------------------------------------------------------- */
102 vfs_s_entry_compare (const void *a
, const void *b
)
104 const struct vfs_s_entry
*e
= (const struct vfs_s_entry
*) a
;
105 const char *name
= (const char *) b
;
107 return strcmp (e
->name
, name
);
110 /* --------------------------------------------------------------------------------------------- */
113 vfs_s_free_inode (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
116 vfs_die ("Don't pass NULL to me");
118 /* ==0 can happen if freshly created entry is deleted */
119 if (ino
->st
.st_nlink
> 1)
125 while (ino
->subdir
!= NULL
)
126 vfs_s_free_entry (me
, (struct vfs_s_entry
*) ino
->subdir
->data
);
128 CALL (free_inode
) (me
, ino
);
129 g_free (ino
->linkname
);
130 if (ino
->localname
!= NULL
)
132 unlink (ino
->localname
);
133 g_free (ino
->localname
);
136 ino
->super
->ino_usage
--;
140 /* --------------------------------------------------------------------------------------------- */
141 /* We were asked to create entries automagically */
143 static struct vfs_s_entry
*
144 vfs_s_automake (struct vfs_class
*me
, struct vfs_s_inode
*dir
, char *path
, int flags
)
146 struct vfs_s_entry
*res
;
149 sep
= strchr (path
, PATH_SEP
);
153 res
= vfs_s_generate_entry (me
, path
, dir
, flags
& FL_MKDIR
? (0777 | S_IFDIR
) : 0777);
154 vfs_s_insert_entry (me
, dir
, res
);
162 /* --------------------------------------------------------------------------------------------- */
163 /* If the entry is a symlink, find the entry for its target */
165 static struct vfs_s_entry
*
166 vfs_s_resolve_symlink (struct vfs_class
*me
, struct vfs_s_entry
*entry
, int follow
)
169 char *fullname
= NULL
;
170 struct vfs_s_entry
*target
;
172 if (follow
== LINK_NO_FOLLOW
)
175 ERRNOR (ELOOP
, NULL
);
177 ERRNOR (ENOENT
, NULL
);
178 if (!S_ISLNK (entry
->ino
->st
.st_mode
))
181 linkname
= entry
->ino
->linkname
;
182 if (linkname
== NULL
)
183 ERRNOR (EFAULT
, NULL
);
185 /* make full path from relative */
186 if (*linkname
!= PATH_SEP
)
188 char *fullpath
= vfs_s_fullpath (me
, entry
->dir
);
191 fullname
= g_strconcat (fullpath
, "/", linkname
, (char *) NULL
);
197 target
= (MEDATA
->find_entry
) (me
, entry
->dir
->super
->root
, linkname
, follow
- 1, 0);
202 /* --------------------------------------------------------------------------------------------- */
204 * Follow > 0: follow links, serves as loop protect,
205 * == -1: do not follow links
208 static struct vfs_s_entry
*
209 vfs_s_find_entry_tree (struct vfs_class
*me
, struct vfs_s_inode
*root
,
210 const char *a_path
, int follow
, int flags
)
213 struct vfs_s_entry
*ent
= NULL
;
214 char *const pathref
= g_strdup (a_path
);
215 char *path
= pathref
;
217 /* canonicalize as well, but don't remove '../' from path */
218 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
224 while (*path
== PATH_SEP
) /* Strip leading '/' */
233 for (pseg
= 0; path
[pseg
] != '\0' && path
[pseg
] != PATH_SEP
; pseg
++)
236 for (iter
= root
->subdir
; iter
!= NULL
; iter
= g_list_next (iter
))
238 ent
= (struct vfs_s_entry
*) iter
->data
;
239 if (strlen (ent
->name
) == pseg
&& strncmp (ent
->name
, path
, pseg
) == 0)
244 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
246 if (ent
== NULL
&& (flags
& (FL_MKFILE
| FL_MKDIR
)) != 0)
247 ent
= vfs_s_automake (me
, root
, path
, flags
);
255 /* here we must follow leading directories always;
256 only the actual file is optional */
257 ent
= vfs_s_resolve_symlink (me
, ent
,
258 strchr (path
, PATH_SEP
) != NULL
? LINK_FOLLOW
: follow
);
268 /* --------------------------------------------------------------------------------------------- */
271 split_dir_name (struct vfs_class
*me
, char *path
, char **dir
, char **name
, char **save
)
277 s
= strrchr (path
, PATH_SEP
);
282 *dir
= path
+ strlen (path
); /* an empty string */
293 /* --------------------------------------------------------------------------------------------- */
295 static struct vfs_s_entry
*
296 vfs_s_find_entry_linear (struct vfs_class
*me
, struct vfs_s_inode
*root
,
297 const char *a_path
, int follow
, int flags
)
299 struct vfs_s_entry
*ent
= NULL
;
300 char *const path
= g_strdup (a_path
);
301 struct vfs_s_entry
*retval
= NULL
;
304 if (root
->super
->root
!= root
)
305 vfs_die ("We have to use _real_ root. Always. Sorry.");
307 /* canonicalize as well, but don't remove '../' from path */
308 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
310 if ((flags
& FL_DIR
) == 0)
312 char *dirname
, *name
, *save
;
313 struct vfs_s_inode
*ino
;
314 split_dir_name (me
, path
, &dirname
, &name
, &save
);
315 ino
= vfs_s_find_inode (me
, root
->super
, dirname
, follow
, flags
| FL_DIR
);
318 retval
= vfs_s_find_entry_tree (me
, ino
, name
, follow
, flags
);
323 iter
= g_list_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
324 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
326 if (ent
!= NULL
&& !MEDATA
->dir_uptodate (me
, ent
->ino
))
329 vfs_print_message (_("Directory cache expired for %s"), path
);
331 vfs_s_free_entry (me
, ent
);
337 struct vfs_s_inode
*ino
;
339 ino
= vfs_s_new_inode (me
, root
->super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
340 ent
= vfs_s_new_entry (me
, path
, ino
);
341 if (MEDATA
->dir_load (me
, ino
, path
) == -1)
343 vfs_s_free_entry (me
, ent
);
348 vfs_s_insert_entry (me
, root
, ent
);
350 iter
= g_list_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
351 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
354 vfs_die ("find_linear: success but directory is not there\n");
357 if (!vfs_s_resolve_symlink (me
, ent
, follow
))
367 /* --------------------------------------------------------------------------------------------- */
368 /* Ook, these were functions around directory entries / inodes */
369 /* -------------------------------- superblock games -------------------------- */
371 static struct vfs_s_super
*
372 vfs_s_new_super (struct vfs_class
*me
)
374 struct vfs_s_super
*super
;
376 super
= g_new0 (struct vfs_s_super
, 1);
381 /* --------------------------------------------------------------------------------------------- */
384 vfs_s_insert_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
386 MEDATA
->supers
= g_list_prepend (MEDATA
->supers
, super
);
389 /* --------------------------------------------------------------------------------------------- */
392 vfs_s_free_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
394 if (super
->root
!= NULL
)
396 vfs_s_free_inode (me
, super
->root
);
401 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
402 if (super
->ino_usage
)
403 message (D_ERROR
, "Direntry warning",
404 "Super ino_usage is %d, memory leak", super
->ino_usage
);
406 if (super
->want_stale
)
407 message (D_ERROR
, "Direntry warning", "%s", "Super has want_stale set");
410 MEDATA
->supers
= g_list_remove (MEDATA
->supers
, super
);
412 CALL (free_archive
) (me
, super
);
413 #ifdef ENABLE_VFS_NET
414 vfs_path_element_free (super
->path_element
);
416 g_free (super
->name
);
420 /* --------------------------------------------------------------------------------------------- */
421 /* Support of archives */
422 /* ------------------------ readdir & friends ----------------------------- */
424 static struct vfs_s_inode
*
425 vfs_s_inode_from_path (const vfs_path_t
* vpath
, int flags
)
427 struct vfs_s_super
*super
;
428 struct vfs_s_inode
*ino
;
430 vfs_path_element_t
*path_element
;
432 q
= vfs_s_get_path (vpath
, &super
, 0);
436 path_element
= vfs_path_get_by_index (vpath
, -1);
439 vfs_s_find_inode (path_element
->class, super
, q
,
440 flags
& FL_FOLLOW
? LINK_FOLLOW
: LINK_NO_FOLLOW
, flags
& ~FL_FOLLOW
);
442 /* We are asking about / directory of ftp server: assume it exists */
444 vfs_s_find_inode (path_element
->class, super
, q
,
445 flags
& FL_FOLLOW
? LINK_FOLLOW
:
446 LINK_NO_FOLLOW
, FL_DIR
| (flags
& ~FL_FOLLOW
));
450 /* --------------------------------------------------------------------------------------------- */
453 vfs_s_opendir (const vfs_path_t
* vpath
)
455 struct vfs_s_inode
*dir
;
456 struct dirhandle
*info
;
457 vfs_path_element_t
*path_element
;
459 path_element
= vfs_path_get_by_index (vpath
, -1);
461 dir
= vfs_s_inode_from_path (vpath
, FL_DIR
| FL_FOLLOW
);
464 if (!S_ISDIR (dir
->st
.st_mode
))
466 path_element
->class->verrno
= ENOTDIR
;
472 if (dir
->subdir
== NULL
) /* This can actually happen if we allow empty directories */
474 path_element
->class->verrno
= EAGAIN
;
478 info
= g_new (struct dirhandle
, 1);
479 info
->cur
= dir
->subdir
;
485 /* --------------------------------------------------------------------------------------------- */
488 vfs_s_readdir (void *data
)
490 static union vfs_dirent dir
;
491 struct dirhandle
*info
= (struct dirhandle
*) data
;
494 if (info
->cur
== NULL
|| info
->cur
->data
== NULL
)
497 name
= ((struct vfs_s_entry
*) info
->cur
->data
)->name
;
499 g_strlcpy (dir
.dent
.d_name
, name
, MC_MAXPATHLEN
);
501 vfs_die ("Null in structure-cannot happen");
503 compute_namelen (&dir
.dent
);
504 info
->cur
= g_list_next (info
->cur
);
506 return (void *) &dir
;
509 /* --------------------------------------------------------------------------------------------- */
512 vfs_s_closedir (void *data
)
514 struct dirhandle
*info
= (struct dirhandle
*) data
;
515 struct vfs_s_inode
*dir
= info
->dir
;
517 vfs_s_free_inode (dir
->super
->me
, dir
);
522 /* --------------------------------------------------------------------------------------------- */
525 vfs_s_chdir (const vfs_path_t
* vpath
)
529 data
= vfs_s_opendir (vpath
);
532 vfs_s_closedir (data
);
536 /* --------------------------------------------------------------------------------------------- */
537 /* --------------------------- stat and friends ---------------------------- */
540 vfs_s_internal_stat (const vfs_path_t
* vpath
, struct stat
*buf
, int flag
)
542 struct vfs_s_inode
*ino
;
544 ino
= vfs_s_inode_from_path (vpath
, flag
);
551 /* --------------------------------------------------------------------------------------------- */
554 vfs_s_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
556 return vfs_s_internal_stat (vpath
, buf
, FL_FOLLOW
);
559 /* --------------------------------------------------------------------------------------------- */
562 vfs_s_lstat (const vfs_path_t
* vpath
, struct stat
*buf
)
564 return vfs_s_internal_stat (vpath
, buf
, FL_NONE
);
567 /* --------------------------------------------------------------------------------------------- */
570 vfs_s_fstat (void *fh
, struct stat
*buf
)
576 /* --------------------------------------------------------------------------------------------- */
579 vfs_s_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
581 struct vfs_s_inode
*ino
;
583 vfs_path_element_t
*path_element
;
585 path_element
= vfs_path_get_by_index (vpath
, -1);
587 ino
= vfs_s_inode_from_path (vpath
, 0);
591 if (!S_ISLNK (ino
->st
.st_mode
))
593 path_element
->class->verrno
= EINVAL
;
597 if (ino
->linkname
== NULL
)
599 path_element
->class->verrno
= EFAULT
;
603 len
= strlen (ino
->linkname
);
606 /* readlink() does not append a NUL character to buf */
607 memcpy (buf
, ino
->linkname
, len
);
611 /* --------------------------------------------------------------------------------------------- */
614 vfs_s_read (void *fh
, char *buffer
, size_t count
)
617 struct vfs_class
*me
= FH_SUPER
->me
;
619 if (FH
->linear
== LS_LINEAR_PREOPEN
)
621 if (!MEDATA
->linear_start (me
, FH
, FH
->pos
))
625 if (FH
->linear
== LS_LINEAR_CLOSED
)
626 vfs_die ("linear_start() did not set linear_state!");
628 if (FH
->linear
== LS_LINEAR_OPEN
)
629 return MEDATA
->linear_read (me
, FH
, buffer
, count
);
631 if (FH
->handle
!= -1)
633 n
= read (FH
->handle
, buffer
, count
);
638 vfs_die ("vfs_s_read: This should not happen\n");
642 /* --------------------------------------------------------------------------------------------- */
645 vfs_s_write (void *fh
, const char *buffer
, size_t count
)
648 struct vfs_class
*me
= FH_SUPER
->me
;
651 vfs_die ("no writing to linear files, please");
654 if (FH
->handle
!= -1)
656 n
= write (FH
->handle
, buffer
, count
);
661 vfs_die ("vfs_s_write: This should not happen\n");
665 /* --------------------------------------------------------------------------------------------- */
668 vfs_s_lseek (void *fh
, off_t offset
, int whence
)
670 off_t size
= FH
->ino
->st
.st_size
;
672 if (FH
->linear
== LS_LINEAR_OPEN
)
673 vfs_die ("cannot lseek() after linear_read!");
675 if (FH
->handle
!= -1)
676 { /* If we have local file opened, we want to work with it */
677 off_t retval
= lseek (FH
->handle
, offset
, whence
);
679 FH
->ino
->super
->me
->verrno
= errno
;
694 else if (offset
< size
)
701 /* --------------------------------------------------------------------------------------------- */
704 vfs_s_close (void *fh
)
707 struct vfs_class
*me
= FH_SUPER
->me
;
709 FH_SUPER
->fd_usage
--;
710 if (!FH_SUPER
->fd_usage
)
711 vfs_stamp_create (me
, FH_SUPER
);
713 if (FH
->linear
== LS_LINEAR_OPEN
)
714 MEDATA
->linear_close (me
, fh
);
715 if (MEDATA
->fh_close
)
716 res
= MEDATA
->fh_close (me
, fh
);
717 if (FH
->changed
&& MEDATA
->file_store
)
719 char *s
= vfs_s_fullpath (me
, FH
->ino
);
724 res
= MEDATA
->file_store (me
, fh
, s
, FH
->ino
->localname
);
727 vfs_s_invalidate (me
, FH_SUPER
);
729 if (FH
->handle
!= -1)
732 vfs_s_free_inode (me
, FH
->ino
);
733 if (MEDATA
->fh_free_data
!= NULL
)
734 MEDATA
->fh_free_data (fh
);
739 /* --------------------------------------------------------------------------------------------- */
742 vfs_s_print_stats (const char *fs_name
, const char *action
,
743 const char *file_name
, off_t have
, off_t need
)
745 static const char *i18n_percent_transf_format
= NULL
;
746 static const char *i18n_transf_format
= NULL
;
748 if (i18n_percent_transf_format
== NULL
)
750 i18n_percent_transf_format
= "%s: %s: %s %3d%% (%" PRIuMAX
" %s";
751 i18n_transf_format
= "%s: %s: %s %" PRIuMAX
" %s";
755 vfs_print_message (i18n_percent_transf_format
, fs_name
, action
,
756 file_name
, (int) ((double) have
* 100 / need
), (uintmax_t) have
,
757 _("bytes transferred"));
759 vfs_print_message (i18n_transf_format
, fs_name
, action
, file_name
, (uintmax_t) have
,
760 _("bytes transferred"));
763 /* --------------------------------------------------------------------------------------------- */
764 /* ------------------------------- mc support ---------------------------- */
767 vfs_s_fill_names (struct vfs_class
*me
, fill_names_f func
)
771 for (iter
= MEDATA
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
773 const struct vfs_s_super
*super
= (const struct vfs_s_super
*) iter
->data
;
776 name
= g_strconcat (super
->name
, "/", me
->prefix
, VFS_PATH_URL_DELIMITER
,
777 /* super->current_dir->name, */ (char *) NULL
);
783 /* --------------------------------------------------------------------------------------------- */
786 vfs_s_ferrno (struct vfs_class
*me
)
791 /* --------------------------------------------------------------------------------------------- */
793 * Get local copy of the given file. We reuse the existing file cache
794 * for remote filesystems. Archives use standard VFS facilities.
798 vfs_s_getlocalcopy (const vfs_path_t
* vpath
)
800 vfs_file_handler_t
*fh
;
803 fh
= vfs_s_open (vpath
, O_RDONLY
, 0);
807 if ((fh
->ino
!= NULL
) && (fh
->ino
->localname
!= NULL
))
808 local
= g_strdup (fh
->ino
->localname
);
816 /* --------------------------------------------------------------------------------------------- */
818 * Return the local copy. Since we are using our cache, we do nothing -
819 * the cache will be removed when the archive is closed.
823 vfs_s_ungetlocalcopy (const vfs_path_t
* vpath
, const char *local
, int has_changed
)
831 /* --------------------------------------------------------------------------------------------- */
834 vfs_s_setctl (const vfs_path_t
* vpath
, int ctlop
, void *arg
)
836 vfs_path_element_t
*path_element
;
838 path_element
= vfs_path_get_by_index (vpath
, -1);
841 case VFS_SETCTL_STALE_DATA
:
843 struct vfs_s_inode
*ino
= vfs_s_inode_from_path (vpath
, 0);
848 ino
->super
->want_stale
= 1;
851 ino
->super
->want_stale
= 0;
852 vfs_s_invalidate (path_element
->class, ino
->super
);
856 case VFS_SETCTL_LOGFILE
:
857 ((struct vfs_s_subclass
*) path_element
->class->data
)->logfile
= fopen ((char *) arg
, "w");
859 case VFS_SETCTL_FLUSH
:
860 ((struct vfs_s_subclass
*) path_element
->class->data
)->flush
= 1;
866 /* --------------------------------------------------------------------------------------------- */
867 /* ----------------------------- Stamping support -------------------------- */
870 vfs_s_getid (const vfs_path_t
* vpath
)
872 struct vfs_s_super
*archive
= NULL
;
875 p
= vfs_s_get_path (vpath
, &archive
, FL_NO_OPEN
);
879 return (vfsid
) archive
;
882 /* --------------------------------------------------------------------------------------------- */
885 vfs_s_nothingisopen (vfsid id
)
888 /* Our data structures should survive free of superblock at any time */
892 /* --------------------------------------------------------------------------------------------- */
895 vfs_s_free (vfsid id
)
897 vfs_s_free_super (((struct vfs_s_super
*) id
)->me
, (struct vfs_s_super
*) id
);
900 /* --------------------------------------------------------------------------------------------- */
903 vfs_s_dir_uptodate (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
913 gettimeofday (&tim
, NULL
);
914 if (tim
.tv_sec
< ino
->timestamp
.tv_sec
)
920 /* --------------------------------------------------------------------------------------------- */
921 /*** public functions ****************************************************************************/
922 /* --------------------------------------------------------------------------------------------- */
925 vfs_s_new_inode (struct vfs_class
*me
, struct vfs_s_super
*super
, struct stat
*initstat
)
927 struct vfs_s_inode
*ino
;
929 ino
= g_try_new0 (struct vfs_s_inode
, 1);
936 ino
->st
.st_nlink
= 0;
937 ino
->st
.st_ino
= MEDATA
->inode_counter
++;
938 ino
->st
.st_dev
= MEDATA
->rdev
;
943 CALL (init_inode
) (me
, ino
);
948 /* --------------------------------------------------------------------------------------------- */
951 vfs_s_new_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*inode
)
953 struct vfs_s_entry
*entry
;
955 entry
= g_new0 (struct vfs_s_entry
, 1);
958 entry
->name
= g_strdup (name
);
960 entry
->ino
->ent
= entry
;
961 CALL (init_entry
) (me
, entry
);
967 /* --------------------------------------------------------------------------------------------- */
970 vfs_s_free_entry (struct vfs_class
*me
, struct vfs_s_entry
*ent
)
972 if (ent
->dir
!= NULL
)
973 ent
->dir
->subdir
= g_list_remove (ent
->dir
->subdir
, ent
);
976 /* ent->name = NULL; */
978 if (ent
->ino
!= NULL
)
980 ent
->ino
->ent
= NULL
;
981 vfs_s_free_inode (me
, ent
->ino
);
988 /* --------------------------------------------------------------------------------------------- */
991 vfs_s_insert_entry (struct vfs_class
*me
, struct vfs_s_inode
*dir
, struct vfs_s_entry
*ent
)
997 ent
->ino
->st
.st_nlink
++;
998 dir
->subdir
= g_list_append (dir
->subdir
, ent
);
1001 /* --------------------------------------------------------------------------------------------- */
1004 vfs_s_default_stat (struct vfs_class
*me
, mode_t mode
)
1006 static struct stat st
;
1011 myumask
= umask (022);
1019 st
.st_uid
= getuid ();
1020 st
.st_gid
= getgid ();
1022 st
.st_mtime
= st
.st_atime
= st
.st_ctime
= time (NULL
);
1027 /* --------------------------------------------------------------------------------------------- */
1029 struct vfs_s_entry
*
1030 vfs_s_generate_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*parent
,
1033 struct vfs_s_inode
*inode
;
1036 st
= vfs_s_default_stat (me
, mode
);
1037 inode
= vfs_s_new_inode (me
, parent
->super
, st
);
1039 return vfs_s_new_entry (me
, name
, inode
);
1042 /* --------------------------------------------------------------------------------------------- */
1044 struct vfs_s_inode
*
1045 vfs_s_find_inode (struct vfs_class
*me
, const struct vfs_s_super
*super
,
1046 const char *path
, int follow
, int flags
)
1048 struct vfs_s_entry
*ent
;
1050 if (((MEDATA
->flags
& VFS_S_REMOTE
) == 0) && (*path
== '\0'))
1053 ent
= (MEDATA
->find_entry
) (me
, super
->root
, path
, follow
, flags
);
1054 return (ent
!= NULL
) ? ent
->ino
: NULL
;
1057 /* --------------------------------------------------------------------------------------------- */
1058 /* Ook, these were functions around directory entries / inodes */
1059 /* -------------------------------- superblock games -------------------------- */
1061 * get path from last VFS-element and create corresponding superblock
1063 * @param vpath source path object
1064 * @param archive pointer to object for store newly created superblock
1065 * @param flags flags
1067 * @return path from last VFS-element
1070 vfs_s_get_path (const vfs_path_t
* vpath
, struct vfs_s_super
**archive
, int flags
)
1075 struct vfs_s_super
*super
;
1076 void *cookie
= NULL
;
1077 vfs_path_element_t
*path_element
;
1078 vfs_path_t
*vpath_archive
;
1079 struct vfs_s_subclass
*subclass
;
1081 path_element
= vfs_path_get_by_index (vpath
, -1);
1082 subclass
= ((struct vfs_s_subclass
*) path_element
->class->data
);
1084 vpath_archive
= vfs_path_clone (vpath
);
1085 vfs_path_remove_element_by_index (vpath_archive
, -1);
1087 retval
= (path_element
->path
!= NULL
) ? path_element
->path
: "";
1089 if (subclass
->archive_check
!= NULL
)
1091 cookie
= subclass
->archive_check (vpath_archive
);
1094 vfs_path_free (vpath_archive
);
1099 for (iter
= subclass
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
1103 super
= (struct vfs_s_super
*) iter
->data
;
1105 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1106 i
= subclass
->archive_same (path_element
, super
, vpath_archive
, cookie
);
1110 goto return_success
;
1115 if (flags
& FL_NO_OPEN
)
1117 path_element
->class->verrno
= EIO
;
1118 vfs_path_free (vpath_archive
);
1122 super
= vfs_s_new_super (path_element
->class);
1123 if (subclass
->open_archive
!= NULL
)
1124 result
= subclass
->open_archive (super
, vpath_archive
, path_element
);
1127 vfs_s_free_super (path_element
->class, super
);
1128 path_element
->class->verrno
= EIO
;
1129 vfs_path_free (vpath_archive
);
1133 vfs_die ("You have to fill name\n");
1135 vfs_die ("You have to fill root inode\n");
1137 vfs_s_insert_super (path_element
->class, super
);
1138 vfs_stamp_create (path_element
->class, super
);
1142 vfs_path_free (vpath_archive
);
1146 /* --------------------------------------------------------------------------------------------- */
1149 vfs_s_invalidate (struct vfs_class
*me
, struct vfs_s_super
*super
)
1151 if (!super
->want_stale
)
1153 vfs_s_free_inode (me
, super
->root
);
1154 super
->root
= vfs_s_new_inode (me
, super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
1158 /* --------------------------------------------------------------------------------------------- */
1161 vfs_s_fullpath (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1164 ERRNOR (EAGAIN
, NULL
);
1166 if (!(MEDATA
->flags
& VFS_S_REMOTE
))
1170 char *path
= g_strdup (ino
->ent
->name
);
1173 ino
= ino
->ent
->dir
;
1174 if (ino
== ino
->super
->root
)
1176 newpath
= g_strconcat (ino
->ent
->name
, "/", path
, (char *) NULL
);
1183 /* remote systems */
1184 if ((!ino
->ent
->dir
) || (!ino
->ent
->dir
->ent
))
1185 return g_strdup (ino
->ent
->name
);
1187 return g_strconcat (ino
->ent
->dir
->ent
->name
, PATH_SEP_STR
, ino
->ent
->name
, (char *) NULL
);
1190 /* --------------------------------------------------------------------------------------------- */
1191 /* --------------------------- stat and friends ---------------------------- */
1194 vfs_s_open (const vfs_path_t
* vpath
, int flags
, mode_t mode
)
1196 int was_changed
= 0;
1197 vfs_file_handler_t
*fh
;
1198 struct vfs_s_super
*super
;
1200 struct vfs_s_inode
*ino
;
1201 vfs_path_element_t
*path_element
;
1203 path_element
= vfs_path_get_by_index (vpath
, -1);
1205 q
= vfs_s_get_path (vpath
, &super
, 0);
1208 ino
= vfs_s_find_inode (path_element
->class, super
, q
, LINK_FOLLOW
, FL_NONE
);
1209 if (ino
&& ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
)))
1211 path_element
->class->verrno
= EEXIST
;
1216 char *dirname
, *name
, *save
, *q_mangle
;
1217 struct vfs_s_entry
*ent
;
1218 struct vfs_s_inode
*dir
;
1221 /* If the filesystem is read-only, disable file creation */
1222 if (!(flags
& O_CREAT
) || !(path_element
->class->write
))
1225 q_mangle
= g_strdup (q
);
1226 split_dir_name (path_element
->class, q_mangle
, &dirname
, &name
, &save
);
1227 dir
= vfs_s_find_inode (path_element
->class, super
, dirname
, LINK_FOLLOW
, FL_DIR
);
1235 ent
= vfs_s_generate_entry (path_element
->class, name
, dir
, 0755);
1237 vfs_s_insert_entry (path_element
->class, dir
, ent
);
1238 tmp_handle
= vfs_mkstemps (&ino
->localname
, path_element
->class->name
, name
);
1240 if (tmp_handle
== -1)
1247 if (S_ISDIR (ino
->st
.st_mode
))
1249 path_element
->class->verrno
= EISDIR
;
1253 fh
= g_new (vfs_file_handler_t
, 1);
1257 fh
->changed
= was_changed
;
1261 if (IS_LINEAR (flags
))
1263 if (VFSDATA (path_element
)->linear_start
)
1265 vfs_print_message (_("Starting linear transfer..."));
1266 fh
->linear
= LS_LINEAR_PREOPEN
;
1271 struct vfs_s_subclass
*s
;
1273 s
= VFSDATA (path_element
);
1274 if (s
->fh_open
!= NULL
&& s
->fh_open (path_element
->class, fh
, flags
, mode
) != 0)
1276 if (s
->fh_free_data
!= NULL
)
1277 s
->fh_free_data (fh
);
1283 if (fh
->ino
->localname
)
1285 fh
->handle
= open (fh
->ino
->localname
, NO_LINEAR (flags
), mode
);
1286 if (fh
->handle
== -1)
1289 path_element
->class->verrno
= errno
;
1294 /* i.e. we had no open files and now we have one */
1295 vfs_rmstamp (path_element
->class, (vfsid
) super
);
1297 fh
->ino
->st
.st_nlink
++;
1301 /* --------------------------------------------------------------------------------------------- */
1304 vfs_s_retrieve_file (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1306 /* If you want reget, you'll have to open file with O_LINEAR */
1310 off_t stat_size
= ino
->st
.st_size
;
1311 vfs_file_handler_t fh
;
1313 memset (&fh
, 0, sizeof (fh
));
1318 handle
= vfs_mkstemps (&ino
->localname
, me
->name
, ino
->ent
->name
);
1325 if (!MEDATA
->linear_start (me
, &fh
, 0))
1328 /* Clear the interrupt status */
1329 tty_got_interrupt ();
1330 tty_enable_interrupt_key ();
1332 while ((n
= MEDATA
->linear_read (me
, &fh
, buffer
, sizeof (buffer
))))
1339 vfs_s_print_stats (me
->name
, _("Getting file"), ino
->ent
->name
, total
, stat_size
);
1341 if (tty_got_interrupt ())
1344 t
= write (handle
, buffer
, n
);
1352 MEDATA
->linear_close (me
, &fh
);
1355 tty_disable_interrupt_key ();
1360 MEDATA
->linear_close (me
, &fh
);
1362 tty_disable_interrupt_key ();
1364 unlink (ino
->localname
);
1366 g_free (ino
->localname
);
1367 ino
->localname
= NULL
;
1372 /* --------------------------------------------------------------------------------------------- */
1373 /* ----------------------------- Stamping support -------------------------- */
1375 /* Initialize one of our subclasses - fill common functions */
1377 vfs_s_init_class (struct vfs_class
*vclass
, struct vfs_s_subclass
*sub
)
1380 vclass
->fill_names
= vfs_s_fill_names
;
1381 vclass
->open
= vfs_s_open
;
1382 vclass
->close
= vfs_s_close
;
1383 vclass
->read
= vfs_s_read
;
1384 if (!(sub
->flags
& VFS_S_READONLY
))
1386 vclass
->write
= vfs_s_write
;
1388 vclass
->opendir
= vfs_s_opendir
;
1389 vclass
->readdir
= vfs_s_readdir
;
1390 vclass
->closedir
= vfs_s_closedir
;
1391 vclass
->stat
= vfs_s_stat
;
1392 vclass
->lstat
= vfs_s_lstat
;
1393 vclass
->fstat
= vfs_s_fstat
;
1394 vclass
->readlink
= vfs_s_readlink
;
1395 vclass
->chdir
= vfs_s_chdir
;
1396 vclass
->ferrno
= vfs_s_ferrno
;
1397 vclass
->lseek
= vfs_s_lseek
;
1398 vclass
->getid
= vfs_s_getid
;
1399 vclass
->nothingisopen
= vfs_s_nothingisopen
;
1400 vclass
->free
= vfs_s_free
;
1401 if (sub
->flags
& VFS_S_REMOTE
)
1403 vclass
->getlocalcopy
= vfs_s_getlocalcopy
;
1404 vclass
->ungetlocalcopy
= vfs_s_ungetlocalcopy
;
1405 sub
->find_entry
= vfs_s_find_entry_linear
;
1409 sub
->find_entry
= vfs_s_find_entry_tree
;
1411 vclass
->setctl
= vfs_s_setctl
;
1412 sub
->dir_uptodate
= vfs_s_dir_uptodate
;
1415 /* --------------------------------------------------------------------------------------------- */
1416 /** Find VFS id for given directory name */
1419 vfs_getid (const vfs_path_t
* vpath
)
1421 vfs_path_element_t
*path_element
;
1423 path_element
= vfs_path_get_by_index (vpath
, -1);
1424 if (!vfs_path_element_valid (path_element
) || path_element
->class->getid
== NULL
)
1427 return (*path_element
->class->getid
) (vpath
);
1430 /* --------------------------------------------------------------------------------------------- */
1431 /* ----------- Utility functions for networked filesystems -------------- */
1433 #ifdef ENABLE_VFS_NET
1435 vfs_s_select_on_two (int fd1
, int fd2
)
1438 struct timeval time_out
;
1440 int maxfd
= (fd1
> fd2
? fd1
: fd2
) + 1;
1442 time_out
.tv_sec
= 1;
1443 time_out
.tv_usec
= 0;
1447 v
= select (maxfd
, &set
, 0, 0, &time_out
);
1450 if (FD_ISSET (fd1
, &set
))
1452 if (FD_ISSET (fd2
, &set
))
1457 /* --------------------------------------------------------------------------------------------- */
1460 vfs_s_get_line (struct vfs_class
*me
, int sock
, char *buf
, int buf_len
, char term
)
1462 FILE *logfile
= MEDATA
->logfile
;
1466 for (i
= 0; i
< buf_len
- 1; i
++, buf
++)
1468 if (read (sock
, buf
, sizeof (char)) <= 0)
1474 ret1
= fwrite (buf
, 1, 1, logfile
);
1475 ret2
= fflush (logfile
);
1484 /* Line is too long - terminate buffer and discard the rest of line */
1486 while (read (sock
, &c
, sizeof (c
)) > 0)
1492 ret1
= fwrite (&c
, 1, 1, logfile
);
1493 ret2
= fflush (logfile
);
1501 /* --------------------------------------------------------------------------------------------- */
1504 vfs_s_get_line_interruptible (struct vfs_class
*me
, char *buffer
, int size
, int fd
)
1511 tty_enable_interrupt_key ();
1512 for (i
= 0; i
< size
- 1; i
++)
1514 n
= read (fd
, buffer
+ i
, 1);
1515 tty_disable_interrupt_key ();
1516 if (n
== -1 && errno
== EINTR
)
1526 if (buffer
[i
] == '\n')
1532 buffer
[size
- 1] = 0;
1535 #endif /* ENABLE_VFS_NET */
1537 /* --------------------------------------------------------------------------------------------- */
1539 * Normalize filenames start position
1543 vfs_s_normalize_filename_leading_spaces (struct vfs_s_inode
*root_inode
, size_t final_num_spaces
)
1547 for (iter
= root_inode
->subdir
; iter
!= NULL
; iter
= g_list_next (iter
))
1549 struct vfs_s_entry
*entry
= (struct vfs_s_entry
*) iter
->data
;
1550 if ((size_t) entry
->ino
->data_offset
> final_num_spaces
)
1552 char *source_name
= entry
->name
;
1553 char *spacer
= g_strnfill (entry
->ino
->data_offset
- final_num_spaces
, ' ');
1554 entry
->name
= g_strdup_printf ("%s%s", spacer
, source_name
);
1556 g_free (source_name
);
1558 entry
->ino
->data_offset
= -1;
1562 /* --------------------------------------------------------------------------------------------- */