Removed bundled slang
[midnight-commander.git] / vfs / direntry.c
blob852c5cb02fee47ce90cb41463c33ab824d62fff0
1 /* Directory cache support -- so that you do not have copy of this in
2 * each and every filesystem.
4 * Written at 1998 by Pavel Machek <pavel@ucw.cz>, distribute under LGPL.
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 * Paths here do _not_ begin with '/', so root directory of
25 * archive/site is simply "". Beware. */
27 #include <config.h>
28 #include <errno.h>
30 #include "../src/global.h"
31 #include "../src/tty.h" /* enable/disable interrupt key */
32 #include "../src/wtools.h" /* message() */
33 #include "../src/main.h" /* print_vfs_message */
34 #include "utilvfs.h"
35 #include "vfs-impl.h"
36 #include "gc.h" /* vfs_rmstamp */
37 #include "xdirentry.h"
39 #define CALL(x) if (MEDATA->x) MEDATA->x
41 static volatile int total_inodes = 0, total_entries = 0;
43 struct vfs_s_inode *
44 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
46 struct vfs_s_inode *ino;
48 ino = g_new0 (struct vfs_s_inode, 1);
49 if (!ino)
50 return NULL;
52 if (initstat)
53 ino->st = *initstat;
54 ino->super = super;
55 ino->st.st_nlink = 0;
56 ino->st.st_ino = MEDATA->inode_counter++;
57 ino->st.st_dev = MEDATA->rdev;
59 super->ino_usage++;
60 total_inodes++;
62 CALL (init_inode) (me, ino);
64 return ino;
67 struct vfs_s_entry *
68 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
70 struct vfs_s_entry *entry;
72 entry = g_new0 (struct vfs_s_entry, 1);
73 total_entries++;
75 if (name)
76 entry->name = g_strdup (name);
78 entry->ino = inode;
79 entry->ino->ent = entry;
80 CALL (init_entry) (me, entry);
82 return entry;
85 static void
86 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
88 if (!ino)
89 vfs_die ("Don't pass NULL to me");
91 /* ==0 can happen if freshly created entry is deleted */
92 if (ino->st.st_nlink <= 1){
93 while (ino->subdir){
94 vfs_s_free_entry (me, ino->subdir);
97 CALL (free_inode) (me, ino);
98 g_free (ino->linkname);
99 if (ino->localname){
100 unlink (ino->localname);
101 g_free(ino->localname);
103 total_inodes--;
104 ino->super->ino_usage--;
105 g_free(ino);
106 } else ino->st.st_nlink--;
109 void
110 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
112 if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
113 *ent->prevp = ent->next;
114 if (ent->next)
115 ent->next->prevp = ent->prevp;
118 g_free (ent->name);
119 ent->name = NULL;
121 if (ent->ino){
122 ent->ino->ent = NULL;
123 vfs_s_free_inode (me, ent->ino);
124 ent->ino = NULL;
127 total_entries--;
128 g_free(ent);
131 void
132 vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
134 struct vfs_s_entry **ep;
136 (void) me;
138 for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
140 ent->prevp = ep;
141 ent->next = NULL;
142 ent->dir = dir;
143 *ep = ent;
145 ent->ino->st.st_nlink++;
148 struct stat *
149 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
151 static struct stat st;
152 int myumask;
154 (void) me;
156 myumask = umask (022);
157 umask (myumask);
158 mode &= ~myumask;
160 st.st_mode = mode;
161 st.st_ino = 0;
162 st.st_dev = 0;
163 st.st_rdev = 0;
164 st.st_uid = getuid ();
165 st.st_gid = getgid ();
166 st.st_size = 0;
167 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
169 return &st;
172 struct vfs_s_entry *
173 vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent, mode_t mode)
175 struct vfs_s_inode *inode;
176 struct stat *st;
178 st = vfs_s_default_stat (me, mode);
179 inode = vfs_s_new_inode (me, parent->super, st);
181 return vfs_s_new_entry (me, name, inode);
184 /* We were asked to create entries automagically */
185 static struct vfs_s_entry *
186 vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
188 struct vfs_s_entry *res;
189 char *sep = strchr (path, PATH_SEP);
191 if (sep)
192 *sep = 0;
193 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
194 vfs_s_insert_entry (me, dir, res);
196 if (sep)
197 *sep = PATH_SEP;
199 return res;
202 /* If the entry is a symlink, find the entry for its target */
203 static struct vfs_s_entry *
204 vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry,
205 int follow)
207 char *linkname;
208 char *fullname = NULL;
209 struct vfs_s_entry *target;
211 if (follow == LINK_NO_FOLLOW)
212 return entry;
213 if (follow == 0)
214 ERRNOR (ELOOP, NULL);
215 if (!entry)
216 ERRNOR (ENOENT, NULL);
217 if (!S_ISLNK (entry->ino->st.st_mode))
218 return entry;
220 linkname = entry->ino->linkname;
221 if (linkname == NULL)
222 ERRNOR (EFAULT, NULL);
224 /* make full path from relative */
225 if (*linkname != PATH_SEP) {
226 char *fullpath = vfs_s_fullpath (me, entry->dir);
227 if (fullpath) {
228 fullname = g_strconcat (fullpath, "/", linkname, NULL);
229 linkname = fullname;
230 g_free (fullpath);
234 target =
235 (MEDATA->find_entry) (me, entry->dir->super->root, linkname,
236 follow - 1, 0);
237 g_free (fullname);
238 return target;
242 * Follow > 0: follow links, serves as loop protect,
243 * == -1: do not follow links
245 static struct vfs_s_entry *
246 vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
247 const char *a_path, int follow, int flags)
249 size_t pseg;
250 struct vfs_s_entry *ent = NULL;
251 char * const pathref = g_strdup (a_path);
252 char *path = pathref;
254 canonicalize_pathname (path);
256 while (root) {
257 while (*path == PATH_SEP) /* Strip leading '/' */
258 path++;
260 if (!path[0]) {
261 g_free (pathref);
262 return ent;
265 for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++);
267 for (ent = root->subdir; ent != NULL; ent = ent->next)
268 if (strlen (ent->name) == pseg
269 && (!strncmp (ent->name, path, pseg)))
270 /* FOUND! */
271 break;
273 if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
274 ent = vfs_s_automake (me, root, path, flags);
275 if (!ent) {
276 me->verrno = ENOENT;
277 goto cleanup;
279 path += pseg;
280 /* here we must follow leading directories always;
281 only the actual file is optional */
282 ent =
283 vfs_s_resolve_symlink (me, ent,
284 strchr (path,
285 PATH_SEP) ? LINK_FOLLOW :
286 follow);
287 if (!ent)
288 goto cleanup;
289 root = ent->ino;
291 cleanup:
292 g_free (pathref);
293 return NULL;
296 static void
297 split_dir_name (struct vfs_class *me, char *path, char **dir, char **name, char **save)
299 char *s;
301 (void) me;
303 s = strrchr (path, PATH_SEP);
304 if (s == NULL) {
305 *save = NULL;
306 *name = path;
307 *dir = path + strlen(path); /* an empty string */
308 } else {
309 *save = s;
310 *dir = path;
311 *s++ = '\0';
312 *name = s;
316 static struct vfs_s_entry *
317 vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
318 const char *a_path, int follow, int flags)
320 struct vfs_s_entry *ent = NULL;
321 char * const path = g_strdup (a_path);
322 struct vfs_s_entry *retval = NULL;
324 if (root->super->root != root)
325 vfs_die ("We have to use _real_ root. Always. Sorry.");
327 canonicalize_pathname (path);
329 if (!(flags & FL_DIR)) {
330 char *dirname, *name, *save;
331 struct vfs_s_inode *ino;
332 split_dir_name (me, path, &dirname, &name, &save);
333 ino =
334 vfs_s_find_inode (me, root->super, dirname, follow,
335 flags | FL_DIR);
336 if (save)
337 *save = PATH_SEP;
338 retval = vfs_s_find_entry_tree (me, ino, name, follow, flags);
339 g_free (path);
340 return retval;
343 for (ent = root->subdir; ent != NULL; ent = ent->next)
344 if (!strcmp (ent->name, path))
345 break;
347 if (ent && (!(MEDATA->dir_uptodate) (me, ent->ino))) {
348 #if 1
349 print_vfs_message (_("Directory cache expired for %s"), path);
350 #endif
351 vfs_s_free_entry (me, ent);
352 ent = NULL;
355 if (!ent) {
356 struct vfs_s_inode *ino;
358 ino =
359 vfs_s_new_inode (me, root->super,
360 vfs_s_default_stat (me, S_IFDIR | 0755));
361 ent = vfs_s_new_entry (me, path, ino);
362 if ((MEDATA->dir_load) (me, ino, path) == -1) {
363 vfs_s_free_entry (me, ent);
364 g_free (path);
365 return NULL;
367 vfs_s_insert_entry (me, root, ent);
369 for (ent = root->subdir; ent != NULL; ent = ent->next)
370 if (!strcmp (ent->name, path))
371 break;
373 if (!ent)
374 vfs_die ("find_linear: success but directory is not there\n");
376 #if 0
377 if (!vfs_s_resolve_symlink (me, ent, follow)) {
378 g_free (path);
379 return NULL;
381 #endif
382 g_free (path);
383 return ent;
386 struct vfs_s_inode *
387 vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
388 const char *path, int follow, int flags)
390 struct vfs_s_entry *ent;
391 if (!(MEDATA->flags & VFS_S_REMOTE) && (!*path))
392 return super->root;
393 ent = (MEDATA->find_entry) (me, super->root, path, follow, flags);
394 if (!ent)
395 return NULL;
396 return ent->ino;
399 /* Ook, these were functions around directory entries / inodes */
400 /* -------------------------------- superblock games -------------------------- */
402 static struct vfs_s_super *
403 vfs_s_new_super (struct vfs_class *me)
405 struct vfs_s_super *super;
407 super = g_new0 (struct vfs_s_super, 1);
408 super->me = me;
409 return super;
412 static void
413 vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
415 super->next = MEDATA->supers;
416 super->prevp = &MEDATA->supers;
418 if (MEDATA->supers != NULL)
419 MEDATA->supers->prevp = &super->next;
420 MEDATA->supers = super;
423 static void
424 vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
426 if (super->root){
427 vfs_s_free_inode (me, super->root);
428 super->root = NULL;
431 #if 0
432 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
433 if (super->ino_usage)
434 message (D_ERROR, " Direntry warning ",
435 "Super ino_usage is %d, memory leak",
436 super->ino_usage);
438 if (super->want_stale)
439 message (D_ERROR, " Direntry warning ", "Super has want_stale set");
440 #endif
442 if (super->prevp){
443 *super->prevp = super->next;
444 if (super->next)
445 super->next->prevp = super->prevp;
448 CALL (free_archive) (me, super);
449 g_free (super->name);
450 g_free(super);
455 * Dissect the path and create corresponding superblock. Note that inname
456 * can be changed and the result may point inside the original string.
458 const char *
459 vfs_s_get_path_mangle (struct vfs_class *me, char *inname,
460 struct vfs_s_super **archive, int flags)
462 const char *retval;
463 char *local, *op;
464 const char *archive_name;
465 int result = -1;
466 struct vfs_s_super *super;
467 void *cookie = NULL;
469 archive_name = inname;
470 vfs_split (inname, &local, &op);
471 retval = (local) ? local : "";
473 if (MEDATA->archive_check)
474 if (!(cookie = MEDATA->archive_check (me, archive_name, op)))
475 return NULL;
477 for (super = MEDATA->supers; super != NULL; super = super->next) {
478 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
479 int i;
480 if ((i =
481 MEDATA->archive_same (me, super, archive_name, op, cookie))) {
482 if (i == 1)
483 goto return_success;
484 else
485 break;
489 if (flags & FL_NO_OPEN)
490 ERRNOR (EIO, NULL);
492 super = vfs_s_new_super (me);
493 result = MEDATA->open_archive (me, super, archive_name, op);
494 if (result == -1) {
495 vfs_s_free_super (me, super);
496 ERRNOR (EIO, NULL);
498 if (!super->name)
499 vfs_die ("You have to fill name\n");
500 if (!super->root)
501 vfs_die ("You have to fill root inode\n");
503 vfs_s_insert_super (me, super);
504 vfs_stamp_create (me, super);
506 return_success:
507 *archive = super;
508 return retval;
513 * Dissect the path and create corresponding superblock.
514 * The result should be freed.
516 static char *
517 vfs_s_get_path (struct vfs_class *me, const char *inname,
518 struct vfs_s_super **archive, int flags)
520 char *buf, *retval;
522 buf = g_strdup (inname);
523 retval = g_strdup (vfs_s_get_path_mangle (me, buf, archive, flags));
524 g_free (buf);
525 return retval;
528 void
529 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
531 if (!super->want_stale){
532 vfs_s_free_inode (me, super->root);
533 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
537 char *
538 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
540 if (!ino->ent)
541 ERRNOR (EAGAIN, NULL);
543 if (!(MEDATA->flags & VFS_S_REMOTE)) {
544 /* archives */
545 char *newpath;
546 char *path = g_strdup (ino->ent->name);
547 while (1) {
548 ino = ino->ent->dir;
549 if (ino == ino->super->root)
550 break;
551 newpath = g_strconcat (ino->ent->name, "/", path, (char *) NULL);
552 g_free (path);
553 path = newpath;
555 return path;
558 /* remote systems */
559 if ((!ino->ent->dir) || (!ino->ent->dir->ent))
560 return g_strdup (ino->ent->name);
562 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR,
563 ino->ent->name, (char *) NULL);
566 /* Support of archives */
567 /* ------------------------ readdir & friends ----------------------------- */
569 static struct vfs_s_inode *
570 vfs_s_inode_from_path (struct vfs_class *me, const char *name, int flags)
572 struct vfs_s_super *super;
573 struct vfs_s_inode *ino;
574 char *q;
576 if (!(q = vfs_s_get_path (me, name, &super, 0)))
577 return NULL;
579 ino =
580 vfs_s_find_inode (me, super, q,
581 flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW,
582 flags & ~FL_FOLLOW);
583 if ((!ino) && (!*q))
584 /* We are asking about / directory of ftp server: assume it exists */
585 ino =
586 vfs_s_find_inode (me, super, q,
587 flags & FL_FOLLOW ? LINK_FOLLOW :
588 LINK_NO_FOLLOW,
589 FL_DIR | (flags & ~FL_FOLLOW));
590 g_free (q);
591 return ino;
594 struct dirhandle {
595 struct vfs_s_entry *cur;
596 struct vfs_s_inode *dir;
599 static void *
600 vfs_s_opendir (struct vfs_class *me, const char *dirname)
602 struct vfs_s_inode *dir;
603 struct dirhandle *info;
605 dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
606 if (!dir)
607 return NULL;
608 if (!S_ISDIR (dir->st.st_mode))
609 ERRNOR (ENOTDIR, NULL);
611 dir->st.st_nlink++;
612 #if 0
613 if (!dir->subdir) /* This can actually happen if we allow empty directories */
614 ERRNOR (EAGAIN, NULL);
615 #endif
616 info = g_new (struct dirhandle, 1);
617 info->cur = dir->subdir;
618 info->dir = dir;
620 return info;
623 static void *
624 vfs_s_readdir(void *data)
626 static union vfs_dirent dir;
627 struct dirhandle *info = (struct dirhandle *) data;
629 if (!(info->cur))
630 return NULL;
632 if (info->cur->name) {
633 g_strlcpy (dir.dent.d_name, info->cur->name, MC_MAXPATHLEN);
634 } else {
635 vfs_die("Null in structure-cannot happen");
638 compute_namelen(&dir.dent);
639 info->cur = info->cur->next;
641 return (void *) &dir;
644 static int
645 vfs_s_closedir (void *data)
647 struct dirhandle *info = (struct dirhandle *) data;
648 struct vfs_s_inode *dir = info->dir;
650 vfs_s_free_inode (dir->super->me, dir);
651 g_free (data);
652 return 0;
655 static int
656 vfs_s_chdir (struct vfs_class *me, const char *path)
658 void *data;
659 if (!(data = vfs_s_opendir (me, path)))
660 return -1;
661 vfs_s_closedir (data);
662 return 0;
665 /* --------------------------- stat and friends ---------------------------- */
667 static int
668 vfs_s_internal_stat (struct vfs_class *me, const char *path, struct stat *buf, int flag)
670 struct vfs_s_inode *ino;
672 if (!(ino = vfs_s_inode_from_path (me, path, flag)))
673 return -1;
674 *buf = ino->st;
675 return 0;
678 static int
679 vfs_s_stat (struct vfs_class *me, const char *path, struct stat *buf)
681 return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
684 static int
685 vfs_s_lstat (struct vfs_class *me, const char *path, struct stat *buf)
687 return vfs_s_internal_stat (me, path, buf, FL_NONE);
690 static int
691 vfs_s_fstat (void *fh, struct stat *buf)
693 *buf = FH->ino->st;
694 return 0;
697 static int
698 vfs_s_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
700 struct vfs_s_inode *ino;
701 size_t len;
703 ino = vfs_s_inode_from_path (me, path, 0);
704 if (!ino)
705 return -1;
707 if (!S_ISLNK (ino->st.st_mode))
708 ERRNOR (EINVAL, -1);
710 if (ino->linkname == NULL)
711 ERRNOR (EFAULT, -1);
713 len = strlen (ino->linkname);
714 if (size < len)
715 len = size;
716 /* readlink() does not append a NUL character to buf */
717 memcpy (buf, ino->linkname, len);
718 return len;
721 static void *
722 vfs_s_open (struct vfs_class *me, const char *file, int flags, int mode)
724 int was_changed = 0;
725 struct vfs_s_fh *fh;
726 struct vfs_s_super *super;
727 char *q;
728 struct vfs_s_inode *ino;
730 if ((q = vfs_s_get_path (me, file, &super, 0)) == NULL)
731 return NULL;
732 ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
733 if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
734 g_free (q);
735 ERRNOR (EEXIST, NULL);
737 if (!ino) {
738 char *dirname, *name, *save;
739 struct vfs_s_entry *ent;
740 struct vfs_s_inode *dir;
741 int tmp_handle;
743 /* If the filesystem is read-only, disable file creation */
744 if (!(flags & O_CREAT) || !(me->write)) {
745 g_free (q);
746 return NULL;
749 split_dir_name (me, q, &dirname, &name, &save);
750 /* FIXME: check if vfs_s_find_inode returns NULL */
751 dir = vfs_s_find_inode (me, super, dirname, LINK_FOLLOW, FL_DIR);
752 if (save)
753 *save = PATH_SEP;
754 ent = vfs_s_generate_entry (me, name, dir, 0755);
755 ino = ent->ino;
756 vfs_s_insert_entry (me, dir, ent);
757 tmp_handle = vfs_mkstemps (&ino->localname, me->name, name);
758 if (tmp_handle == -1) {
759 g_free (q);
760 return NULL;
762 close (tmp_handle);
763 was_changed = 1;
766 g_free (q);
768 if (S_ISDIR (ino->st.st_mode))
769 ERRNOR (EISDIR, NULL);
771 fh = g_new (struct vfs_s_fh, 1);
772 fh->pos = 0;
773 fh->ino = ino;
774 fh->handle = -1;
775 fh->changed = was_changed;
776 fh->linear = 0;
778 if (IS_LINEAR (flags)) {
779 if (MEDATA->linear_start) {
780 print_vfs_message (_("Starting linear transfer..."));
781 fh->linear = LS_LINEAR_PREOPEN;
783 } else if ((MEDATA->fh_open)
784 && (MEDATA->fh_open (me, fh, flags, mode))) {
785 g_free (fh);
786 return NULL;
789 if (fh->ino->localname) {
790 fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
791 if (fh->handle == -1) {
792 g_free (fh);
793 ERRNOR (errno, NULL);
797 /* i.e. we had no open files and now we have one */
798 vfs_rmstamp (me, (vfsid) super);
799 super->fd_usage++;
800 fh->ino->st.st_nlink++;
801 return fh;
804 static ssize_t
805 vfs_s_read (void *fh, char *buffer, int count)
807 int n;
808 struct vfs_class *me = FH_SUPER->me;
810 if (FH->linear == LS_LINEAR_PREOPEN) {
811 if (!MEDATA->linear_start (me, FH, FH->pos))
812 return -1;
815 if (FH->linear == LS_LINEAR_CLOSED)
816 vfs_die ("linear_start() did not set linear_state!");
818 if (FH->linear == LS_LINEAR_OPEN)
819 return MEDATA->linear_read (me, FH, buffer, count);
821 if (FH->handle != -1){
822 n = read (FH->handle, buffer, count);
823 if (n < 0)
824 me->verrno = errno;
825 return n;
827 vfs_die ("vfs_s_read: This should not happen\n");
828 return -1;
831 static int
832 vfs_s_write (void *fh, const char *buffer, int count)
834 int n;
835 struct vfs_class *me = FH_SUPER->me;
837 if (FH->linear)
838 vfs_die ("no writing to linear files, please");
840 FH->changed = 1;
841 if (FH->handle != -1){
842 n = write (FH->handle, buffer, count);
843 if (n < 0)
844 me->verrno = errno;
845 return n;
847 vfs_die ("vfs_s_write: This should not happen\n");
848 return 0;
851 static off_t
852 vfs_s_lseek (void *fh, off_t offset, int whence)
854 off_t size = FH->ino->st.st_size;
856 if (FH->linear == LS_LINEAR_OPEN)
857 vfs_die ("cannot lseek() after linear_read!");
859 if (FH->handle != -1){ /* If we have local file opened, we want to work with it */
860 int retval = lseek (FH->handle, offset, whence);
861 if (retval == -1)
862 FH->ino->super->me->verrno = errno;
863 return retval;
866 switch (whence){
867 case SEEK_CUR:
868 offset += FH->pos; break;
869 case SEEK_END:
870 offset += size; break;
872 if (offset < 0)
873 FH->pos = 0;
874 else if (offset < size)
875 FH->pos = offset;
876 else
877 FH->pos = size;
878 return FH->pos;
881 static int
882 vfs_s_close (void *fh)
884 int res = 0;
885 struct vfs_class *me = FH_SUPER->me;
887 FH_SUPER->fd_usage--;
888 if (!FH_SUPER->fd_usage)
889 vfs_stamp_create (me, FH_SUPER);
891 if (FH->linear == LS_LINEAR_OPEN)
892 MEDATA->linear_close (me, fh);
893 if (MEDATA->fh_close)
894 res = MEDATA->fh_close (me, fh);
895 if (FH->changed && MEDATA->file_store){
896 char *s = vfs_s_fullpath (me, FH->ino);
897 if (!s)
898 res = -1;
899 else {
900 res = MEDATA->file_store (me, fh, s, FH->ino->localname);
901 g_free (s);
903 vfs_s_invalidate (me, FH_SUPER);
905 if (FH->handle != -1)
906 close (FH->handle);
908 vfs_s_free_inode (me, FH->ino);
909 g_free (fh);
910 return res;
913 static void
914 vfs_s_print_stats (const char *fs_name, const char *action,
915 const char *file_name, off_t have, off_t need)
917 static const char *i18n_percent_transf_format = NULL;
918 static const char *i18n_transf_format = NULL;
920 if (i18n_percent_transf_format == NULL) {
921 i18n_percent_transf_format =
922 _("%s: %s: %s %3d%% (%lu bytes transferred)");
923 i18n_transf_format = _("%s: %s: %s %lu bytes transferred");
926 if (need)
927 print_vfs_message (i18n_percent_transf_format, fs_name, action,
928 file_name, (int) ((double) have * 100 / need),
929 (unsigned long) have);
930 else
931 print_vfs_message (i18n_transf_format, fs_name, action, file_name,
932 (unsigned long) have);
936 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
938 /* If you want reget, you'll have to open file with O_LINEAR */
939 off_t total = 0;
940 char buffer[8192];
941 int handle, n;
942 off_t stat_size = ino->st.st_size;
943 struct vfs_s_fh fh;
945 memset (&fh, 0, sizeof (fh));
947 fh.ino = ino;
948 fh.handle = -1;
950 handle = vfs_mkstemps (&ino->localname, me->name, ino->ent->name);
951 if (handle == -1) {
952 me->verrno = errno;
953 goto error_4;
956 if (!MEDATA->linear_start (me, &fh, 0))
957 goto error_3;
959 /* Clear the interrupt status */
960 got_interrupt ();
961 enable_interrupt_key ();
963 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof (buffer)))) {
964 int t;
965 if (n < 0)
966 goto error_1;
968 total += n;
969 vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name,
970 total, stat_size);
972 if (got_interrupt ())
973 goto error_1;
975 t = write (handle, buffer, n);
976 if (t != n) {
977 if (t == -1)
978 me->verrno = errno;
979 goto error_1;
982 MEDATA->linear_close (me, &fh);
983 close (handle);
985 disable_interrupt_key ();
986 return 0;
988 error_1:
989 MEDATA->linear_close (me, &fh);
990 error_3:
991 disable_interrupt_key ();
992 close (handle);
993 unlink (ino->localname);
994 error_4:
995 g_free (ino->localname);
996 ino->localname = NULL;
997 return -1;
1000 /* ------------------------------- mc support ---------------------------- */
1002 static void
1003 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
1005 struct vfs_s_super *a = MEDATA->supers;
1006 char *name;
1008 while (a){
1009 name = g_strconcat ( a->name, "#", me->prefix, "/", /* a->current_dir->name, */ NULL);
1010 (*func)(name);
1011 g_free (name);
1012 a = a->next;
1016 static int
1017 vfs_s_ferrno (struct vfs_class *me)
1019 return me->verrno;
1023 * Get local copy of the given file. We reuse the existing file cache
1024 * for remote filesystems. Archives use standard VFS facilities.
1026 static char *
1027 vfs_s_getlocalcopy (struct vfs_class *me, const char *path)
1029 struct vfs_s_fh *fh;
1030 char *local;
1032 fh = vfs_s_open (me, path, O_RDONLY, 0);
1033 if (!fh || !fh->ino || !fh->ino->localname)
1034 return NULL;
1036 local = g_strdup (fh->ino->localname);
1037 vfs_s_close (fh);
1038 return local;
1042 * Return the local copy. Since we are using our cache, we do nothing -
1043 * the cache will be removed when the archive is closed.
1045 static int
1046 vfs_s_ungetlocalcopy (struct vfs_class *me, const char *path,
1047 const char *local, int has_changed)
1049 (void) me;
1050 (void) path;
1051 (void) local;
1052 (void) has_changed;
1053 return 0;
1056 static int
1057 vfs_s_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
1059 switch (ctlop) {
1060 case VFS_SETCTL_STALE_DATA:
1062 struct vfs_s_inode *ino = vfs_s_inode_from_path (me, path, 0);
1064 if (!ino)
1065 return 0;
1066 if (arg)
1067 ino->super->want_stale = 1;
1068 else {
1069 ino->super->want_stale = 0;
1070 vfs_s_invalidate (me, ino->super);
1072 return 1;
1074 case VFS_SETCTL_LOGFILE:
1075 MEDATA->logfile = fopen ((char *) arg, "w");
1076 return 1;
1077 case VFS_SETCTL_FLUSH:
1078 MEDATA->flush = 1;
1079 return 1;
1081 return 0;
1085 /* ----------------------------- Stamping support -------------------------- */
1087 static vfsid
1088 vfs_s_getid (struct vfs_class *me, const char *path)
1090 struct vfs_s_super *archive;
1091 char *p;
1093 if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
1094 return NULL;
1095 g_free(p);
1096 return (vfsid) archive;
1099 static int
1100 vfs_s_nothingisopen (vfsid id)
1102 (void) id;
1103 /* Our data structures should survive free of superblock at any time */
1104 return 1;
1107 static void
1108 vfs_s_free (vfsid id)
1110 vfs_s_free_super (((struct vfs_s_super *)id)->me, (struct vfs_s_super *)id);
1113 static int
1114 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
1116 struct timeval tim;
1118 if (MEDATA->flush) {
1119 MEDATA->flush = 0;
1120 return 0;
1123 gettimeofday(&tim, NULL);
1124 if (tim.tv_sec < ino->timestamp.tv_sec)
1125 return 1;
1126 return 0;
1129 /* Initialize one of our subclasses - fill common functions */
1130 void
1131 vfs_s_init_class (struct vfs_class *vclass, struct vfs_s_subclass *sub)
1133 vclass->data = sub;
1134 vclass->fill_names = vfs_s_fill_names;
1135 vclass->open = vfs_s_open;
1136 vclass->close = vfs_s_close;
1137 vclass->read = vfs_s_read;
1138 if (!(sub->flags & VFS_S_READONLY)) {
1139 vclass->write = vfs_s_write;
1141 vclass->opendir = vfs_s_opendir;
1142 vclass->readdir = vfs_s_readdir;
1143 vclass->closedir = vfs_s_closedir;
1144 vclass->stat = vfs_s_stat;
1145 vclass->lstat = vfs_s_lstat;
1146 vclass->fstat = vfs_s_fstat;
1147 vclass->readlink = vfs_s_readlink;
1148 vclass->chdir = vfs_s_chdir;
1149 vclass->ferrno = vfs_s_ferrno;
1150 vclass->lseek = vfs_s_lseek;
1151 vclass->getid = vfs_s_getid;
1152 vclass->nothingisopen = vfs_s_nothingisopen;
1153 vclass->free = vfs_s_free;
1154 if (sub->flags & VFS_S_REMOTE) {
1155 vclass->getlocalcopy = vfs_s_getlocalcopy;
1156 vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1157 sub->find_entry = vfs_s_find_entry_linear;
1158 } else {
1159 sub->find_entry = vfs_s_find_entry_tree;
1161 vclass->setctl = vfs_s_setctl;
1162 sub->dir_uptodate = vfs_s_dir_uptodate;
1165 /* ----------- Utility functions for networked filesystems -------------- */
1167 #ifdef USE_NETCODE
1169 vfs_s_select_on_two (int fd1, int fd2)
1171 fd_set set;
1172 struct timeval timeout;
1173 int v;
1174 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1176 timeout.tv_sec = 1;
1177 timeout.tv_usec = 0;
1178 FD_ZERO (&set);
1179 FD_SET (fd1, &set);
1180 FD_SET (fd2, &set);
1181 v = select (maxfd, &set, 0, 0, &timeout);
1182 if (v <= 0)
1183 return v;
1184 if (FD_ISSET (fd1, &set))
1185 return 1;
1186 if (FD_ISSET (fd2, &set))
1187 return 2;
1188 return -1;
1192 vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
1194 FILE *logfile = MEDATA->logfile;
1195 int i;
1196 char c;
1198 for (i = 0; i < buf_len - 1; i++, buf++){
1199 if (read (sock, buf, sizeof(char)) <= 0)
1200 return 0;
1201 if (logfile){
1202 fwrite (buf, 1, 1, logfile);
1203 fflush (logfile);
1205 if (*buf == term){
1206 *buf = 0;
1207 return 1;
1211 /* Line is too long - terminate buffer and discard the rest of line */
1212 *buf = 0;
1213 while (read (sock, &c, sizeof (c)) > 0) {
1214 if (logfile){
1215 fwrite (&c, 1, 1, logfile);
1216 fflush (logfile);
1218 if (c == '\n')
1219 return 1;
1221 return 0;
1225 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
1227 int n;
1228 int i;
1230 (void) me;
1232 enable_interrupt_key ();
1233 for (i = 0; i < size-1; i++){
1234 n = read (fd, buffer+i, 1);
1235 disable_interrupt_key ();
1236 if (n == -1 && errno == EINTR){
1237 buffer [i] = 0;
1238 return EINTR;
1240 if (n == 0){
1241 buffer [i] = 0;
1242 return 0;
1244 if (buffer [i] == '\n'){
1245 buffer [i] = 0;
1246 return 1;
1249 buffer [size-1] = 0;
1250 return 0;
1252 #endif /* USE_NETCODE */