2 Directory cache support
4 Copyright (C) 1998-2024
5 Free Software Foundation, Inc.
8 Pavel Machek <pavel@ucw.cz>, 1998
9 Slava Zanko <slavazanko@gmail.com>, 2010-2013
10 Andrew Borodin <aborodin@vmail.ru> 2010-2022
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 \warning Paths here do _not_ begin with '/', so root directory of
28 archive/site is simply "".
32 * \brief Source: directory cache support
34 * So that you do not have copy of this in each and every filesystem.
36 * Very loosely based on tar.c from midnight and archives.[ch] from
37 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
39 * Unfortunately, I was unable to keep all filesystems
40 * uniform. tar-like filesystems use tree structure where each
41 * directory has pointers to its subdirectories. We can do this
42 * because we have full information about our archive.
44 * At ftp-like filesystems, situation is a little bit different. When
45 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
46 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
47 * listed. That means that we do not have complete information, and if
48 * /usr is symlink to /4, we will not know. Also we have to time out
49 * entries and things would get messy with tree-like approach. So we
50 * do different trick: root directory is completely special and
51 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
52 * and we'll try to use custom find_entry function.
54 * \author Pavel Machek <pavel@ucw.cz>
62 #include <inttypes.h> /* uintmax_t */
64 #ifdef HAVE_SYS_SELECT_H
65 #include <sys/select.h>
67 #include <sys/types.h>
70 #include "lib/global.h"
72 #include "lib/tty/tty.h" /* enable/disable interrupt key */
73 #include "lib/util.h" /* canonicalize_pathname_custom() */
75 #include "lib/widget.h" /* message() */
80 #include "xdirentry.h"
81 #include "gc.h" /* vfs_rmstamp */
83 /*** global variables ****************************************************************************/
85 /*** file scope macro definitions ****************************************************************/
88 if (VFS_SUBCLASS (me)->x != NULL) \
91 /*** file scope type declarations ****************************************************************/
96 struct vfs_s_inode
*dir
;
99 /*** file scope variables ************************************************************************/
101 /*** forward declarations (file scope functions) *************************************************/
103 /* --------------------------------------------------------------------------------------------- */
104 /*** file scope functions ************************************************************************/
105 /* --------------------------------------------------------------------------------------------- */
107 /* We were asked to create entries automagically */
109 static struct vfs_s_entry
*
110 vfs_s_automake (struct vfs_class
*me
, struct vfs_s_inode
*dir
, char *path
, int flags
)
112 struct vfs_s_entry
*res
;
115 sep
= strchr (path
, PATH_SEP
);
119 res
= vfs_s_generate_entry (me
, path
, dir
, (flags
& FL_MKDIR
) != 0 ? (0777 | S_IFDIR
) : 0777);
120 vfs_s_insert_entry (me
, dir
, res
);
128 /* --------------------------------------------------------------------------------------------- */
129 /* If the entry is a symlink, find the entry for its target */
131 static struct vfs_s_entry
*
132 vfs_s_resolve_symlink (struct vfs_class
*me
, struct vfs_s_entry
*entry
, int follow
)
135 char *fullname
= NULL
;
136 struct vfs_s_entry
*target
;
138 if (follow
== LINK_NO_FOLLOW
)
141 ERRNOR (ELOOP
, NULL
);
143 ERRNOR (ENOENT
, NULL
);
144 if (!S_ISLNK (entry
->ino
->st
.st_mode
))
147 linkname
= entry
->ino
->linkname
;
148 if (linkname
== NULL
)
149 ERRNOR (EFAULT
, NULL
);
151 /* make full path from relative */
152 if (!IS_PATH_SEP (*linkname
))
156 fullpath
= vfs_s_fullpath (me
, entry
->dir
);
157 if (fullpath
!= NULL
)
159 fullname
= g_strconcat (fullpath
, PATH_SEP_STR
, linkname
, (char *) NULL
);
166 VFS_SUBCLASS (me
)->find_entry (me
, entry
->dir
->super
->root
, linkname
, follow
- 1, FL_NONE
);
171 /* --------------------------------------------------------------------------------------------- */
173 * Follow > 0: follow links, serves as loop protect,
174 * == -1: do not follow links
177 static struct vfs_s_entry
*
178 vfs_s_find_entry_tree (struct vfs_class
*me
, struct vfs_s_inode
*root
,
179 const char *a_path
, int follow
, int flags
)
182 struct vfs_s_entry
*ent
= NULL
;
183 char *const pathref
= g_strdup (a_path
);
184 char *path
= pathref
;
186 /* canonicalize as well, but don't remove '../' from path */
187 canonicalize_pathname_custom (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
193 while (IS_PATH_SEP (*path
)) /* Strip leading '/' */
202 for (pseg
= 0; path
[pseg
] != '\0' && !IS_PATH_SEP (path
[pseg
]); pseg
++)
205 for (iter
= g_queue_peek_head_link (root
->subdir
); iter
!= NULL
; iter
= g_list_next (iter
))
207 ent
= VFS_ENTRY (iter
->data
);
208 if (strlen (ent
->name
) == pseg
&& strncmp (ent
->name
, path
, pseg
) == 0)
213 ent
= iter
!= NULL
? VFS_ENTRY (iter
->data
) : NULL
;
215 if (ent
== NULL
&& (flags
& (FL_MKFILE
| FL_MKDIR
)) != 0)
216 ent
= vfs_s_automake (me
, root
, path
, flags
);
224 /* here we must follow leading directories always;
225 only the actual file is optional */
226 ent
= vfs_s_resolve_symlink (me
, ent
,
227 strchr (path
, PATH_SEP
) != NULL
? LINK_FOLLOW
: follow
);
237 /* --------------------------------------------------------------------------------------------- */
239 static struct vfs_s_entry
*
240 vfs_s_find_entry_linear (struct vfs_class
*me
, struct vfs_s_inode
*root
,
241 const char *a_path
, int follow
, int flags
)
243 struct vfs_s_entry
*ent
= NULL
;
244 char *const path
= g_strdup (a_path
);
247 if (root
->super
->root
!= root
)
248 vfs_die ("We have to use _real_ root. Always. Sorry.");
250 /* canonicalize as well, but don't remove '../' from path */
251 canonicalize_pathname_custom (path
, CANON_PATH_ALL
& (~CANON_PATH_REMDOUBLEDOTS
));
253 if ((flags
& FL_DIR
) == 0)
255 char *dirname
, *name
;
256 struct vfs_s_inode
*ino
;
258 dirname
= g_path_get_dirname (path
);
259 name
= g_path_get_basename (path
);
260 ino
= vfs_s_find_inode (me
, root
->super
, dirname
, follow
, flags
| FL_DIR
);
261 ent
= vfs_s_find_entry_tree (me
, ino
, name
, follow
, flags
);
268 iter
= g_queue_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
269 ent
= iter
!= NULL
? VFS_ENTRY (iter
->data
) : NULL
;
271 if (ent
!= NULL
&& !VFS_SUBCLASS (me
)->dir_uptodate (me
, ent
->ino
))
274 vfs_print_message (_("Directory cache expired for %s"), path
);
276 vfs_s_free_entry (me
, ent
);
282 struct vfs_s_inode
*ino
;
284 ino
= vfs_s_new_inode (me
, root
->super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
285 ent
= vfs_s_new_entry (me
, path
, ino
);
286 if (VFS_SUBCLASS (me
)->dir_load (me
, ino
, path
) == -1)
288 vfs_s_free_entry (me
, ent
);
293 vfs_s_insert_entry (me
, root
, ent
);
295 iter
= g_queue_find_custom (root
->subdir
, path
, (GCompareFunc
) vfs_s_entry_compare
);
296 ent
= iter
!= NULL
? VFS_ENTRY (iter
->data
) : NULL
;
299 vfs_die ("find_linear: success but directory is not there\n");
302 if (vfs_s_resolve_symlink (me
, ent
, follow
) == NULL
)
312 /* --------------------------------------------------------------------------------------------- */
313 /* Ook, these were functions around directory entries / inodes */
314 /* -------------------------------- superblock games -------------------------- */
316 static struct vfs_s_super
*
317 vfs_s_new_super (struct vfs_class
*me
)
319 struct vfs_s_super
*super
;
321 super
= g_new0 (struct vfs_s_super
, 1);
326 /* --------------------------------------------------------------------------------------------- */
329 vfs_s_insert_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
331 VFS_SUBCLASS (me
)->supers
= g_list_prepend (VFS_SUBCLASS (me
)->supers
, super
);
334 /* --------------------------------------------------------------------------------------------- */
337 vfs_s_free_super (struct vfs_class
*me
, struct vfs_s_super
*super
)
339 if (super
->root
!= NULL
)
341 vfs_s_free_inode (me
, super
->root
);
346 /* FIXME: We currently leak small amount of memory, sometimes. Fix it if you can. */
347 if (super
->ino_usage
!= 0)
348 message (D_ERROR
, "Direntry warning",
349 "Super ino_usage is %d, memory leak", super
->ino_usage
);
351 if (super
->want_stale
)
352 message (D_ERROR
, "Direntry warning", "%s", "Super has want_stale set");
355 VFS_SUBCLASS (me
)->supers
= g_list_remove (VFS_SUBCLASS (me
)->supers
, super
);
357 CALL (free_archive
) (me
, super
);
358 #ifdef ENABLE_VFS_NET
359 vfs_path_element_free (super
->path_element
);
361 g_free (super
->name
);
365 /* --------------------------------------------------------------------------------------------- */
367 static vfs_file_handler_t
*
368 vfs_s_new_fh (struct vfs_s_inode
*ino
, gboolean changed
)
370 vfs_file_handler_t
*fh
;
372 fh
= g_new0 (vfs_file_handler_t
, 1);
373 vfs_s_init_fh (fh
, ino
, changed
);
378 /* --------------------------------------------------------------------------------------------- */
381 vfs_s_free_fh (struct vfs_s_subclass
*s
, vfs_file_handler_t
* fh
)
383 if (s
->fh_free
!= NULL
)
389 /* --------------------------------------------------------------------------------------------- */
390 /* Support of archives */
391 /* ------------------------ readdir & friends ----------------------------- */
393 static struct vfs_s_inode
*
394 vfs_s_inode_from_path (const vfs_path_t
* vpath
, int flags
)
396 struct vfs_s_super
*super
;
397 struct vfs_s_inode
*ino
;
399 struct vfs_class
*me
;
401 q
= vfs_s_get_path (vpath
, &super
, 0);
405 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
408 vfs_s_find_inode (me
, super
, q
,
409 (flags
& FL_FOLLOW
) != 0 ? LINK_FOLLOW
: LINK_NO_FOLLOW
,
411 if (ino
== NULL
&& *q
== '\0')
412 /* We are asking about / directory of ftp server: assume it exists */
414 vfs_s_find_inode (me
, super
, q
,
415 (flags
& FL_FOLLOW
) != 0 ? LINK_FOLLOW
: LINK_NO_FOLLOW
,
416 FL_DIR
| (flags
& ~FL_FOLLOW
));
420 /* --------------------------------------------------------------------------------------------- */
423 vfs_s_opendir (const vfs_path_t
* vpath
)
425 struct vfs_s_inode
*dir
;
426 struct dirhandle
*info
;
427 struct vfs_class
*me
;
429 dir
= vfs_s_inode_from_path (vpath
, FL_DIR
| FL_FOLLOW
);
433 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
435 if (!S_ISDIR (dir
->st
.st_mode
))
437 me
->verrno
= ENOTDIR
;
443 if (dir
->subdir
== NULL
) /* This can actually happen if we allow empty directories */
449 info
= g_new (struct dirhandle
, 1);
450 info
->cur
= g_queue_peek_head_link (dir
->subdir
);
456 /* --------------------------------------------------------------------------------------------- */
458 static struct vfs_dirent
*
459 vfs_s_readdir (void *data
)
461 struct vfs_dirent
*dir
= NULL
;
462 struct dirhandle
*info
= (struct dirhandle
*) data
;
465 if (info
->cur
== NULL
|| info
->cur
->data
== NULL
)
468 name
= VFS_ENTRY (info
->cur
->data
)->name
;
470 dir
= vfs_dirent_init (NULL
, name
, 0);
472 vfs_die ("Null in structure-cannot happen");
474 info
->cur
= g_list_next (info
->cur
);
479 /* --------------------------------------------------------------------------------------------- */
482 vfs_s_closedir (void *data
)
484 struct dirhandle
*info
= (struct dirhandle
*) data
;
485 struct vfs_s_inode
*dir
= info
->dir
;
487 vfs_s_free_inode (dir
->super
->me
, dir
);
492 /* --------------------------------------------------------------------------------------------- */
495 vfs_s_chdir (const vfs_path_t
* vpath
)
499 data
= vfs_s_opendir (vpath
);
502 vfs_s_closedir (data
);
506 /* --------------------------------------------------------------------------------------------- */
507 /* --------------------------- stat and friends ---------------------------- */
510 vfs_s_internal_stat (const vfs_path_t
* vpath
, struct stat
*buf
, int flag
)
512 struct vfs_s_inode
*ino
;
514 ino
= vfs_s_inode_from_path (vpath
, flag
);
521 /* --------------------------------------------------------------------------------------------- */
524 vfs_s_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
526 struct vfs_s_inode
*ino
;
528 struct vfs_class
*me
;
530 ino
= vfs_s_inode_from_path (vpath
, 0);
534 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
536 if (!S_ISLNK (ino
->st
.st_mode
))
542 if (ino
->linkname
== NULL
)
548 len
= strlen (ino
->linkname
);
551 /* readlink() does not append a NUL character to buf */
552 memcpy (buf
, ino
->linkname
, len
);
556 /* --------------------------------------------------------------------------------------------- */
559 vfs_s_read (void *fh
, char *buffer
, size_t count
)
561 vfs_file_handler_t
*file
= VFS_FILE_HANDLER (fh
);
562 struct vfs_class
*me
= VFS_FILE_HANDLER_SUPER (fh
)->me
;
564 if (file
->linear
== LS_LINEAR_PREOPEN
)
566 if (VFS_SUBCLASS (me
)->linear_start (me
, file
, file
->pos
) == 0)
570 if (file
->linear
== LS_LINEAR_CLOSED
)
571 vfs_die ("linear_start() did not set linear_state!");
573 if (file
->linear
== LS_LINEAR_OPEN
)
574 return VFS_SUBCLASS (me
)->linear_read (me
, file
, buffer
, count
);
576 if (file
->handle
!= -1)
580 n
= read (file
->handle
, buffer
, count
);
585 vfs_die ("vfs_s_read: This should not happen\n");
589 /* --------------------------------------------------------------------------------------------- */
592 vfs_s_write (void *fh
, const char *buffer
, size_t count
)
594 vfs_file_handler_t
*file
= VFS_FILE_HANDLER (fh
);
595 struct vfs_class
*me
= VFS_FILE_HANDLER_SUPER (fh
)->me
;
597 if (file
->linear
!= LS_NOT_LINEAR
)
598 vfs_die ("no writing to linear files, please");
600 file
->changed
= TRUE
;
601 if (file
->handle
!= -1)
605 n
= write (file
->handle
, buffer
, count
);
610 vfs_die ("vfs_s_write: This should not happen\n");
614 /* --------------------------------------------------------------------------------------------- */
617 vfs_s_lseek (void *fh
, off_t offset
, int whence
)
619 vfs_file_handler_t
*file
= VFS_FILE_HANDLER (fh
);
620 off_t size
= file
->ino
->st
.st_size
;
622 if (file
->linear
== LS_LINEAR_OPEN
)
623 vfs_die ("cannot lseek() after linear_read!");
625 if (file
->handle
!= -1)
626 { /* If we have local file opened, we want to work with it */
629 retval
= lseek (file
->handle
, offset
, whence
);
631 VFS_FILE_HANDLER_SUPER (fh
)->me
->verrno
= errno
;
648 else if (offset
< size
)
655 /* --------------------------------------------------------------------------------------------- */
658 vfs_s_close (void *fh
)
660 vfs_file_handler_t
*file
= VFS_FILE_HANDLER (fh
);
661 struct vfs_s_super
*super
= VFS_FILE_HANDLER_SUPER (fh
);
662 struct vfs_class
*me
= super
->me
;
663 struct vfs_s_subclass
*sub
= VFS_SUBCLASS (me
);
670 if (super
->fd_usage
== 0)
671 vfs_stamp_create (me
, VFS_FILE_HANDLER_SUPER (fh
));
673 if (file
->linear
== LS_LINEAR_OPEN
)
674 sub
->linear_close (me
, fh
);
675 if (sub
->fh_close
!= NULL
)
676 res
= sub
->fh_close (me
, fh
);
677 if ((me
->flags
& VFSF_USETMP
) != 0 && file
->changed
&& sub
->file_store
!= NULL
)
681 s
= vfs_s_fullpath (me
, file
->ino
);
687 res
= sub
->file_store (me
, fh
, s
, file
->ino
->localname
);
690 vfs_s_invalidate (me
, super
);
693 if (file
->handle
!= -1)
695 close (file
->handle
);
699 vfs_s_free_inode (me
, file
->ino
);
700 vfs_s_free_fh (sub
, fh
);
705 /* --------------------------------------------------------------------------------------------- */
708 vfs_s_print_stats (const char *fs_name
, const char *action
,
709 const char *file_name
, off_t have
, off_t need
)
712 vfs_print_message (_("%s: %s: %s %3d%% (%lld) bytes transferred"), fs_name
, action
,
713 file_name
, (int) ((double) have
* 100 / need
), (long long) have
);
715 vfs_print_message (_("%s: %s: %s %lld bytes transferred"), fs_name
, action
, file_name
,
719 /* --------------------------------------------------------------------------------------------- */
720 /* ------------------------------- mc support ---------------------------- */
723 vfs_s_fill_names (struct vfs_class
*me
, fill_names_f func
)
727 for (iter
= VFS_SUBCLASS (me
)->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
729 const struct vfs_s_super
*super
= (const struct vfs_s_super
*) iter
->data
;
732 name
= g_strconcat (super
->name
, PATH_SEP_STR
, me
->prefix
, VFS_PATH_URL_DELIMITER
,
733 /* super->current_dir->name, */ (char *) NULL
);
739 /* --------------------------------------------------------------------------------------------- */
742 vfs_s_ferrno (struct vfs_class
*me
)
747 /* --------------------------------------------------------------------------------------------- */
749 * Get local copy of the given file. We reuse the existing file cache
750 * for remote filesystems. Archives use standard VFS facilities.
754 vfs_s_getlocalcopy (const vfs_path_t
* vpath
)
756 vfs_file_handler_t
*fh
;
757 vfs_path_t
*local
= NULL
;
762 fh
= vfs_s_open (vpath
, O_RDONLY
, 0);
766 const struct vfs_class
*me
;
768 me
= vfs_path_get_last_path_vfs (vpath
);
769 if ((me
->flags
& VFSF_USETMP
) != 0 && fh
->ino
!= NULL
)
770 local
= vfs_path_from_str_flags (fh
->ino
->localname
, VPF_NO_CANON
);
778 /* --------------------------------------------------------------------------------------------- */
780 * Return the local copy. Since we are using our cache, we do nothing -
781 * the cache will be removed when the archive is closed.
785 vfs_s_ungetlocalcopy (const vfs_path_t
* vpath
, const vfs_path_t
* local
, gboolean has_changed
)
793 /* --------------------------------------------------------------------------------------------- */
796 vfs_s_setctl (const vfs_path_t
* vpath
, int ctlop
, void *arg
)
798 struct vfs_class
*me
;
800 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
804 case VFS_SETCTL_STALE_DATA
:
806 struct vfs_s_inode
*ino
;
808 ino
= vfs_s_inode_from_path (vpath
, 0);
812 ino
->super
->want_stale
= TRUE
;
815 ino
->super
->want_stale
= FALSE
;
816 vfs_s_invalidate (me
, ino
->super
);
820 case VFS_SETCTL_LOGFILE
:
821 me
->logfile
= fopen ((char *) arg
, "w");
823 case VFS_SETCTL_FLUSH
:
831 /* --------------------------------------------------------------------------------------------- */
832 /* ----------------------------- Stamping support -------------------------- */
835 vfs_s_getid (const vfs_path_t
* vpath
)
837 struct vfs_s_super
*archive
= NULL
;
840 p
= vfs_s_get_path (vpath
, &archive
, FL_NO_OPEN
);
844 return (vfsid
) archive
;
847 /* --------------------------------------------------------------------------------------------- */
850 vfs_s_nothingisopen (vfsid id
)
852 return (VFS_SUPER (id
)->fd_usage
<= 0);
855 /* --------------------------------------------------------------------------------------------- */
858 vfs_s_free (vfsid id
)
860 vfs_s_free_super (VFS_SUPER (id
)->me
, VFS_SUPER (id
));
863 /* --------------------------------------------------------------------------------------------- */
866 vfs_s_dir_uptodate (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
876 tim
= g_get_monotonic_time ();
878 return (tim
< ino
->timestamp
);
881 /* --------------------------------------------------------------------------------------------- */
882 /*** public functions ****************************************************************************/
883 /* --------------------------------------------------------------------------------------------- */
886 vfs_s_new_inode (struct vfs_class
*me
, struct vfs_s_super
*super
, struct stat
*initstat
)
888 struct vfs_s_inode
*ino
;
890 ino
= g_try_new0 (struct vfs_s_inode
, 1);
894 if (initstat
!= NULL
)
897 ino
->subdir
= g_queue_new ();
898 ino
->st
.st_nlink
= 0;
899 ino
->st
.st_ino
= VFS_SUBCLASS (me
)->inode_counter
++;
900 ino
->st
.st_dev
= VFS_SUBCLASS (me
)->rdev
;
904 CALL (init_inode
) (me
, ino
);
909 /* --------------------------------------------------------------------------------------------- */
912 vfs_s_free_inode (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
915 vfs_die ("Don't pass NULL to me");
917 /* ==0 can happen if freshly created entry is deleted */
918 if (ino
->st
.st_nlink
> 1)
924 while (g_queue_get_length (ino
->subdir
) != 0)
926 struct vfs_s_entry
*entry
;
928 entry
= VFS_ENTRY (g_queue_peek_head (ino
->subdir
));
929 vfs_s_free_entry (me
, entry
);
932 g_queue_free (ino
->subdir
);
935 CALL (free_inode
) (me
, ino
);
936 g_free (ino
->linkname
);
937 if ((me
->flags
& VFSF_USETMP
) != 0 && ino
->localname
!= NULL
)
939 unlink (ino
->localname
);
940 g_free (ino
->localname
);
942 ino
->super
->ino_usage
--;
946 /* --------------------------------------------------------------------------------------------- */
949 vfs_s_new_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*inode
)
951 struct vfs_s_entry
*entry
;
953 entry
= g_new0 (struct vfs_s_entry
, 1);
955 entry
->name
= g_strdup (name
);
957 entry
->ino
->ent
= entry
;
958 CALL (init_entry
) (me
, entry
);
963 /* --------------------------------------------------------------------------------------------- */
966 vfs_s_free_entry (struct vfs_class
*me
, struct vfs_s_entry
*ent
)
968 if (ent
->dir
!= NULL
)
969 g_queue_remove (ent
->dir
->subdir
, ent
);
971 MC_PTR_FREE (ent
->name
);
973 if (ent
->ino
!= NULL
)
975 ent
->ino
->ent
= NULL
;
976 vfs_s_free_inode (me
, ent
->ino
);
982 /* --------------------------------------------------------------------------------------------- */
985 vfs_s_insert_entry (struct vfs_class
*me
, struct vfs_s_inode
*dir
, struct vfs_s_entry
*ent
)
991 ent
->ino
->st
.st_nlink
++;
992 g_queue_push_tail (dir
->subdir
, ent
);
995 /* --------------------------------------------------------------------------------------------- */
998 vfs_s_entry_compare (const void *a
, const void *b
)
1000 const struct vfs_s_entry
*e
= (const struct vfs_s_entry
*) a
;
1001 const char *name
= (const char *) b
;
1003 return strcmp (e
->name
, name
);
1006 /* --------------------------------------------------------------------------------------------- */
1009 vfs_s_default_stat (struct vfs_class
*me
, mode_t mode
)
1011 static struct stat st
;
1016 myumask
= umask (022);
1023 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1026 st
.st_uid
= getuid ();
1027 st
.st_gid
= getgid ();
1028 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1029 st
.st_blksize
= 512;
1033 st
.st_mtime
= st
.st_atime
= st
.st_ctime
= time (NULL
);
1034 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1035 st
.st_atim
.tv_nsec
= st
.st_mtim
.tv_nsec
= st
.st_ctim
.tv_nsec
= 0;
1038 vfs_adjust_stat (&st
);
1043 /* --------------------------------------------------------------------------------------------- */
1045 * Calculate number of st_blocks using st_size and st_blksize.
1046 * In according to stat(2), st_blocks is the size in 512-byte units.
1048 * @param s stat info
1052 vfs_adjust_stat (struct stat
*s
)
1054 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
1055 if (s
->st_size
== 0)
1059 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1061 blksize_t ioblock_size
;
1063 /* 1. Calculate how many IO blocks are occupied */
1064 ioblocks
= 1 + (s
->st_size
- 1) / s
->st_blksize
;
1065 /* 2. Calculate size of st_blksize in 512-byte units */
1066 ioblock_size
= 1 + (s
->st_blksize
- 1) / 512;
1067 /* 3. Calculate number of blocks */
1068 s
->st_blocks
= ioblocks
* ioblock_size
;
1070 /* Let IO block size is 512 bytes */
1071 s
->st_blocks
= 1 + (s
->st_size
- 1) / 512;
1072 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1074 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
1077 /* --------------------------------------------------------------------------------------------- */
1079 struct vfs_s_entry
*
1080 vfs_s_generate_entry (struct vfs_class
*me
, const char *name
, struct vfs_s_inode
*parent
,
1083 struct vfs_s_inode
*inode
;
1086 st
= vfs_s_default_stat (me
, mode
);
1087 inode
= vfs_s_new_inode (me
, parent
->super
, st
);
1089 return vfs_s_new_entry (me
, name
, inode
);
1092 /* --------------------------------------------------------------------------------------------- */
1094 struct vfs_s_inode
*
1095 vfs_s_find_inode (struct vfs_class
*me
, const struct vfs_s_super
*super
,
1096 const char *path
, int follow
, int flags
)
1098 struct vfs_s_entry
*ent
;
1100 if (((me
->flags
& VFSF_REMOTE
) == 0) && (*path
== '\0'))
1103 ent
= VFS_SUBCLASS (me
)->find_entry (me
, super
->root
, path
, follow
, flags
);
1104 return (ent
!= NULL
? ent
->ino
: NULL
);
1107 /* --------------------------------------------------------------------------------------------- */
1108 /* Ook, these were functions around directory entries / inodes */
1109 /* -------------------------------- superblock games -------------------------- */
1111 * get superlock object by vpath
1114 * @return superlock object or NULL if not found
1117 struct vfs_s_super
*
1118 vfs_get_super_by_vpath (const vfs_path_t
* vpath
)
1121 void *cookie
= NULL
;
1122 const vfs_path_element_t
*path_element
;
1123 struct vfs_s_subclass
*subclass
;
1124 struct vfs_s_super
*super
= NULL
;
1125 vfs_path_t
*vpath_archive
;
1127 path_element
= vfs_path_get_by_index (vpath
, -1);
1128 subclass
= VFS_SUBCLASS (path_element
->class);
1130 vpath_archive
= vfs_path_clone (vpath
);
1131 vfs_path_remove_element_by_index (vpath_archive
, -1);
1133 if (subclass
->archive_check
!= NULL
)
1135 cookie
= subclass
->archive_check (vpath_archive
);
1140 if (subclass
->archive_same
== NULL
)
1143 for (iter
= subclass
->supers
; iter
!= NULL
; iter
= g_list_next (iter
))
1147 super
= VFS_SUPER (iter
->data
);
1149 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1150 i
= subclass
->archive_same (path_element
, super
, vpath_archive
, cookie
);
1160 vfs_path_free (vpath_archive
, TRUE
);
1164 /* --------------------------------------------------------------------------------------------- */
1166 * get path from last VFS-element and create corresponding superblock
1168 * @param vpath source path object
1169 * @param archive pointer to object for store newly created superblock
1170 * @param flags flags
1172 * @return path from last VFS-element
1175 vfs_s_get_path (const vfs_path_t
* vpath
, struct vfs_s_super
**archive
, int flags
)
1177 const char *retval
= "";
1179 struct vfs_s_super
*super
;
1180 const vfs_path_element_t
*path_element
;
1181 struct vfs_s_subclass
*subclass
;
1183 path_element
= vfs_path_get_by_index (vpath
, -1);
1185 if (path_element
->path
!= NULL
)
1186 retval
= path_element
->path
;
1188 super
= vfs_get_super_by_vpath (vpath
);
1190 goto return_success
;
1192 if ((flags
& FL_NO_OPEN
) != 0)
1194 path_element
->class->verrno
= EIO
;
1198 subclass
= VFS_SUBCLASS (path_element
->class);
1200 super
= subclass
->new_archive
!= NULL
?
1201 subclass
->new_archive (path_element
->class) : vfs_s_new_super (path_element
->class);
1203 if (subclass
->open_archive
!= NULL
)
1205 vfs_path_t
*vpath_archive
;
1207 vpath_archive
= vfs_path_clone (vpath
);
1208 vfs_path_remove_element_by_index (vpath_archive
, -1);
1210 result
= subclass
->open_archive (super
, vpath_archive
, path_element
);
1211 vfs_path_free (vpath_archive
, TRUE
);
1215 vfs_s_free_super (path_element
->class, super
);
1216 path_element
->class->verrno
= EIO
;
1219 if (super
->name
== NULL
)
1220 vfs_die ("You have to fill name\n");
1221 if (super
->root
== NULL
)
1222 vfs_die ("You have to fill root inode\n");
1224 vfs_s_insert_super (path_element
->class, super
);
1225 vfs_stamp_create (path_element
->class, super
);
1232 /* --------------------------------------------------------------------------------------------- */
1235 vfs_s_invalidate (struct vfs_class
*me
, struct vfs_s_super
*super
)
1237 if (!super
->want_stale
)
1239 vfs_s_free_inode (me
, super
->root
);
1240 super
->root
= vfs_s_new_inode (me
, super
, vfs_s_default_stat (me
, S_IFDIR
| 0755));
1244 /* --------------------------------------------------------------------------------------------- */
1247 vfs_s_fullpath (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1249 if (ino
->ent
== NULL
)
1250 ERRNOR (EAGAIN
, NULL
);
1252 if ((me
->flags
& VFSF_USETMP
) == 0)
1257 path
= g_strdup (ino
->ent
->name
);
1263 ino
= ino
->ent
->dir
;
1264 if (ino
== ino
->super
->root
)
1267 newpath
= g_strconcat (ino
->ent
->name
, PATH_SEP_STR
, path
, (char *) NULL
);
1274 /* remote systems */
1275 if (ino
->ent
->dir
== NULL
|| ino
->ent
->dir
->ent
== NULL
)
1276 return g_strdup (ino
->ent
->name
);
1278 return g_strconcat (ino
->ent
->dir
->ent
->name
, PATH_SEP_STR
, ino
->ent
->name
, (char *) NULL
);
1281 /* --------------------------------------------------------------------------------------------- */
1284 vfs_s_init_fh (vfs_file_handler_t
* fh
, struct vfs_s_inode
*ino
, gboolean changed
)
1288 fh
->changed
= changed
;
1289 fh
->linear
= LS_NOT_LINEAR
;
1292 /* --------------------------------------------------------------------------------------------- */
1293 /* --------------------------- stat and friends ---------------------------- */
1296 vfs_s_open (const vfs_path_t
* vpath
, int flags
, mode_t mode
)
1298 gboolean was_changed
= FALSE
;
1299 vfs_file_handler_t
*fh
;
1300 struct vfs_s_super
*super
;
1302 struct vfs_s_inode
*ino
;
1303 struct vfs_class
*me
;
1304 struct vfs_s_subclass
*s
;
1306 q
= vfs_s_get_path (vpath
, &super
, 0);
1310 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
1312 ino
= vfs_s_find_inode (me
, super
, q
, LINK_FOLLOW
, FL_NONE
);
1313 if (ino
!= NULL
&& (flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
1315 me
->verrno
= EEXIST
;
1319 s
= VFS_SUBCLASS (me
);
1324 struct vfs_s_entry
*ent
;
1325 struct vfs_s_inode
*dir
;
1327 /* If the filesystem is read-only, disable file creation */
1328 if ((flags
& O_CREAT
) == 0 || me
->write
== NULL
)
1331 name
= g_path_get_dirname (q
);
1332 dir
= vfs_s_find_inode (me
, super
, name
, LINK_FOLLOW
, FL_DIR
);
1337 name
= g_path_get_basename (q
);
1338 ent
= vfs_s_generate_entry (me
, name
, dir
, 0755);
1340 vfs_s_insert_entry (me
, dir
, ent
);
1341 if ((VFS_CLASS (s
)->flags
& VFSF_USETMP
) != 0)
1344 vfs_path_t
*tmp_vpath
;
1346 tmp_handle
= vfs_mkstemps (&tmp_vpath
, me
->name
, name
);
1347 ino
->localname
= vfs_path_free (tmp_vpath
, FALSE
);
1348 if (tmp_handle
== -1)
1361 if (S_ISDIR (ino
->st
.st_mode
))
1363 me
->verrno
= EISDIR
;
1367 fh
= s
->fh_new
!= NULL
? s
->fh_new (ino
, was_changed
) : vfs_s_new_fh (ino
, was_changed
);
1369 if (IS_LINEAR (flags
))
1371 if (s
->linear_start
!= NULL
)
1373 vfs_print_message ("%s", _("Starting linear transfer..."));
1374 fh
->linear
= LS_LINEAR_PREOPEN
;
1379 if (s
->fh_open
!= NULL
&& s
->fh_open (me
, fh
, flags
, mode
) != 0)
1381 vfs_s_free_fh (s
, fh
);
1386 if ((VFS_CLASS (s
)->flags
& VFSF_USETMP
) != 0 && fh
->ino
->localname
!= NULL
)
1388 fh
->handle
= open (fh
->ino
->localname
, NO_LINEAR (flags
), mode
);
1389 if (fh
->handle
== -1)
1391 vfs_s_free_fh (s
, fh
);
1397 /* i.e. we had no open files and now we have one */
1398 vfs_rmstamp (me
, (vfsid
) super
);
1400 fh
->ino
->st
.st_nlink
++;
1404 /* --------------------------------------------------------------------------------------------- */
1407 vfs_s_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
1409 return vfs_s_internal_stat (vpath
, buf
, FL_FOLLOW
);
1412 /* --------------------------------------------------------------------------------------------- */
1415 vfs_s_lstat (const vfs_path_t
* vpath
, struct stat
*buf
)
1417 return vfs_s_internal_stat (vpath
, buf
, FL_NONE
);
1420 /* --------------------------------------------------------------------------------------------- */
1423 vfs_s_fstat (void *fh
, struct stat
*buf
)
1425 *buf
= VFS_FILE_HANDLER (fh
)->ino
->st
;
1429 /* --------------------------------------------------------------------------------------------- */
1432 vfs_s_retrieve_file (struct vfs_class
*me
, struct vfs_s_inode
*ino
)
1434 /* If you want reget, you'll have to open file with O_LINEAR */
1436 char buffer
[BUF_8K
];
1439 off_t stat_size
= ino
->st
.st_size
;
1440 vfs_file_handler_t
*fh
= NULL
;
1441 vfs_path_t
*tmp_vpath
;
1442 struct vfs_s_subclass
*s
= VFS_SUBCLASS (me
);
1444 if ((me
->flags
& VFSF_USETMP
) == 0)
1447 handle
= vfs_mkstemps (&tmp_vpath
, me
->name
, ino
->ent
->name
);
1448 ino
->localname
= vfs_path_free (tmp_vpath
, FALSE
);
1455 fh
= s
->fh_new
!= NULL
? s
->fh_new (ino
, FALSE
) : vfs_s_new_fh (ino
, FALSE
);
1457 if (s
->linear_start (me
, fh
, 0) == 0)
1460 /* Clear the interrupt status */
1461 tty_got_interrupt ();
1462 tty_enable_interrupt_key ();
1464 while ((n
= s
->linear_read (me
, fh
, buffer
, sizeof (buffer
))) != 0)
1472 vfs_s_print_stats (me
->name
, _("Getting file"), ino
->ent
->name
, total
, stat_size
);
1474 if (tty_got_interrupt ())
1477 t
= write (handle
, buffer
, n
);
1485 s
->linear_close (me
, fh
);
1488 tty_disable_interrupt_key ();
1489 vfs_s_free_fh (s
, fh
);
1493 s
->linear_close (me
, fh
);
1495 tty_disable_interrupt_key ();
1497 unlink (ino
->localname
);
1499 MC_PTR_FREE (ino
->localname
);
1501 vfs_s_free_fh (s
, fh
);
1505 /* --------------------------------------------------------------------------------------------- */
1506 /* ----------------------------- Stamping support -------------------------- */
1508 /* Initialize one of our subclasses - fill common functions */
1510 vfs_init_class (struct vfs_class
*vclass
, const char *name
, vfs_flags_t flags
, const char *prefix
)
1512 memset (vclass
, 0, sizeof (struct vfs_class
));
1514 vclass
->name
= name
;
1515 vclass
->flags
= flags
;
1516 vclass
->prefix
= prefix
;
1518 vclass
->fill_names
= vfs_s_fill_names
;
1519 vclass
->open
= vfs_s_open
;
1520 vclass
->close
= vfs_s_close
;
1521 vclass
->read
= vfs_s_read
;
1522 if ((vclass
->flags
& VFSF_READONLY
) == 0)
1523 vclass
->write
= vfs_s_write
;
1524 vclass
->opendir
= vfs_s_opendir
;
1525 vclass
->readdir
= vfs_s_readdir
;
1526 vclass
->closedir
= vfs_s_closedir
;
1527 vclass
->stat
= vfs_s_stat
;
1528 vclass
->lstat
= vfs_s_lstat
;
1529 vclass
->fstat
= vfs_s_fstat
;
1530 vclass
->readlink
= vfs_s_readlink
;
1531 vclass
->chdir
= vfs_s_chdir
;
1532 vclass
->ferrno
= vfs_s_ferrno
;
1533 vclass
->lseek
= vfs_s_lseek
;
1534 vclass
->getid
= vfs_s_getid
;
1535 vclass
->nothingisopen
= vfs_s_nothingisopen
;
1536 vclass
->free
= vfs_s_free
;
1537 vclass
->setctl
= vfs_s_setctl
;
1538 if ((vclass
->flags
& VFSF_USETMP
) != 0)
1540 vclass
->getlocalcopy
= vfs_s_getlocalcopy
;
1541 vclass
->ungetlocalcopy
= vfs_s_ungetlocalcopy
;
1545 /* --------------------------------------------------------------------------------------------- */
1548 vfs_init_subclass (struct vfs_s_subclass
*sub
, const char *name
, vfs_flags_t flags
,
1551 struct vfs_class
*vclass
= VFS_CLASS (sub
);
1555 vfs_init_class (vclass
, name
, flags
, prefix
);
1557 len
= sizeof (struct vfs_s_subclass
) - sizeof (struct vfs_class
);
1558 start
= (char *) sub
+ sizeof (struct vfs_class
);
1559 memset (start
, 0, len
);
1561 if ((vclass
->flags
& VFSF_USETMP
) != 0)
1562 sub
->find_entry
= vfs_s_find_entry_linear
;
1563 else if ((vclass
->flags
& VFSF_REMOTE
) != 0)
1564 sub
->find_entry
= vfs_s_find_entry_linear
;
1566 sub
->find_entry
= vfs_s_find_entry_tree
;
1567 sub
->dir_uptodate
= vfs_s_dir_uptodate
;
1570 /* --------------------------------------------------------------------------------------------- */
1571 /** Find VFS id for given directory name */
1574 vfs_getid (const vfs_path_t
* vpath
)
1576 const struct vfs_class
*me
;
1578 me
= vfs_path_get_last_path_vfs (vpath
);
1579 if (me
== NULL
|| me
->getid
== NULL
)
1582 return me
->getid (vpath
);
1585 /* --------------------------------------------------------------------------------------------- */
1586 /* ----------- Utility functions for networked filesystems -------------- */
1588 #ifdef ENABLE_VFS_NET
1590 vfs_s_select_on_two (int fd1
, int fd2
)
1593 struct timeval time_out
;
1595 int maxfd
= MAX (fd1
, fd2
) + 1;
1597 time_out
.tv_sec
= 1;
1598 time_out
.tv_usec
= 0;
1603 v
= select (maxfd
, &set
, 0, 0, &time_out
);
1606 if (FD_ISSET (fd1
, &set
))
1608 if (FD_ISSET (fd2
, &set
))
1613 /* --------------------------------------------------------------------------------------------- */
1616 vfs_s_get_line (struct vfs_class
*me
, int sock
, char *buf
, int buf_len
, char term
)
1618 FILE *logfile
= me
->logfile
;
1622 for (i
= 0; i
< buf_len
- 1; i
++, buf
++)
1624 if (read (sock
, buf
, sizeof (char)) <= 0)
1627 if (logfile
!= NULL
)
1632 ret1
= fwrite (buf
, 1, 1, logfile
);
1633 ret2
= fflush (logfile
);
1645 /* Line is too long - terminate buffer and discard the rest of line */
1647 while (read (sock
, &c
, sizeof (c
)) > 0)
1649 if (logfile
!= NULL
)
1654 ret1
= fwrite (&c
, 1, 1, logfile
);
1655 ret2
= fflush (logfile
);
1665 /* --------------------------------------------------------------------------------------------- */
1668 vfs_s_get_line_interruptible (struct vfs_class
*me
, char *buffer
, int size
, int fd
)
1675 tty_enable_interrupt_key ();
1677 for (i
= 0; i
< size
- 1; i
++)
1681 n
= read (fd
, &buffer
[i
], 1);
1682 if (n
== -1 && errno
== EINTR
)
1693 if (buffer
[i
] == '\n')
1701 buffer
[size
- 1] = '\0';
1704 tty_disable_interrupt_key ();
1708 #endif /* ENABLE_VFS_NET */
1710 /* --------------------------------------------------------------------------------------------- */
1712 * Normalize filenames start position
1716 vfs_s_normalize_filename_leading_spaces (struct vfs_s_inode
*root_inode
, size_t final_num_spaces
)
1720 for (iter
= g_queue_peek_head_link (root_inode
->subdir
); iter
!= NULL
;
1721 iter
= g_list_next (iter
))
1723 struct vfs_s_entry
*entry
= VFS_ENTRY (iter
->data
);
1725 if ((size_t) entry
->leading_spaces
> final_num_spaces
)
1727 char *source_name
, *spacer
;
1729 source_name
= entry
->name
;
1730 spacer
= g_strnfill ((size_t) entry
->leading_spaces
- final_num_spaces
, ' ');
1731 entry
->name
= g_strconcat (spacer
, source_name
, (char *) NULL
);
1733 g_free (source_name
);
1736 entry
->leading_spaces
= -1;
1740 /* --------------------------------------------------------------------------------------------- */