2 Directory cache support
4 Copyright (C) 1998-2018
5 Free Software Foundation, Inc.
8 Pavel Machek <pavel@ucw.cz>, 1998
9 Slava Zanko <slavazanko@gmail.com>, 2013
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 \warning Paths here do _not_ begin with '/', so root directory of
27 archive/site is simply "".
31 * \brief Source: directory cache support
33 * So that you do not have copy of this in each and every filesystem.
35 * Very loosely based on tar.c from midnight and archives.[ch] from
36 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
38 * Unfortunately, I was unable to keep all filesystems
39 * uniform. tar-like filesystems use tree structure where each
40 * directory has pointers to its subdirectories. We can do this
41 * because we have full information about our archive.
43 * At ftp-like filesystems, situation is a little bit different. When
44 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
45 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
46 * listed. That means that we do not have complete information, and if
47 * /usr is symlink to /4, we will not know. Also we have to time out
48 * entries and things would get messy with tree-like approach. So we
49 * do different trick: root directory is completely special and
50 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
51 * and we'll try to use custom find_entry function.
53 * \author Pavel Machek <pavel@ucw.cz>
62 #include <sys/time.h> /* gettimeofday() */
63 #include <inttypes.h> /* uintmax_t */
66 #include "lib/global.h"
68 #include "lib/tty/tty.h" /* enable/disable interrupt key */
69 #include "lib/util.h" /* custom_canonicalize_pathname() */
71 #include "lib/widget.h" /* message() */
76 #include "xdirentry.h"
77 #include "gc.h" /* vfs_rmstamp */
79 /*** global variables ****************************************************************************/
81 /*** file scope macro definitions ****************************************************************/
83 #define CALL(x) if (MEDATA->x) MEDATA->x
85 /*** file scope type declarations ****************************************************************/
90 struct vfs_s_inode
*dir
;
93 /*** file scope variables ************************************************************************/
95 /*** file scope functions ************************************************************************/
96 /* --------------------------------------------------------------------------------------------- */
99 vfs_s_entry_compare (const void *a
, const void *b
)
101 const struct vfs_s_entry
*e
= (const struct vfs_s_entry
*) a
;
102 const char *name
= (const char *) b
;
104 return strcmp (e
->name
, name
);
107 /* --------------------------------------------------------------------------------------------- */
109 /* We were asked to create entries automagically */
111 static struct vfs_s_entry
*
112 vfs_s_automake (struct vfs_class
*me
, struct vfs_s_inode
*dir
, char *path
, int flags
)
114 struct vfs_s_entry
*res
;
117 sep
= strchr (path
, PATH_SEP
);
121 res
= vfs_s_generate_entry (me
, path
, dir
, (flags
& FL_MKDIR
) != 0 ? (0777 | S_IFDIR
) : 0777);
122 vfs_s_insert_entry (me
, dir
, res
);
130 /* --------------------------------------------------------------------------------------------- */
131 /* If the entry is a symlink, find the entry for its target */
133 static struct vfs_s_entry
*
134 vfs_s_resolve_symlink (struct vfs_class
*me
, struct vfs_s_entry
*entry
, int follow
)
137 char *fullname
= NULL
;
138 struct vfs_s_entry
*target
;
140 if (follow
== LINK_NO_FOLLOW
)
143 ERRNOR (ELOOP
, NULL
);
145 ERRNOR (ENOENT
, NULL
);
146 if (!S_ISLNK (entry
->ino
->st
.st_mode
))
149 linkname
= entry
->ino
->linkname
;
150 if (linkname
== NULL
)
151 ERRNOR (EFAULT
, NULL
);
153 /* make full path from relative */
154 if (!IS_PATH_SEP (*linkname
))
158 fullpath
= vfs_s_fullpath (me
, entry
->dir
);
159 if (fullpath
!= NULL
)
161 fullname
= g_strconcat (fullpath
, PATH_SEP_STR
, linkname
, (char *) NULL
);
167 target
= MEDATA
->find_entry (me
, entry
->dir
->super
->root
, linkname
, follow
- 1, 0);
172 /* --------------------------------------------------------------------------------------------- */
174 * Follow > 0: follow links, serves as loop protect,
175 * == -1: do not follow links
178 static struct vfs_s_entry
*
179 vfs_s_find_entry_tree (struct vfs_class
*me
, struct vfs_s_inode
*root
,
180 const char *a_path
, int follow
, int flags
)
183 struct vfs_s_entry
*ent
= NULL
;
184 char *const pathref
= g_strdup (a_path
);
185 char *path
= pathref
;
187 /* canonicalize as well, but don't remove '../' from path */
188 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
194 while (IS_PATH_SEP (*path
)) /* Strip leading '/' */
203 for (pseg
= 0; path
[pseg
] != '\0' && !IS_PATH_SEP (path
[pseg
]); pseg
++)
206 for (iter
= root
->subdir
; iter
!= NULL
; iter
= g_list_next (iter
))
208 ent
= (struct vfs_s_entry
*) iter
->data
;
209 if (strlen (ent
->name
) == pseg
&& strncmp (ent
->name
, path
, pseg
) == 0)
214 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
216 if (ent
== NULL
&& (flags
& (FL_MKFILE
| FL_MKDIR
)) != 0)
217 ent
= vfs_s_automake (me
, root
, path
, flags
);
225 /* here we must follow leading directories always;
226 only the actual file is optional */
227 ent
= vfs_s_resolve_symlink (me
, ent
,
228 strchr (path
, PATH_SEP
) != NULL
? LINK_FOLLOW
: follow
);
238 /* --------------------------------------------------------------------------------------------- */
240 static struct vfs_s_entry
*
241 vfs_s_find_entry_linear (struct vfs_class
*me
, struct vfs_s_inode
*root
,
242 const char *a_path
, int follow
, int flags
)
244 struct vfs_s_entry
*ent
= NULL
;
245 char *const path
= g_strdup (a_path
);
248 if (root
->super
->root
!= root
)
249 vfs_die ("We have to use _real_ root. Always. Sorry.");
251 /* canonicalize as well, but don't remove '../' from path */
252 custom_canonicalize_pathname (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
254 if ((flags
& FL_DIR
) == 0)
256 char *dirname
, *name
;
257 struct vfs_s_inode
*ino
;
259 dirname
= g_path_get_dirname (path
);
260 name
= g_path_get_basename (path
);
261 ino
= vfs_s_find_inode (me
, root
->super
, dirname
, follow
, flags
| FL_DIR
);
262 ent
= vfs_s_find_entry_tree (me
, ino
, name
, follow
, flags
);
269 iter
= g_list_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
270 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
272 if (ent
!= NULL
&& !MEDATA
->dir_uptodate (me
, ent
->ino
))
275 vfs_print_message (_("Directory cache expired for %s"), path
);
277 vfs_s_free_entry (me
, ent
);
283 struct vfs_s_inode
*ino
;
285 ino
= vfs_s_new_inode (me
, root
->super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
286 ent
= vfs_s_new_entry (me
, path
, ino
);
287 if (MEDATA
->dir_load (me
, ino
, path
) == -1)
289 vfs_s_free_entry (me
, ent
);
294 vfs_s_insert_entry (me
, root
, ent
);
296 iter
= g_list_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
297 ent
= iter
!= NULL
? (struct vfs_s_entry
*) iter
->data
: NULL
;
300 vfs_die ("find_linear: success but directory is not there\n");
303 if (vfs_s_resolve_symlink (me
, ent
, follow
) == NULL
)
313 /* --------------------------------------------------------------------------------------------- */
314 /* Ook, these were functions around directory entries / inodes */
315 /* -------------------------------- superblock games -------------------------- */
317 static struct vfs_s_super
*
318 vfs_s_new_super (struct vfs_class
*me
)
320 struct vfs_s_super
*super
;
322 super
= g_new0 (struct vfs_s_super
, 1);
327 /* --------------------------------------------------------------------------------------------- */
330 vfs_s_insert_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
332 MEDATA
->supers
= g_list_prepend (MEDATA
->supers
, super
);
335 /* --------------------------------------------------------------------------------------------- */
338 vfs_s_free_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
340 if (super
->root
!= NULL
)
342 vfs_s_free_inode (me
, super
->root
);
347 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
348 if (super
->ino_usage
!= 0)
349 message (D_ERROR
, "Direntry warning",
350 "Super ino_usage is %d, memory leak", super
->ino_usage
);
352 if (super
->want_stale
)
353 message (D_ERROR
, "Direntry warning", "%s", "Super has want_stale set");
356 MEDATA
->supers
= g_list_remove (MEDATA
->supers
, super
);
358 CALL (free_archive
) (me
, super
);
359 #ifdef ENABLE_VFS_NET
360 vfs_path_element_free (super
->path_element
);
362 g_free (super
->name
);
366 /* --------------------------------------------------------------------------------------------- */
367 /* Support of archives */
368 /* ------------------------ readdir & friends ----------------------------- */
370 static struct vfs_s_inode
*
371 vfs_s_inode_from_path (const vfs_path_t
* vpath
, int flags
)
373 struct vfs_s_super
*super
;
374 struct vfs_s_inode
*ino
;
376 const vfs_path_element_t
*path_element
;
378 q
= vfs_s_get_path (vpath
, &super
, 0);
382 path_element
= vfs_path_get_by_index (vpath
, -1);
385 vfs_s_find_inode (path_element
->class, super
, q
,
386 (flags
& FL_FOLLOW
) != 0 ? LINK_FOLLOW
: LINK_NO_FOLLOW
,
388 if (ino
== NULL
&& *q
== '\0')
389 /* We are asking about / directory of ftp server: assume it exists */
391 vfs_s_find_inode (path_element
->class, super
, q
,
392 (flags
& FL_FOLLOW
) != 0 ? LINK_FOLLOW
: LINK_NO_FOLLOW
,
393 FL_DIR
| (flags
& ~FL_FOLLOW
));
397 /* --------------------------------------------------------------------------------------------- */
400 vfs_s_opendir (const vfs_path_t
* vpath
)
402 struct vfs_s_inode
*dir
;
403 struct dirhandle
*info
;
404 const vfs_path_element_t
*path_element
;
406 path_element
= vfs_path_get_by_index (vpath
, -1);
408 dir
= vfs_s_inode_from_path (vpath
, FL_DIR
| FL_FOLLOW
);
411 if (!S_ISDIR (dir
->st
.st_mode
))
413 path_element
->class->verrno
= ENOTDIR
;
419 if (dir
->subdir
== NULL
) /* This can actually happen if we allow empty directories */
421 path_element
->class->verrno
= EAGAIN
;
425 info
= g_new (struct dirhandle
, 1);
426 info
->cur
= dir
->subdir
;
432 /* --------------------------------------------------------------------------------------------- */
435 vfs_s_readdir (void *data
)
437 static union vfs_dirent dir
;
438 struct dirhandle
*info
= (struct dirhandle
*) data
;
441 if (info
->cur
== NULL
|| info
->cur
->data
== NULL
)
444 name
= ((struct vfs_s_entry
*) info
->cur
->data
)->name
;
446 g_strlcpy (dir
.dent
.d_name
, name
, MC_MAXPATHLEN
);
448 vfs_die ("Null in structure-cannot happen");
450 info
->cur
= g_list_next (info
->cur
);
452 return (void *) &dir
;
455 /* --------------------------------------------------------------------------------------------- */
458 vfs_s_closedir (void *data
)
460 struct dirhandle
*info
= (struct dirhandle
*) data
;
461 struct vfs_s_inode
*dir
= info
->dir
;
463 vfs_s_free_inode (dir
->super
->me
, dir
);
468 /* --------------------------------------------------------------------------------------------- */
471 vfs_s_chdir (const vfs_path_t
* vpath
)
475 data
= vfs_s_opendir (vpath
);
478 vfs_s_closedir (data
);
482 /* --------------------------------------------------------------------------------------------- */
483 /* --------------------------- stat and friends ---------------------------- */
486 vfs_s_internal_stat (const vfs_path_t
* vpath
, struct stat
*buf
, int flag
)
488 struct vfs_s_inode
*ino
;
490 ino
= vfs_s_inode_from_path (vpath
, flag
);
497 /* --------------------------------------------------------------------------------------------- */
500 vfs_s_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
502 struct vfs_s_inode
*ino
;
504 const vfs_path_element_t
*path_element
;
506 path_element
= vfs_path_get_by_index (vpath
, -1);
508 ino
= vfs_s_inode_from_path (vpath
, 0);
512 if (!S_ISLNK (ino
->st
.st_mode
))
514 path_element
->class->verrno
= EINVAL
;
518 if (ino
->linkname
== NULL
)
520 path_element
->class->verrno
= EFAULT
;
524 len
= strlen (ino
->linkname
);
527 /* readlink() does not append a NUL character to buf */
528 memcpy (buf
, ino
->linkname
, len
);
532 /* --------------------------------------------------------------------------------------------- */
535 vfs_s_read (void *fh
, char *buffer
, size_t count
)
537 struct vfs_class
*me
= FH_SUPER
->me
;
539 if (FH
->linear
== LS_LINEAR_PREOPEN
)
541 if (MEDATA
->linear_start (me
, FH
, FH
->pos
) == 0)
545 if (FH
->linear
== LS_LINEAR_CLOSED
)
546 vfs_die ("linear_start() did not set linear_state!");
548 if (FH
->linear
== LS_LINEAR_OPEN
)
549 return MEDATA
->linear_read (me
, FH
, buffer
, count
);
551 if (FH
->handle
!= -1)
555 n
= read (FH
->handle
, buffer
, count
);
560 vfs_die ("vfs_s_read: This should not happen\n");
564 /* --------------------------------------------------------------------------------------------- */
567 vfs_s_write (void *fh
, const char *buffer
, size_t count
)
569 struct vfs_class
*me
= FH_SUPER
->me
;
572 vfs_die ("no writing to linear files, please");
575 if (FH
->handle
!= -1)
579 n
= write (FH
->handle
, buffer
, count
);
584 vfs_die ("vfs_s_write: This should not happen\n");
588 /* --------------------------------------------------------------------------------------------- */
591 vfs_s_lseek (void *fh
, off_t offset
, int whence
)
593 off_t size
= FH
->ino
->st
.st_size
;
595 if (FH
->linear
== LS_LINEAR_OPEN
)
596 vfs_die ("cannot lseek() after linear_read!");
598 if (FH
->handle
!= -1)
599 { /* If we have local file opened, we want to work with it */
602 retval
= lseek (FH
->handle
, offset
, whence
);
604 FH
->ino
->super
->me
->verrno
= errno
;
621 else if (offset
< size
)
628 /* --------------------------------------------------------------------------------------------- */
631 vfs_s_close (void *fh
)
634 struct vfs_class
*me
= FH_SUPER
->me
;
639 FH_SUPER
->fd_usage
--;
640 if (FH_SUPER
->fd_usage
== 0)
641 vfs_stamp_create (me
, FH_SUPER
);
643 if (FH
->linear
== LS_LINEAR_OPEN
)
644 MEDATA
->linear_close (me
, fh
);
645 if (MEDATA
->fh_close
!= NULL
)
646 res
= MEDATA
->fh_close (me
, fh
);
647 if ((MEDATA
->flags
& VFS_S_USETMP
) != 0 && FH
->changed
&& MEDATA
->file_store
!= NULL
)
651 s
= vfs_s_fullpath (me
, FH
->ino
);
657 res
= MEDATA
->file_store (me
, fh
, s
, FH
->ino
->localname
);
660 vfs_s_invalidate (me
, FH_SUPER
);
662 if (FH
->handle
!= -1)
665 vfs_s_free_inode (me
, FH
->ino
);
666 if (MEDATA
->fh_free_data
!= NULL
)
667 MEDATA
->fh_free_data (fh
);
672 /* --------------------------------------------------------------------------------------------- */
675 vfs_s_print_stats (const char *fs_name
, const char *action
,
676 const char *file_name
, off_t have
, off_t need
)
679 vfs_print_message (_("%s: %s: %s %3d%% (%lld) bytes transferred"), fs_name
, action
,
680 file_name
, (int) ((double) have
* 100 / need
), (long long) have
);
682 vfs_print_message (_("%s: %s: %s %lld bytes transferred"), fs_name
, action
, file_name
,
686 /* --------------------------------------------------------------------------------------------- */
687 /* ------------------------------- mc support ---------------------------- */
690 vfs_s_fill_names (struct vfs_class
*me
, fill_names_f func
)
694 for (iter
= MEDATA
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
696 const struct vfs_s_super
*super
= (const struct vfs_s_super
*) iter
->data
;
699 name
= g_strconcat (super
->name
, PATH_SEP_STR
, me
->prefix
, VFS_PATH_URL_DELIMITER
,
700 /* super->current_dir->name, */ (char *) NULL
);
706 /* --------------------------------------------------------------------------------------------- */
709 vfs_s_ferrno (struct vfs_class
*me
)
714 /* --------------------------------------------------------------------------------------------- */
716 * Get local copy of the given file. We reuse the existing file cache
717 * for remote filesystems. Archives use standard VFS facilities.
721 vfs_s_getlocalcopy (const vfs_path_t
* vpath
)
723 vfs_file_handler_t
*fh
;
724 vfs_path_t
*local
= NULL
;
729 fh
= vfs_s_open (vpath
, O_RDONLY
, 0);
733 const struct vfs_class
*me
;
735 me
= vfs_path_get_by_index (vpath
, -1)->class;
736 if ((MEDATA
->flags
& VFS_S_USETMP
) != 0 && fh
->ino
!= NULL
)
737 local
= vfs_path_from_str_flags (fh
->ino
->localname
, VPF_NO_CANON
);
745 /* --------------------------------------------------------------------------------------------- */
747 * Return the local copy. Since we are using our cache, we do nothing -
748 * the cache will be removed when the archive is closed.
752 vfs_s_ungetlocalcopy (const vfs_path_t
* vpath
, const vfs_path_t
* local
, gboolean has_changed
)
760 /* --------------------------------------------------------------------------------------------- */
763 vfs_s_setctl (const vfs_path_t
* vpath
, int ctlop
, void *arg
)
765 const vfs_path_element_t
*path_element
;
767 path_element
= vfs_path_get_by_index (vpath
, -1);
771 case VFS_SETCTL_STALE_DATA
:
773 struct vfs_s_inode
*ino
;
775 ino
= vfs_s_inode_from_path (vpath
, 0);
779 ino
->super
->want_stale
= TRUE
;
782 ino
->super
->want_stale
= FALSE
;
783 vfs_s_invalidate (path_element
->class, ino
->super
);
787 case VFS_SETCTL_LOGFILE
:
788 ((struct vfs_s_subclass
*) path_element
->class->data
)->logfile
= fopen ((char *) arg
, "w");
790 case VFS_SETCTL_FLUSH
:
791 ((struct vfs_s_subclass
*) path_element
->class->data
)->flush
= 1;
798 /* --------------------------------------------------------------------------------------------- */
799 /* ----------------------------- Stamping support -------------------------- */
802 vfs_s_getid (const vfs_path_t
* vpath
)
804 struct vfs_s_super
*archive
= NULL
;
807 p
= vfs_s_get_path (vpath
, &archive
, FL_NO_OPEN
);
811 return (vfsid
) archive
;
814 /* --------------------------------------------------------------------------------------------- */
817 vfs_s_nothingisopen (vfsid id
)
820 /* Our data structures should survive free of superblock at any time */
824 /* --------------------------------------------------------------------------------------------- */
827 vfs_s_free (vfsid id
)
829 vfs_s_free_super (((struct vfs_s_super
*) id
)->me
, (struct vfs_s_super
*) id
);
832 /* --------------------------------------------------------------------------------------------- */
835 vfs_s_dir_uptodate (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
839 if (MEDATA
->flush
!= 0)
845 gettimeofday (&tim
, NULL
);
847 return (tim
.tv_sec
< ino
->timestamp
.tv_sec
? 1 : 0);
851 /* --------------------------------------------------------------------------------------------- */
852 /*** public functions ****************************************************************************/
853 /* --------------------------------------------------------------------------------------------- */
856 vfs_s_new_inode (struct vfs_class
*me
, struct vfs_s_super
*super
, struct stat
*initstat
)
858 struct vfs_s_inode
*ino
;
860 ino
= g_try_new0 (struct vfs_s_inode
, 1);
864 if (initstat
!= NULL
)
867 ino
->st
.st_nlink
= 0;
868 ino
->st
.st_ino
= MEDATA
->inode_counter
++;
869 ino
->st
.st_dev
= MEDATA
->rdev
;
873 CALL (init_inode
) (me
, ino
);
878 /* --------------------------------------------------------------------------------------------- */
881 vfs_s_free_inode (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
884 vfs_die ("Don't pass NULL to me");
886 /* ==0 can happen if freshly created entry is deleted */
887 if (ino
->st
.st_nlink
> 1)
893 while (ino
->subdir
!= NULL
)
894 vfs_s_free_entry (me
, (struct vfs_s_entry
*) ino
->subdir
->data
);
896 CALL (free_inode
) (me
, ino
);
897 g_free (ino
->linkname
);
898 if ((MEDATA
->flags
& VFS_S_USETMP
) != 0 && ino
->localname
!= NULL
)
900 unlink (ino
->localname
);
901 g_free (ino
->localname
);
903 ino
->super
->ino_usage
--;
907 /* --------------------------------------------------------------------------------------------- */
910 vfs_s_new_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*inode
)
912 struct vfs_s_entry
*entry
;
914 entry
= g_new0 (struct vfs_s_entry
, 1);
916 entry
->name
= g_strdup (name
);
918 entry
->ino
->ent
= entry
;
919 CALL (init_entry
) (me
, entry
);
924 /* --------------------------------------------------------------------------------------------- */
927 vfs_s_free_entry (struct vfs_class
*me
, struct vfs_s_entry
*ent
)
929 if (ent
->dir
!= NULL
)
930 ent
->dir
->subdir
= g_list_remove (ent
->dir
->subdir
, ent
);
932 MC_PTR_FREE (ent
->name
);
934 if (ent
->ino
!= NULL
)
936 ent
->ino
->ent
= NULL
;
937 vfs_s_free_inode (me
, ent
->ino
);
943 /* --------------------------------------------------------------------------------------------- */
946 vfs_s_insert_entry (struct vfs_class
*me
, struct vfs_s_inode
*dir
, struct vfs_s_entry
*ent
)
952 ent
->ino
->st
.st_nlink
++;
953 dir
->subdir
= g_list_append (dir
->subdir
, ent
);
956 /* --------------------------------------------------------------------------------------------- */
959 vfs_s_default_stat (struct vfs_class
*me
, mode_t mode
)
961 static struct stat st
;
966 myumask
= umask (022);
973 #ifdef HAVE_STRUCT_STAT_ST_RDEV
976 st
.st_uid
= getuid ();
977 st
.st_gid
= getgid ();
978 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
983 st
.st_mtime
= st
.st_atime
= st
.st_ctime
= time (NULL
);
984 #ifdef HAVE_STRUCT_STAT_ST_MTIM
985 st
.st_atim
.tv_nsec
= st
.st_mtim
.tv_nsec
= st
.st_ctim
.tv_nsec
= 0;
988 vfs_adjust_stat (&st
);
993 /* --------------------------------------------------------------------------------------------- */
995 * Calculate number of st_blocks using st_size and st_blksize.
996 * In according to stat(2), st_blocks is the size in 512-byte units.
1002 vfs_adjust_stat (struct stat
*s
)
1004 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
1005 if (s
->st_size
== 0)
1009 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1011 blksize_t ioblock_size
;
1013 /* 1. Calculate how many IO blocks are occupied */
1014 ioblocks
= 1 + (s
->st_size
- 1) / s
->st_blksize
;
1015 /* 2. Calculate size of st_blksize in 512-byte units */
1016 ioblock_size
= 1 + (s
->st_blksize
- 1) / 512;
1017 /* 3. Calculate number of blocks */
1018 s
->st_blocks
= ioblocks
* ioblock_size
;
1020 /* Let IO block size is 512 bytes */
1021 s
->st_blocks
= 1 + (s
->st_size
- 1) / 512;
1022 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1024 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
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 superlock object by vpath
1064 * @return superlock object or NULL if not found
1067 struct vfs_s_super
*
1068 vfs_get_super_by_vpath (const vfs_path_t
* vpath
)
1071 void *cookie
= NULL
;
1072 const vfs_path_element_t
*path_element
;
1073 struct vfs_s_subclass
*subclass
;
1074 struct vfs_s_super
*super
= NULL
;
1075 vfs_path_t
*vpath_archive
;
1077 path_element
= vfs_path_get_by_index (vpath
, -1);
1078 subclass
= (struct vfs_s_subclass
*) path_element
->class->data
;
1079 if (subclass
== NULL
)
1082 vpath_archive
= vfs_path_clone (vpath
);
1083 vfs_path_remove_element_by_index (vpath_archive
, -1);
1085 if (subclass
->archive_check
!= NULL
)
1087 cookie
= subclass
->archive_check (vpath_archive
);
1092 for (iter
= subclass
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
1096 super
= (struct vfs_s_super
*) iter
->data
;
1098 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1099 i
= subclass
->archive_same (path_element
, super
, vpath_archive
, cookie
);
1109 vfs_path_free (vpath_archive
);
1113 /* --------------------------------------------------------------------------------------------- */
1115 * get path from last VFS-element and create corresponding superblock
1117 * @param vpath source path object
1118 * @param archive pointer to object for store newly created superblock
1119 * @param flags flags
1121 * @return path from last VFS-element
1124 vfs_s_get_path (const vfs_path_t
* vpath
, struct vfs_s_super
**archive
, int flags
)
1126 const char *retval
= "";
1128 struct vfs_s_super
*super
;
1129 const vfs_path_element_t
*path_element
;
1130 struct vfs_s_subclass
*subclass
;
1132 path_element
= vfs_path_get_by_index (vpath
, -1);
1134 if (path_element
->path
!= NULL
)
1135 retval
= path_element
->path
;
1137 super
= vfs_get_super_by_vpath (vpath
);
1139 goto return_success
;
1141 if ((flags
& FL_NO_OPEN
) != 0)
1143 path_element
->class->verrno
= EIO
;
1147 super
= vfs_s_new_super (path_element
->class);
1149 subclass
= (struct vfs_s_subclass
*) path_element
->class->data
;
1150 if (subclass
->open_archive
!= NULL
)
1152 vfs_path_t
*vpath_archive
;
1154 vpath_archive
= vfs_path_clone (vpath
);
1155 vfs_path_remove_element_by_index (vpath_archive
, -1);
1157 result
= subclass
->open_archive (super
, vpath_archive
, path_element
);
1158 vfs_path_free (vpath_archive
);
1162 vfs_s_free_super (path_element
->class, super
);
1163 path_element
->class->verrno
= EIO
;
1166 if (super
->name
== NULL
)
1167 vfs_die ("You have to fill name\n");
1168 if (super
->root
== NULL
)
1169 vfs_die ("You have to fill root inode\n");
1171 vfs_s_insert_super (path_element
->class, super
);
1172 vfs_stamp_create (path_element
->class, super
);
1179 /* --------------------------------------------------------------------------------------------- */
1182 vfs_s_invalidate (struct vfs_class
*me
, struct vfs_s_super
*super
)
1184 if (!super
->want_stale
)
1186 vfs_s_free_inode (me
, super
->root
);
1187 super
->root
= vfs_s_new_inode (me
, super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
1191 /* --------------------------------------------------------------------------------------------- */
1194 vfs_s_fullpath (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1196 if (ino
->ent
== NULL
)
1197 ERRNOR (EAGAIN
, NULL
);
1199 if ((MEDATA
->flags
& VFS_S_USETMP
) == 0)
1204 path
= g_strdup (ino
->ent
->name
);
1210 ino
= ino
->ent
->dir
;
1211 if (ino
== ino
->super
->root
)
1214 newpath
= g_strconcat (ino
->ent
->name
, PATH_SEP_STR
, path
, (char *) NULL
);
1221 /* remote systems */
1222 if (ino
->ent
->dir
== NULL
|| ino
->ent
->dir
->ent
== NULL
)
1223 return g_strdup (ino
->ent
->name
);
1225 return g_strconcat (ino
->ent
->dir
->ent
->name
, PATH_SEP_STR
, ino
->ent
->name
, (char *) NULL
);
1228 /* --------------------------------------------------------------------------------------------- */
1229 /* --------------------------- stat and friends ---------------------------- */
1232 vfs_s_open (const vfs_path_t
* vpath
, int flags
, mode_t mode
)
1234 int was_changed
= 0;
1235 vfs_file_handler_t
*fh
;
1236 struct vfs_s_super
*super
;
1238 struct vfs_s_inode
*ino
;
1239 const vfs_path_element_t
*path_element
;
1241 path_element
= vfs_path_get_by_index (vpath
, -1);
1243 q
= vfs_s_get_path (vpath
, &super
, 0);
1246 ino
= vfs_s_find_inode (path_element
->class, super
, q
, LINK_FOLLOW
, FL_NONE
);
1247 if (ino
!= NULL
&& (flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
1249 path_element
->class->verrno
= EEXIST
;
1255 char *dirname
, *name
;
1256 struct vfs_s_entry
*ent
;
1257 struct vfs_s_inode
*dir
;
1259 /* If the filesystem is read-only, disable file creation */
1260 if ((flags
& O_CREAT
) == 0 || path_element
->class->write
== NULL
)
1263 dirname
= g_path_get_dirname (q
);
1264 name
= g_path_get_basename (q
);
1265 dir
= vfs_s_find_inode (path_element
->class, super
, dirname
, LINK_FOLLOW
, FL_DIR
);
1273 ent
= vfs_s_generate_entry (path_element
->class, name
, dir
, 0755);
1275 vfs_s_insert_entry (path_element
->class, dir
, ent
);
1276 if ((VFSDATA (path_element
)->flags
& VFS_S_USETMP
) != 0)
1279 vfs_path_t
*tmp_vpath
;
1281 tmp_handle
= vfs_mkstemps (&tmp_vpath
, path_element
->class->name
, name
);
1282 ino
->localname
= g_strdup (vfs_path_as_str (tmp_vpath
));
1283 vfs_path_free (tmp_vpath
);
1284 if (tmp_handle
== -1)
1298 if (S_ISDIR (ino
->st
.st_mode
))
1300 path_element
->class->verrno
= EISDIR
;
1304 fh
= g_new (vfs_file_handler_t
, 1);
1308 fh
->changed
= was_changed
;
1312 if (IS_LINEAR (flags
))
1314 if (VFSDATA (path_element
)->linear_start
!= NULL
)
1316 vfs_print_message ("%s", _("Starting linear transfer..."));
1317 fh
->linear
= LS_LINEAR_PREOPEN
;
1322 struct vfs_s_subclass
*s
;
1324 s
= VFSDATA (path_element
);
1325 if (s
->fh_open
!= NULL
&& s
->fh_open (path_element
->class, fh
, flags
, mode
) != 0)
1327 if (s
->fh_free_data
!= NULL
)
1328 s
->fh_free_data (fh
);
1334 if ((VFSDATA (path_element
)->flags
& VFS_S_USETMP
) != 0 && fh
->ino
->localname
!= NULL
)
1336 fh
->handle
= open (fh
->ino
->localname
, NO_LINEAR (flags
), mode
);
1337 if (fh
->handle
== -1)
1340 path_element
->class->verrno
= errno
;
1345 /* i.e. we had no open files and now we have one */
1346 vfs_rmstamp (path_element
->class, (vfsid
) super
);
1348 fh
->ino
->st
.st_nlink
++;
1352 /* --------------------------------------------------------------------------------------------- */
1355 vfs_s_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
1357 return vfs_s_internal_stat (vpath
, buf
, FL_FOLLOW
);
1360 /* --------------------------------------------------------------------------------------------- */
1363 vfs_s_lstat (const vfs_path_t
* vpath
, struct stat
*buf
)
1365 return vfs_s_internal_stat (vpath
, buf
, FL_NONE
);
1368 /* --------------------------------------------------------------------------------------------- */
1371 vfs_s_fstat (void *fh
, struct stat
*buf
)
1377 /* --------------------------------------------------------------------------------------------- */
1380 vfs_s_retrieve_file (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1382 /* If you want reget, you'll have to open file with O_LINEAR */
1387 off_t stat_size
= ino
->st
.st_size
;
1388 vfs_file_handler_t fh
;
1389 vfs_path_t
*tmp_vpath
;
1391 if ((MEDATA
->flags
& VFS_S_USETMP
) == 0)
1394 memset (&fh
, 0, sizeof (fh
));
1399 handle
= vfs_mkstemps (&tmp_vpath
, me
->name
, ino
->ent
->name
);
1400 ino
->localname
= g_strdup (vfs_path_as_str (tmp_vpath
));
1401 vfs_path_free (tmp_vpath
);
1408 if (MEDATA
->linear_start (me
, &fh
, 0) == 0)
1411 /* Clear the interrupt status */
1412 tty_got_interrupt ();
1413 tty_enable_interrupt_key ();
1415 while ((n
= MEDATA
->linear_read (me
, &fh
, buffer
, sizeof (buffer
))) != 0)
1423 vfs_s_print_stats (me
->name
, _("Getting file"), ino
->ent
->name
, total
, stat_size
);
1425 if (tty_got_interrupt ())
1428 t
= write (handle
, buffer
, n
);
1436 MEDATA
->linear_close (me
, &fh
);
1439 tty_disable_interrupt_key ();
1444 MEDATA
->linear_close (me
, &fh
);
1446 tty_disable_interrupt_key ();
1448 unlink (ino
->localname
);
1450 MC_PTR_FREE (ino
->localname
);
1455 /* --------------------------------------------------------------------------------------------- */
1456 /* ----------------------------- Stamping support -------------------------- */
1458 /* Initialize one of our subclasses - fill common functions */
1460 vfs_s_init_class (struct vfs_class
*vclass
, struct vfs_s_subclass
*sub
)
1463 vclass
->fill_names
= vfs_s_fill_names
;
1464 vclass
->open
= vfs_s_open
;
1465 vclass
->close
= vfs_s_close
;
1466 vclass
->read
= vfs_s_read
;
1467 if ((sub
->flags
& VFS_S_READONLY
) == 0)
1468 vclass
->write
= vfs_s_write
;
1469 vclass
->opendir
= vfs_s_opendir
;
1470 vclass
->readdir
= vfs_s_readdir
;
1471 vclass
->closedir
= vfs_s_closedir
;
1472 vclass
->stat
= vfs_s_stat
;
1473 vclass
->lstat
= vfs_s_lstat
;
1474 vclass
->fstat
= vfs_s_fstat
;
1475 vclass
->readlink
= vfs_s_readlink
;
1476 vclass
->chdir
= vfs_s_chdir
;
1477 vclass
->ferrno
= vfs_s_ferrno
;
1478 vclass
->lseek
= vfs_s_lseek
;
1479 vclass
->getid
= vfs_s_getid
;
1480 vclass
->nothingisopen
= vfs_s_nothingisopen
;
1481 vclass
->free
= vfs_s_free
;
1482 if ((sub
->flags
& VFS_S_USETMP
) != 0)
1484 vclass
->getlocalcopy
= vfs_s_getlocalcopy
;
1485 vclass
->ungetlocalcopy
= vfs_s_ungetlocalcopy
;
1486 sub
->find_entry
= vfs_s_find_entry_linear
;
1488 else if ((sub
->flags
& VFS_S_REMOTE
) != 0)
1489 sub
->find_entry
= vfs_s_find_entry_linear
;
1491 sub
->find_entry
= vfs_s_find_entry_tree
;
1492 vclass
->setctl
= vfs_s_setctl
;
1493 sub
->dir_uptodate
= vfs_s_dir_uptodate
;
1496 /* --------------------------------------------------------------------------------------------- */
1497 /** Find VFS id for given directory name */
1500 vfs_getid (const vfs_path_t
* vpath
)
1502 const vfs_path_element_t
*path_element
;
1504 path_element
= vfs_path_get_by_index (vpath
, -1);
1505 if (!vfs_path_element_valid (path_element
) || path_element
->class->getid
== NULL
)
1508 return (*path_element
->class->getid
) (vpath
);
1511 /* --------------------------------------------------------------------------------------------- */
1512 /* ----------- Utility functions for networked filesystems -------------- */
1514 #ifdef ENABLE_VFS_NET
1516 vfs_s_select_on_two (int fd1
, int fd2
)
1519 struct timeval time_out
;
1521 int maxfd
= MAX (fd1
, fd2
) + 1;
1523 time_out
.tv_sec
= 1;
1524 time_out
.tv_usec
= 0;
1529 v
= select (maxfd
, &set
, 0, 0, &time_out
);
1532 if (FD_ISSET (fd1
, &set
))
1534 if (FD_ISSET (fd2
, &set
))
1539 /* --------------------------------------------------------------------------------------------- */
1542 vfs_s_get_line (struct vfs_class
*me
, int sock
, char *buf
, int buf_len
, char term
)
1544 FILE *logfile
= MEDATA
->logfile
;
1548 for (i
= 0; i
< buf_len
- 1; i
++, buf
++)
1550 if (read (sock
, buf
, sizeof (char)) <= 0)
1553 if (logfile
!= NULL
)
1558 ret1
= fwrite (buf
, 1, 1, logfile
);
1559 ret2
= fflush (logfile
);
1571 /* Line is too long - terminate buffer and discard the rest of line */
1573 while (read (sock
, &c
, sizeof (c
)) > 0)
1575 if (logfile
!= NULL
)
1580 ret1
= fwrite (&c
, 1, 1, logfile
);
1581 ret2
= fflush (logfile
);
1591 /* --------------------------------------------------------------------------------------------- */
1594 vfs_s_get_line_interruptible (struct vfs_class
*me
, char *buffer
, int size
, int fd
)
1601 tty_enable_interrupt_key ();
1603 for (i
= 0; i
< size
- 1; i
++)
1607 n
= read (fd
, &buffer
[i
], 1);
1608 if (n
== -1 && errno
== EINTR
)
1619 if (buffer
[i
] == '\n')
1627 buffer
[size
- 1] = '\0';
1630 tty_disable_interrupt_key ();
1634 #endif /* ENABLE_VFS_NET */
1636 /* --------------------------------------------------------------------------------------------- */
1638 * Normalize filenames start position
1642 vfs_s_normalize_filename_leading_spaces (struct vfs_s_inode
*root_inode
, size_t final_num_spaces
)
1646 for (iter
= root_inode
->subdir
; iter
!= NULL
; iter
= g_list_next (iter
))
1648 struct vfs_s_entry
*entry
= (struct vfs_s_entry
*) iter
->data
;
1650 if ((size_t) entry
->ino
->data_offset
> final_num_spaces
)
1652 char *source_name
= entry
->name
;
1655 spacer
= g_strnfill (entry
->ino
->data_offset
- final_num_spaces
, ' ');
1656 entry
->name
= g_strdup_printf ("%s%s", spacer
, source_name
);
1658 g_free (source_name
);
1660 entry
->ino
->data_offset
= -1;
1664 /* --------------------------------------------------------------------------------------------- */