Remove vfs_url_t structure (replace with vfs_path_element_t)
[midnight-commander.git] / lib / vfs / direntry.c
blobfd46baeca74c9300ffe9ed4e07e5388a1e904d02
1 /** \file
2 * \brief Source: directory cache support
4 * So that you do not have copy of this in each and every filesystem.
6 * Very loosely based on tar.c from midnight and archives.[ch] from
7 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
9 * Unfortunately, I was unable to keep all filesystems
10 * uniform. tar-like filesystems use tree structure where each
11 * directory has pointers to its subdirectories. We can do this
12 * because we have full information about our archive.
14 * At ftp-like filesystems, situation is a little bit different. When
15 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
16 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
17 * listed. That means that we do not have complete information, and if
18 * /usr is symlink to /4, we will not know. Also we have to time out
19 * entries and things would get messy with tree-like approach. So we
20 * do different trick: root directory is completely special and
21 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
22 * and we'll try to use custom find_entry function.
24 * \author Pavel Machek <pavel@ucw.cz>, distribute under LGPL.
25 * \date 1998
27 * \warning Paths here do _not_ begin with '/', so root directory of
28 * archive/site is simply "".
31 #include <config.h>
33 #include <errno.h>
34 #include <fcntl.h> /* include fcntl.h -> sys/fcntl.h only */
35 /* includes fcntl.h see IEEE Std 1003.1-2008 */
36 #include <time.h>
37 #include <sys/time.h> /* gettimeofday() */
38 #include <inttypes.h> /* uintmax_t */
39 #include <stdarg.h>
41 #include "lib/global.h"
43 #include "lib/tty/tty.h" /* enable/disable interrupt key */
44 #include "lib/util.h" /* concat_dir_and_file */
45 #if 0
46 #include "lib/widget.h" /* message() */
47 #endif
49 #include "vfs.h"
50 #include "utilvfs.h"
51 #include "xdirentry.h"
52 #include "gc.h" /* vfs_rmstamp */
54 /*** global variables ****************************************************************************/
56 /*** file scope macro definitions ****************************************************************/
58 #define CALL(x) if (MEDATA->x) MEDATA->x
60 /*** file scope type declarations ****************************************************************/
62 struct dirhandle
64 GList *cur;
65 struct vfs_s_inode *dir;
68 /*** file scope variables ************************************************************************/
70 static volatile int total_inodes = 0, total_entries = 0;
72 /*** file scope functions ************************************************************************/
73 /* --------------------------------------------------------------------------------------------- */
75 static int
76 vfs_s_entry_compare (const void *a, const void *b)
78 const struct vfs_s_entry *e = (const struct vfs_s_entry *) a;
79 const char *name = (const char *) b;
81 return strcmp (e->name, name);
84 /* --------------------------------------------------------------------------------------------- */
86 static void
87 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
89 if (ino == NULL)
90 vfs_die ("Don't pass NULL to me");
92 /* ==0 can happen if freshly created entry is deleted */
93 if (ino->st.st_nlink > 1)
95 ino->st.st_nlink--;
96 return;
99 while (ino->subdir != NULL)
100 vfs_s_free_entry (me, (struct vfs_s_entry *) ino->subdir->data);
102 CALL (free_inode) (me, ino);
103 g_free (ino->linkname);
104 if (ino->localname != NULL)
106 unlink (ino->localname);
107 g_free (ino->localname);
109 total_inodes--;
110 ino->super->ino_usage--;
111 g_free (ino);
114 /* --------------------------------------------------------------------------------------------- */
115 /* We were asked to create entries automagically */
117 static struct vfs_s_entry *
118 vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
120 struct vfs_s_entry *res;
121 char *sep;
123 sep = strchr (path, PATH_SEP);
124 if (sep != NULL)
125 *sep = '\0';
127 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
128 vfs_s_insert_entry (me, dir, res);
130 if (sep != NULL)
131 *sep = PATH_SEP;
133 return res;
136 /* --------------------------------------------------------------------------------------------- */
137 /* If the entry is a symlink, find the entry for its target */
139 static struct vfs_s_entry *
140 vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry, int follow)
142 char *linkname;
143 char *fullname = NULL;
144 struct vfs_s_entry *target;
146 if (follow == LINK_NO_FOLLOW)
147 return entry;
148 if (follow == 0)
149 ERRNOR (ELOOP, NULL);
150 if (!entry)
151 ERRNOR (ENOENT, NULL);
152 if (!S_ISLNK (entry->ino->st.st_mode))
153 return entry;
155 linkname = entry->ino->linkname;
156 if (linkname == NULL)
157 ERRNOR (EFAULT, NULL);
159 /* make full path from relative */
160 if (*linkname != PATH_SEP)
162 char *fullpath = vfs_s_fullpath (me, entry->dir);
163 if (fullpath)
165 fullname = g_strconcat (fullpath, "/", linkname, (char *) NULL);
166 linkname = fullname;
167 g_free (fullpath);
171 target = (MEDATA->find_entry) (me, entry->dir->super->root, linkname, follow - 1, 0);
172 g_free (fullname);
173 return target;
176 /* --------------------------------------------------------------------------------------------- */
178 * Follow > 0: follow links, serves as loop protect,
179 * == -1: do not follow links
182 static struct vfs_s_entry *
183 vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
184 const char *a_path, int follow, int flags)
186 size_t pseg;
187 struct vfs_s_entry *ent = NULL;
188 char *const pathref = g_strdup (a_path);
189 char *path = pathref;
191 /* canonicalize as well, but don't remove '../' from path */
192 custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
194 while (root != NULL)
196 GList *iter;
198 while (*path == PATH_SEP) /* Strip leading '/' */
199 path++;
201 if (path[0] == '\0')
203 g_free (pathref);
204 return ent;
207 for (pseg = 0; path[pseg] != '\0' && path[pseg] != PATH_SEP; pseg++)
210 for (iter = root->subdir; iter != NULL; iter = g_list_next (iter))
212 ent = (struct vfs_s_entry *) iter->data;
213 if (strlen (ent->name) == pseg && strncmp (ent->name, path, pseg) == 0)
214 /* FOUND! */
215 break;
218 ent = iter != NULL ? (struct vfs_s_entry *) iter->data : NULL;
220 if (ent == NULL && (flags & (FL_MKFILE | FL_MKDIR)) != 0)
221 ent = vfs_s_automake (me, root, path, flags);
222 if (ent == NULL)
224 me->verrno = ENOENT;
225 goto cleanup;
228 path += pseg;
229 /* here we must follow leading directories always;
230 only the actual file is optional */
231 ent = vfs_s_resolve_symlink (me, ent,
232 strchr (path, PATH_SEP) != NULL ? LINK_FOLLOW : follow);
233 if (ent == NULL)
234 goto cleanup;
235 root = ent->ino;
237 cleanup:
238 g_free (pathref);
239 return NULL;
242 /* --------------------------------------------------------------------------------------------- */
244 static void
245 split_dir_name (struct vfs_class *me, char *path, char **dir, char **name, char **save)
247 char *s;
249 (void) me;
251 s = strrchr (path, PATH_SEP);
252 if (s == NULL)
254 *save = NULL;
255 *name = path;
256 *dir = path + strlen (path); /* an empty string */
258 else
260 *save = s;
261 *dir = path;
262 *s++ = '\0';
263 *name = s;
267 /* --------------------------------------------------------------------------------------------- */
269 static struct vfs_s_entry *
270 vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
271 const char *a_path, int follow, int flags)
273 struct vfs_s_entry *ent = NULL;
274 char *const path = g_strdup (a_path);
275 struct vfs_s_entry *retval = NULL;
276 GList *iter;
278 if (root->super->root != root)
279 vfs_die ("We have to use _real_ root. Always. Sorry.");
281 /* canonicalize as well, but don't remove '../' from path */
282 custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
284 if ((flags & FL_DIR) == 0)
286 char *dirname, *name, *save;
287 struct vfs_s_inode *ino;
288 split_dir_name (me, path, &dirname, &name, &save);
289 ino = vfs_s_find_inode (me, root->super, dirname, follow, flags | FL_DIR);
290 if (save != NULL)
291 *save = PATH_SEP;
292 retval = vfs_s_find_entry_tree (me, ino, name, follow, flags);
293 g_free (path);
294 return retval;
297 iter = g_list_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
298 ent = iter != NULL ? (struct vfs_s_entry *) iter->data : NULL;
300 if (ent != NULL && !MEDATA->dir_uptodate (me, ent->ino))
302 #if 1
303 vfs_print_message (_("Directory cache expired for %s"), path);
304 #endif
305 vfs_s_free_entry (me, ent);
306 ent = NULL;
309 if (ent == NULL)
311 struct vfs_s_inode *ino;
313 ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
314 ent = vfs_s_new_entry (me, path, ino);
315 if (MEDATA->dir_load (me, ino, path) == -1)
317 vfs_s_free_entry (me, ent);
318 g_free (path);
319 return NULL;
322 vfs_s_insert_entry (me, root, ent);
324 iter = g_list_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
325 ent = iter != NULL ? (struct vfs_s_entry *) iter->data : NULL;
327 if (ent == NULL)
328 vfs_die ("find_linear: success but directory is not there\n");
330 #if 0
331 if (!vfs_s_resolve_symlink (me, ent, follow))
333 g_free (path);
334 return NULL;
336 #endif
337 g_free (path);
338 return ent;
341 /* --------------------------------------------------------------------------------------------- */
342 /* Ook, these were functions around directory entries / inodes */
343 /* -------------------------------- superblock games -------------------------- */
345 static struct vfs_s_super *
346 vfs_s_new_super (struct vfs_class *me)
348 struct vfs_s_super *super;
350 super = g_new0 (struct vfs_s_super, 1);
351 super->me = me;
352 return super;
355 /* --------------------------------------------------------------------------------------------- */
357 static inline void
358 vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
360 MEDATA->supers = g_list_prepend (MEDATA->supers, super);
363 /* --------------------------------------------------------------------------------------------- */
365 static void
366 vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
368 if (super->root != NULL)
370 vfs_s_free_inode (me, super->root);
371 super->root = NULL;
374 #if 0
375 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
376 if (super->ino_usage)
377 message (D_ERROR, "Direntry warning",
378 "Super ino_usage is %d, memory leak", super->ino_usage);
380 if (super->want_stale)
381 message (D_ERROR, "Direntry warning", "%s", "Super has want_stale set");
382 #endif
384 MEDATA->supers = g_list_remove (MEDATA->supers, super);
386 CALL (free_archive) (me, super);
387 #ifdef ENABLE_VFS_NET
388 vfs_path_element_free (super->path_element);
389 #endif
390 g_free (super->name);
391 g_free (super);
394 /* --------------------------------------------------------------------------------------------- */
396 * Dissect the path and create corresponding superblock.
397 * The result should be freed.
400 static char *
401 vfs_s_get_path (const vfs_path_t * vpath, struct vfs_s_super **archive, int flags)
403 return g_strdup (vfs_s_get_path_mangle (vpath, archive, flags));
406 /* --------------------------------------------------------------------------------------------- */
407 /* Support of archives */
408 /* ------------------------ readdir & friends ----------------------------- */
410 static struct vfs_s_inode *
411 vfs_s_inode_from_path (const vfs_path_t * vpath, int flags)
413 struct vfs_s_super *super;
414 struct vfs_s_inode *ino;
415 char *q;
416 vfs_path_element_t *path_element;
418 q = vfs_s_get_path (vpath, &super, 0);
419 if (q == NULL)
420 return NULL;
422 path_element = vfs_path_get_by_index (vpath, -1);
424 ino =
425 vfs_s_find_inode (path_element->class, super, q,
426 flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW, flags & ~FL_FOLLOW);
427 if ((!ino) && (!*q))
428 /* We are asking about / directory of ftp server: assume it exists */
429 ino =
430 vfs_s_find_inode (path_element->class, super, q,
431 flags & FL_FOLLOW ? LINK_FOLLOW :
432 LINK_NO_FOLLOW, FL_DIR | (flags & ~FL_FOLLOW));
433 g_free (q);
434 return ino;
437 /* --------------------------------------------------------------------------------------------- */
439 static void *
440 vfs_s_opendir (const vfs_path_t * vpath)
442 struct vfs_s_inode *dir;
443 struct dirhandle *info;
444 vfs_path_element_t *path_element;
446 path_element = vfs_path_get_by_index (vpath, -1);
448 dir = vfs_s_inode_from_path (vpath, FL_DIR | FL_FOLLOW);
449 if (dir == NULL)
450 return NULL;
451 if (!S_ISDIR (dir->st.st_mode))
453 path_element->class->verrno = ENOTDIR;
454 return NULL;
457 dir->st.st_nlink++;
458 #if 0
459 if (dir->subdir == NULL) /* This can actually happen if we allow empty directories */
461 path_element->class->verrno = EAGAIN;
462 return NULL;
464 #endif
465 info = g_new (struct dirhandle, 1);
466 info->cur = dir->subdir;
467 info->dir = dir;
469 return info;
472 /* --------------------------------------------------------------------------------------------- */
474 static void *
475 vfs_s_readdir (void *data)
477 static union vfs_dirent dir;
478 struct dirhandle *info = (struct dirhandle *) data;
479 const char *name;
481 if (info->cur == NULL || info->cur->data == NULL)
482 return NULL;
484 name = ((struct vfs_s_entry *) info->cur->data)->name;
485 if (name != NULL)
486 g_strlcpy (dir.dent.d_name, name, MC_MAXPATHLEN);
487 else
488 vfs_die ("Null in structure-cannot happen");
490 compute_namelen (&dir.dent);
491 info->cur = g_list_next (info->cur);
493 return (void *) &dir;
496 /* --------------------------------------------------------------------------------------------- */
498 static int
499 vfs_s_closedir (void *data)
501 struct dirhandle *info = (struct dirhandle *) data;
502 struct vfs_s_inode *dir = info->dir;
504 vfs_s_free_inode (dir->super->me, dir);
505 g_free (data);
506 return 0;
509 /* --------------------------------------------------------------------------------------------- */
511 static int
512 vfs_s_chdir (const vfs_path_t * vpath)
514 void *data;
516 data = vfs_s_opendir (vpath);
517 if (data == NULL)
518 return -1;
519 vfs_s_closedir (data);
520 return 0;
523 /* --------------------------------------------------------------------------------------------- */
524 /* --------------------------- stat and friends ---------------------------- */
526 static int
527 vfs_s_internal_stat (const vfs_path_t * vpath, struct stat *buf, int flag)
529 struct vfs_s_inode *ino;
531 ino = vfs_s_inode_from_path (vpath, flag);
532 if (ino == NULL)
533 return -1;
534 *buf = ino->st;
535 return 0;
538 /* --------------------------------------------------------------------------------------------- */
540 static int
541 vfs_s_stat (const vfs_path_t * vpath, struct stat *buf)
543 return vfs_s_internal_stat (vpath, buf, FL_FOLLOW);
546 /* --------------------------------------------------------------------------------------------- */
548 static int
549 vfs_s_lstat (const vfs_path_t * vpath, struct stat *buf)
551 return vfs_s_internal_stat (vpath, buf, FL_NONE);
554 /* --------------------------------------------------------------------------------------------- */
556 static int
557 vfs_s_fstat (void *fh, struct stat *buf)
559 *buf = FH->ino->st;
560 return 0;
563 /* --------------------------------------------------------------------------------------------- */
565 static int
566 vfs_s_readlink (const vfs_path_t * vpath, char *buf, size_t size)
568 struct vfs_s_inode *ino;
569 size_t len;
570 vfs_path_element_t *path_element;
572 path_element = vfs_path_get_by_index (vpath, -1);
574 ino = vfs_s_inode_from_path (vpath, 0);
575 if (!ino)
576 return -1;
578 if (!S_ISLNK (ino->st.st_mode))
580 path_element->class->verrno = EINVAL;
581 return -1;
584 if (ino->linkname == NULL)
586 path_element->class->verrno = EFAULT;
587 return -1;
590 len = strlen (ino->linkname);
591 if (size < len)
592 len = size;
593 /* readlink() does not append a NUL character to buf */
594 memcpy (buf, ino->linkname, len);
595 return len;
598 /* --------------------------------------------------------------------------------------------- */
600 static ssize_t
601 vfs_s_read (void *fh, char *buffer, size_t count)
603 int n;
604 struct vfs_class *me = FH_SUPER->me;
606 if (FH->linear == LS_LINEAR_PREOPEN)
608 if (!MEDATA->linear_start (me, FH, FH->pos))
609 return -1;
612 if (FH->linear == LS_LINEAR_CLOSED)
613 vfs_die ("linear_start() did not set linear_state!");
615 if (FH->linear == LS_LINEAR_OPEN)
616 return MEDATA->linear_read (me, FH, buffer, count);
618 if (FH->handle != -1)
620 n = read (FH->handle, buffer, count);
621 if (n < 0)
622 me->verrno = errno;
623 return n;
625 vfs_die ("vfs_s_read: This should not happen\n");
626 return -1;
629 /* --------------------------------------------------------------------------------------------- */
631 static ssize_t
632 vfs_s_write (void *fh, const char *buffer, size_t count)
634 int n;
635 struct vfs_class *me = FH_SUPER->me;
637 if (FH->linear)
638 vfs_die ("no writing to linear files, please");
640 FH->changed = 1;
641 if (FH->handle != -1)
643 n = write (FH->handle, buffer, count);
644 if (n < 0)
645 me->verrno = errno;
646 return n;
648 vfs_die ("vfs_s_write: This should not happen\n");
649 return 0;
652 /* --------------------------------------------------------------------------------------------- */
654 static off_t
655 vfs_s_lseek (void *fh, off_t offset, int whence)
657 off_t size = FH->ino->st.st_size;
659 if (FH->linear == LS_LINEAR_OPEN)
660 vfs_die ("cannot lseek() after linear_read!");
662 if (FH->handle != -1)
663 { /* If we have local file opened, we want to work with it */
664 off_t retval = lseek (FH->handle, offset, whence);
665 if (retval == -1)
666 FH->ino->super->me->verrno = errno;
667 return retval;
670 switch (whence)
672 case SEEK_CUR:
673 offset += FH->pos;
674 break;
675 case SEEK_END:
676 offset += size;
677 break;
679 if (offset < 0)
680 FH->pos = 0;
681 else if (offset < size)
682 FH->pos = offset;
683 else
684 FH->pos = size;
685 return FH->pos;
688 /* --------------------------------------------------------------------------------------------- */
690 static int
691 vfs_s_close (void *fh)
693 int res = 0;
694 struct vfs_class *me = FH_SUPER->me;
696 FH_SUPER->fd_usage--;
697 if (!FH_SUPER->fd_usage)
698 vfs_stamp_create (me, FH_SUPER);
700 if (FH->linear == LS_LINEAR_OPEN)
701 MEDATA->linear_close (me, fh);
702 if (MEDATA->fh_close)
703 res = MEDATA->fh_close (me, fh);
704 if (FH->changed && MEDATA->file_store)
706 char *s = vfs_s_fullpath (me, FH->ino);
707 if (!s)
708 res = -1;
709 else
711 res = MEDATA->file_store (me, fh, s, FH->ino->localname);
712 g_free (s);
714 vfs_s_invalidate (me, FH_SUPER);
716 if (FH->handle != -1)
717 close (FH->handle);
719 vfs_s_free_inode (me, FH->ino);
720 g_free (fh);
721 return res;
724 /* --------------------------------------------------------------------------------------------- */
726 static void
727 vfs_s_print_stats (const char *fs_name, const char *action,
728 const char *file_name, off_t have, off_t need)
730 static const char *i18n_percent_transf_format = NULL;
731 static const char *i18n_transf_format = NULL;
733 if (i18n_percent_transf_format == NULL)
735 i18n_percent_transf_format = "%s: %s: %s %3d%% (%" PRIuMAX " %s";
736 i18n_transf_format = "%s: %s: %s %" PRIuMAX " %s";
739 if (need)
740 vfs_print_message (i18n_percent_transf_format, fs_name, action,
741 file_name, (int) ((double) have * 100 / need), (uintmax_t) have,
742 _("bytes transferred"));
743 else
744 vfs_print_message (i18n_transf_format, fs_name, action, file_name, (uintmax_t) have,
745 _("bytes transferred"));
748 /* --------------------------------------------------------------------------------------------- */
749 /* ------------------------------- mc support ---------------------------- */
751 static void
752 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
754 GList *iter;
756 for (iter = MEDATA->supers; iter != NULL; iter = g_list_next (iter))
758 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
759 char *name;
761 name = g_strconcat (super->name, "#", me->prefix, "/",
762 /* super->current_dir->name, */ (char *) NULL);
763 func (name);
764 g_free (name);
768 /* --------------------------------------------------------------------------------------------- */
770 static int
771 vfs_s_ferrno (struct vfs_class *me)
773 return me->verrno;
776 /* --------------------------------------------------------------------------------------------- */
778 * Get local copy of the given file. We reuse the existing file cache
779 * for remote filesystems. Archives use standard VFS facilities.
782 static char *
783 vfs_s_getlocalcopy (const vfs_path_t * vpath)
785 vfs_file_handler_t *fh;
786 char *local = NULL;
788 fh = vfs_s_open (vpath, O_RDONLY, 0);
790 if (fh != NULL)
792 if ((fh->ino != NULL) && (fh->ino->localname != NULL))
793 local = g_strdup (fh->ino->localname);
795 vfs_s_close (fh);
798 return local;
801 /* --------------------------------------------------------------------------------------------- */
803 * Return the local copy. Since we are using our cache, we do nothing -
804 * the cache will be removed when the archive is closed.
807 static int
808 vfs_s_ungetlocalcopy (const vfs_path_t * vpath, const char *local, int has_changed)
810 (void) vpath;
811 (void) local;
812 (void) has_changed;
813 return 0;
816 /* --------------------------------------------------------------------------------------------- */
818 static int
819 vfs_s_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
821 vfs_path_element_t *path_element;
823 path_element = vfs_path_get_by_index (vpath, -1);
824 switch (ctlop)
826 case VFS_SETCTL_STALE_DATA:
828 struct vfs_s_inode *ino = vfs_s_inode_from_path (vpath, 0);
830 if (ino == NULL)
831 return 0;
832 if (arg)
833 ino->super->want_stale = 1;
834 else
836 ino->super->want_stale = 0;
837 vfs_s_invalidate (path_element->class, ino->super);
839 return 1;
841 case VFS_SETCTL_LOGFILE:
842 ((struct vfs_s_subclass *) path_element->class->data)->logfile = fopen ((char *) arg, "w");
843 return 1;
844 case VFS_SETCTL_FLUSH:
845 ((struct vfs_s_subclass *) path_element->class->data)->flush = 1;
846 return 1;
848 return 0;
851 /* --------------------------------------------------------------------------------------------- */
852 /* ----------------------------- Stamping support -------------------------- */
854 static vfsid
855 vfs_s_getid (const vfs_path_t * vpath)
857 struct vfs_s_super *archive = NULL;
858 char *p;
860 p = vfs_s_get_path (vpath, &archive, FL_NO_OPEN);
861 if (p == NULL)
862 return NULL;
863 g_free (p);
864 return (vfsid) archive;
867 /* --------------------------------------------------------------------------------------------- */
869 static int
870 vfs_s_nothingisopen (vfsid id)
872 (void) id;
873 /* Our data structures should survive free of superblock at any time */
874 return 1;
877 /* --------------------------------------------------------------------------------------------- */
879 static void
880 vfs_s_free (vfsid id)
882 vfs_s_free_super (((struct vfs_s_super *) id)->me, (struct vfs_s_super *) id);
885 /* --------------------------------------------------------------------------------------------- */
887 static int
888 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
890 struct timeval tim;
892 if (MEDATA->flush)
894 MEDATA->flush = 0;
895 return 0;
898 gettimeofday (&tim, NULL);
899 if (tim.tv_sec < ino->timestamp.tv_sec)
900 return 1;
901 return 0;
905 /* --------------------------------------------------------------------------------------------- */
906 /*** public functions ****************************************************************************/
907 /* --------------------------------------------------------------------------------------------- */
909 struct vfs_s_inode *
910 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
912 struct vfs_s_inode *ino;
914 ino = g_try_new0 (struct vfs_s_inode, 1);
915 if (ino == NULL)
916 return NULL;
918 if (initstat)
919 ino->st = *initstat;
920 ino->super = super;
921 ino->st.st_nlink = 0;
922 ino->st.st_ino = MEDATA->inode_counter++;
923 ino->st.st_dev = MEDATA->rdev;
925 super->ino_usage++;
926 total_inodes++;
928 CALL (init_inode) (me, ino);
930 return ino;
933 /* --------------------------------------------------------------------------------------------- */
935 struct vfs_s_entry *
936 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
938 struct vfs_s_entry *entry;
940 entry = g_new0 (struct vfs_s_entry, 1);
941 total_entries++;
943 entry->name = g_strdup (name);
944 entry->ino = inode;
945 entry->ino->ent = entry;
946 CALL (init_entry) (me, entry);
948 return entry;
952 /* --------------------------------------------------------------------------------------------- */
954 void
955 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
957 if (ent->dir != NULL)
958 ent->dir->subdir = g_list_remove (ent->dir->subdir, ent);
960 g_free (ent->name);
961 /* ent->name = NULL; */
963 if (ent->ino != NULL)
965 ent->ino->ent = NULL;
966 vfs_s_free_inode (me, ent->ino);
969 total_entries--;
970 g_free (ent);
973 /* --------------------------------------------------------------------------------------------- */
975 void
976 vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
978 (void) me;
980 ent->dir = dir;
982 ent->ino->st.st_nlink++;
983 dir->subdir = g_list_append (dir->subdir, ent);
986 /* --------------------------------------------------------------------------------------------- */
988 struct stat *
989 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
991 static struct stat st;
992 int myumask;
994 (void) me;
996 myumask = umask (022);
997 umask (myumask);
998 mode &= ~myumask;
1000 st.st_mode = mode;
1001 st.st_ino = 0;
1002 st.st_dev = 0;
1003 st.st_rdev = 0;
1004 st.st_uid = getuid ();
1005 st.st_gid = getgid ();
1006 st.st_size = 0;
1007 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
1009 return &st;
1012 /* --------------------------------------------------------------------------------------------- */
1014 struct vfs_s_entry *
1015 vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent,
1016 mode_t mode)
1018 struct vfs_s_inode *inode;
1019 struct stat *st;
1021 st = vfs_s_default_stat (me, mode);
1022 inode = vfs_s_new_inode (me, parent->super, st);
1024 return vfs_s_new_entry (me, name, inode);
1027 /* --------------------------------------------------------------------------------------------- */
1029 struct vfs_s_inode *
1030 vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
1031 const char *path, int follow, int flags)
1033 struct vfs_s_entry *ent;
1035 if (((MEDATA->flags & VFS_S_REMOTE) == 0) && (*path == '\0'))
1036 return super->root;
1038 ent = (MEDATA->find_entry) (me, super->root, path, follow, flags);
1039 return (ent != NULL) ? ent->ino : NULL;
1042 /* --------------------------------------------------------------------------------------------- */
1043 /* Ook, these were functions around directory entries / inodes */
1044 /* -------------------------------- superblock games -------------------------- */
1047 * Dissect the path and create corresponding superblock. Note that inname
1048 * can be changed and the result may point inside the original string.
1050 const char *
1051 vfs_s_get_path_mangle (const vfs_path_t * vpath, struct vfs_s_super **archive, int flags)
1053 GList *iter;
1054 const char *retval;
1055 char *archive_name;
1056 int result = -1;
1057 struct vfs_s_super *super;
1058 void *cookie = NULL;
1059 vfs_path_element_t *path_element;
1060 struct vfs_s_subclass *subclass;
1062 path_element = vfs_path_get_by_index (vpath, -1);
1063 subclass = ((struct vfs_s_subclass *) path_element->class->data);
1065 archive_name = vfs_path_to_str_elements_count (vpath, -1);
1066 retval = (path_element->path != NULL) ? path_element->path : "";
1068 if (subclass->archive_check != NULL)
1070 cookie =
1071 subclass->archive_check (path_element->class, archive_name, path_element->raw_url_str);
1072 if (cookie == NULL)
1074 g_free (archive_name);
1075 return NULL;
1079 for (iter = subclass->supers; iter != NULL; iter = g_list_next (iter))
1081 int i;
1083 super = (struct vfs_s_super *) iter->data;
1085 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1086 i = subclass->archive_same (path_element->class, super, archive_name,
1087 path_element->raw_url_str, cookie);
1088 if (i != 0)
1090 if (i == 1)
1091 goto return_success;
1092 break;
1096 if (flags & FL_NO_OPEN)
1098 path_element->class->verrno = EIO;
1099 g_free (archive_name);
1100 return NULL;
1103 super = vfs_s_new_super (path_element->class);
1104 if (subclass->open_archive != NULL)
1105 result =
1106 subclass->open_archive (path_element->class, super, archive_name,
1107 path_element->raw_url_str);
1108 if (result == -1)
1110 vfs_s_free_super (path_element->class, super);
1111 path_element->class->verrno = EIO;
1112 g_free (archive_name);
1113 return NULL;
1115 if (!super->name)
1116 vfs_die ("You have to fill name\n");
1117 if (!super->root)
1118 vfs_die ("You have to fill root inode\n");
1120 vfs_s_insert_super (path_element->class, super);
1121 vfs_stamp_create (path_element->class, super);
1123 return_success:
1124 *archive = super;
1125 g_free (archive_name);
1126 return retval;
1129 /* --------------------------------------------------------------------------------------------- */
1131 void
1132 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
1134 if (!super->want_stale)
1136 vfs_s_free_inode (me, super->root);
1137 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
1141 /* --------------------------------------------------------------------------------------------- */
1143 char *
1144 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
1146 if (!ino->ent)
1147 ERRNOR (EAGAIN, NULL);
1149 if (!(MEDATA->flags & VFS_S_REMOTE))
1151 /* archives */
1152 char *newpath;
1153 char *path = g_strdup (ino->ent->name);
1154 while (1)
1156 ino = ino->ent->dir;
1157 if (ino == ino->super->root)
1158 break;
1159 newpath = g_strconcat (ino->ent->name, "/", path, (char *) NULL);
1160 g_free (path);
1161 path = newpath;
1163 return path;
1166 /* remote systems */
1167 if ((!ino->ent->dir) || (!ino->ent->dir->ent))
1168 return g_strdup (ino->ent->name);
1170 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, ino->ent->name, (char *) NULL);
1173 /* --------------------------------------------------------------------------------------------- */
1174 /* --------------------------- stat and friends ---------------------------- */
1176 void *
1177 vfs_s_open (const vfs_path_t * vpath, int flags, mode_t mode)
1179 int was_changed = 0;
1180 vfs_file_handler_t *fh;
1181 struct vfs_s_super *super;
1182 char *q;
1183 struct vfs_s_inode *ino;
1184 vfs_path_element_t *path_element;
1186 path_element = vfs_path_get_by_index (vpath, -1);
1188 q = vfs_s_get_path (vpath, &super, 0);
1189 if (q == NULL)
1190 return NULL;
1191 ino = vfs_s_find_inode (path_element->class, super, q, LINK_FOLLOW, FL_NONE);
1192 if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)))
1194 g_free (q);
1195 path_element->class->verrno = EEXIST;
1196 return NULL;
1198 if (!ino)
1200 char *dirname, *name, *save;
1201 struct vfs_s_entry *ent;
1202 struct vfs_s_inode *dir;
1203 int tmp_handle;
1205 /* If the filesystem is read-only, disable file creation */
1206 if (!(flags & O_CREAT) || !(path_element->class->write))
1208 g_free (q);
1209 return NULL;
1212 split_dir_name (path_element->class, q, &dirname, &name, &save);
1213 dir = vfs_s_find_inode (path_element->class, super, dirname, LINK_FOLLOW, FL_DIR);
1214 if (dir == NULL)
1216 g_free (q);
1217 return NULL;
1219 if (save)
1220 *save = PATH_SEP;
1221 ent = vfs_s_generate_entry (path_element->class, name, dir, 0755);
1222 ino = ent->ino;
1223 vfs_s_insert_entry (path_element->class, dir, ent);
1224 tmp_handle = vfs_mkstemps (&ino->localname, path_element->class->name, name);
1225 if (tmp_handle == -1)
1227 g_free (q);
1228 return NULL;
1230 close (tmp_handle);
1231 was_changed = 1;
1234 g_free (q);
1236 if (S_ISDIR (ino->st.st_mode))
1238 path_element->class->verrno = EISDIR;
1239 return NULL;
1242 fh = g_new (vfs_file_handler_t, 1);
1243 fh->pos = 0;
1244 fh->ino = ino;
1245 fh->handle = -1;
1246 fh->changed = was_changed;
1247 fh->linear = 0;
1248 fh->data = NULL;
1250 if (IS_LINEAR (flags))
1252 if (VFSDATA (path_element)->linear_start)
1254 vfs_print_message (_("Starting linear transfer..."));
1255 fh->linear = LS_LINEAR_PREOPEN;
1258 else if ((VFSDATA (path_element)->fh_open != NULL)
1259 && (VFSDATA (path_element)->fh_open (path_element->class, fh, flags, mode) != 0))
1261 g_free (fh);
1262 return NULL;
1265 if (fh->ino->localname)
1267 fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
1268 if (fh->handle == -1)
1270 g_free (fh);
1271 path_element->class->verrno = errno;
1272 return NULL;
1276 /* i.e. we had no open files and now we have one */
1277 vfs_rmstamp (path_element->class, (vfsid) super);
1278 super->fd_usage++;
1279 fh->ino->st.st_nlink++;
1280 return fh;
1283 /* --------------------------------------------------------------------------------------------- */
1286 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
1288 /* If you want reget, you'll have to open file with O_LINEAR */
1289 off_t total = 0;
1290 char buffer[8192];
1291 int handle, n;
1292 off_t stat_size = ino->st.st_size;
1293 vfs_file_handler_t fh;
1295 memset (&fh, 0, sizeof (fh));
1297 fh.ino = ino;
1298 fh.handle = -1;
1300 handle = vfs_mkstemps (&ino->localname, me->name, ino->ent->name);
1301 if (handle == -1)
1303 me->verrno = errno;
1304 goto error_4;
1307 if (!MEDATA->linear_start (me, &fh, 0))
1308 goto error_3;
1310 /* Clear the interrupt status */
1311 tty_got_interrupt ();
1312 tty_enable_interrupt_key ();
1314 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof (buffer))))
1316 int t;
1317 if (n < 0)
1318 goto error_1;
1320 total += n;
1321 vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name, total, stat_size);
1323 if (tty_got_interrupt ())
1324 goto error_1;
1326 t = write (handle, buffer, n);
1327 if (t != n)
1329 if (t == -1)
1330 me->verrno = errno;
1331 goto error_1;
1334 MEDATA->linear_close (me, &fh);
1335 close (handle);
1337 tty_disable_interrupt_key ();
1338 g_free (fh.data);
1339 return 0;
1341 error_1:
1342 MEDATA->linear_close (me, &fh);
1343 error_3:
1344 tty_disable_interrupt_key ();
1345 close (handle);
1346 unlink (ino->localname);
1347 error_4:
1348 g_free (ino->localname);
1349 ino->localname = NULL;
1350 g_free (fh.data);
1351 return -1;
1354 /* --------------------------------------------------------------------------------------------- */
1355 /* ----------------------------- Stamping support -------------------------- */
1357 /* Initialize one of our subclasses - fill common functions */
1358 void
1359 vfs_s_init_class (struct vfs_class *vclass, struct vfs_s_subclass *sub)
1361 vclass->data = sub;
1362 vclass->fill_names = vfs_s_fill_names;
1363 vclass->open = vfs_s_open;
1364 vclass->close = vfs_s_close;
1365 vclass->read = vfs_s_read;
1366 if (!(sub->flags & VFS_S_READONLY))
1368 vclass->write = vfs_s_write;
1370 vclass->opendir = vfs_s_opendir;
1371 vclass->readdir = vfs_s_readdir;
1372 vclass->closedir = vfs_s_closedir;
1373 vclass->stat = vfs_s_stat;
1374 vclass->lstat = vfs_s_lstat;
1375 vclass->fstat = vfs_s_fstat;
1376 vclass->readlink = vfs_s_readlink;
1377 vclass->chdir = vfs_s_chdir;
1378 vclass->ferrno = vfs_s_ferrno;
1379 vclass->lseek = vfs_s_lseek;
1380 vclass->getid = vfs_s_getid;
1381 vclass->nothingisopen = vfs_s_nothingisopen;
1382 vclass->free = vfs_s_free;
1383 if (sub->flags & VFS_S_REMOTE)
1385 vclass->getlocalcopy = vfs_s_getlocalcopy;
1386 vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1387 sub->find_entry = vfs_s_find_entry_linear;
1389 else
1391 sub->find_entry = vfs_s_find_entry_tree;
1393 vclass->setctl = vfs_s_setctl;
1394 sub->dir_uptodate = vfs_s_dir_uptodate;
1397 /* --------------------------------------------------------------------------------------------- */
1398 /** Find VFS id for given directory name */
1400 vfsid
1401 vfs_getid (const vfs_path_t * vpath)
1403 vfs_path_element_t *path_element;
1405 path_element = vfs_path_get_by_index (vpath, -1);
1406 if (path_element == NULL || path_element->class->getid == NULL)
1407 return NULL;
1409 return (*path_element->class->getid) (vpath);
1412 /* --------------------------------------------------------------------------------------------- */
1413 /* ----------- Utility functions for networked filesystems -------------- */
1415 #ifdef ENABLE_VFS_NET
1417 vfs_s_select_on_two (int fd1, int fd2)
1419 fd_set set;
1420 struct timeval time_out;
1421 int v;
1422 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1424 time_out.tv_sec = 1;
1425 time_out.tv_usec = 0;
1426 FD_ZERO (&set);
1427 FD_SET (fd1, &set);
1428 FD_SET (fd2, &set);
1429 v = select (maxfd, &set, 0, 0, &time_out);
1430 if (v <= 0)
1431 return v;
1432 if (FD_ISSET (fd1, &set))
1433 return 1;
1434 if (FD_ISSET (fd2, &set))
1435 return 2;
1436 return -1;
1439 /* --------------------------------------------------------------------------------------------- */
1442 vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
1444 FILE *logfile = MEDATA->logfile;
1445 int i;
1446 char c;
1448 for (i = 0; i < buf_len - 1; i++, buf++)
1450 if (read (sock, buf, sizeof (char)) <= 0)
1451 return 0;
1452 if (logfile)
1454 size_t ret1;
1455 int ret2;
1456 ret1 = fwrite (buf, 1, 1, logfile);
1457 ret2 = fflush (logfile);
1459 if (*buf == term)
1461 *buf = 0;
1462 return 1;
1466 /* Line is too long - terminate buffer and discard the rest of line */
1467 *buf = 0;
1468 while (read (sock, &c, sizeof (c)) > 0)
1470 if (logfile)
1472 size_t ret1;
1473 int ret2;
1474 ret1 = fwrite (&c, 1, 1, logfile);
1475 ret2 = fflush (logfile);
1477 if (c == '\n')
1478 return 1;
1480 return 0;
1483 /* --------------------------------------------------------------------------------------------- */
1486 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
1488 int n;
1489 int i;
1491 (void) me;
1493 tty_enable_interrupt_key ();
1494 for (i = 0; i < size - 1; i++)
1496 n = read (fd, buffer + i, 1);
1497 tty_disable_interrupt_key ();
1498 if (n == -1 && errno == EINTR)
1500 buffer[i] = 0;
1501 return EINTR;
1503 if (n == 0)
1505 buffer[i] = 0;
1506 return 0;
1508 if (buffer[i] == '\n')
1510 buffer[i] = 0;
1511 return 1;
1514 buffer[size - 1] = 0;
1515 return 0;
1517 #endif /* ENABLE_VFS_NET */
1519 /* --------------------------------------------------------------------------------------------- */