Fixed incorrect showing name of search library in summary screen
[midnight-commander.git] / vfs / direntry.c
blob5c22c9c11f27da1ce671a29788df74ef1ef200e2
2 /** \file
3 * \brief Source: directory cache support
5 * So that you do not have copy of this in each and every filesystem.
7 * Very loosely based on tar.c from midnight and archives.[ch] from
8 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
10 * Unfortunately, I was unable to keep all filesystems
11 * uniform. tar-like filesystems use tree structure where each
12 * directory has pointers to its subdirectories. We can do this
13 * because we have full information about our archive.
15 * At ftp-like filesystems, situation is a little bit different. When
16 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
17 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
18 * listed. That means that we do not have complete information, and if
19 * /usr is symlink to /4, we will not know. Also we have to time out
20 * entries and things would get messy with tree-like approach. So we
21 * do different trick: root directory is completely special and
22 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
23 * and we'll try to use custom find_entry function.
25 * \author Pavel Machek <pavel@ucw.cz>, distribute under LGPL.
26 * \date 1998
28 * \warning Paths here do _not_ begin with '/', so root directory of
29 * archive/site is simply "".
32 #include <config.h>
34 #include <errno.h>
35 #include <sys/fcntl.h>
36 #include <time.h>
37 #include <sys/time.h> /* gettimeofday() */
39 #include "../src/global.h"
41 #include "../src/tty/tty.h" /* enable/disable interrupt key */
43 #include "../src/wtools.h" /* message() */
44 #include "../src/main.h" /* print_vfs_message */
46 #include "utilvfs.h"
47 #include "vfs-impl.h"
48 #include "gc.h" /* vfs_rmstamp */
49 #include "xdirentry.h"
51 #define CALL(x) if (MEDATA->x) MEDATA->x
53 static volatile int total_inodes = 0, total_entries = 0;
55 struct vfs_s_inode *
56 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
58 struct vfs_s_inode *ino;
60 ino = g_try_new0 (struct vfs_s_inode, 1);
61 if (ino == NULL)
62 return NULL;
64 if (initstat)
65 ino->st = *initstat;
66 ino->super = super;
67 ino->st.st_nlink = 0;
68 ino->st.st_ino = MEDATA->inode_counter++;
69 ino->st.st_dev = MEDATA->rdev;
71 super->ino_usage++;
72 total_inodes++;
74 CALL (init_inode) (me, ino);
76 return ino;
79 struct vfs_s_entry *
80 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
82 struct vfs_s_entry *entry;
84 entry = g_new0 (struct vfs_s_entry, 1);
85 total_entries++;
87 if (name)
88 entry->name = g_strdup (name);
90 entry->ino = inode;
91 entry->ino->ent = entry;
92 CALL (init_entry) (me, entry);
94 return entry;
97 static void
98 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
100 if (!ino)
101 vfs_die ("Don't pass NULL to me");
103 /* ==0 can happen if freshly created entry is deleted */
104 if (ino->st.st_nlink <= 1){
105 while (ino->subdir){
106 vfs_s_free_entry (me, ino->subdir);
109 CALL (free_inode) (me, ino);
110 g_free (ino->linkname);
111 if (ino->localname){
112 unlink (ino->localname);
113 g_free(ino->localname);
115 total_inodes--;
116 ino->super->ino_usage--;
117 g_free(ino);
118 } else ino->st.st_nlink--;
121 void
122 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
124 if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
125 *ent->prevp = ent->next;
126 if (ent->next)
127 ent->next->prevp = ent->prevp;
130 g_free (ent->name);
131 ent->name = NULL;
133 if (ent->ino){
134 ent->ino->ent = NULL;
135 vfs_s_free_inode (me, ent->ino);
136 ent->ino = NULL;
139 total_entries--;
140 g_free(ent);
143 void
144 vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
146 struct vfs_s_entry **ep;
148 (void) me;
150 for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
152 ent->prevp = ep;
153 ent->next = NULL;
154 ent->dir = dir;
155 *ep = ent;
157 ent->ino->st.st_nlink++;
160 struct stat *
161 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
163 static struct stat st;
164 int myumask;
166 (void) me;
168 myumask = umask (022);
169 umask (myumask);
170 mode &= ~myumask;
172 st.st_mode = mode;
173 st.st_ino = 0;
174 st.st_dev = 0;
175 st.st_rdev = 0;
176 st.st_uid = getuid ();
177 st.st_gid = getgid ();
178 st.st_size = 0;
179 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
181 return &st;
184 struct vfs_s_entry *
185 vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent, mode_t mode)
187 struct vfs_s_inode *inode;
188 struct stat *st;
190 st = vfs_s_default_stat (me, mode);
191 inode = vfs_s_new_inode (me, parent->super, st);
193 return vfs_s_new_entry (me, name, inode);
196 /* We were asked to create entries automagically */
197 static struct vfs_s_entry *
198 vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
200 struct vfs_s_entry *res;
201 char *sep = strchr (path, PATH_SEP);
203 if (sep)
204 *sep = 0;
205 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
206 vfs_s_insert_entry (me, dir, res);
208 if (sep)
209 *sep = PATH_SEP;
211 return res;
214 /* If the entry is a symlink, find the entry for its target */
215 static struct vfs_s_entry *
216 vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry,
217 int follow)
219 char *linkname;
220 char *fullname = NULL;
221 struct vfs_s_entry *target;
223 if (follow == LINK_NO_FOLLOW)
224 return entry;
225 if (follow == 0)
226 ERRNOR (ELOOP, NULL);
227 if (!entry)
228 ERRNOR (ENOENT, NULL);
229 if (!S_ISLNK (entry->ino->st.st_mode))
230 return entry;
232 linkname = entry->ino->linkname;
233 if (linkname == NULL)
234 ERRNOR (EFAULT, NULL);
236 /* make full path from relative */
237 if (*linkname != PATH_SEP) {
238 char *fullpath = vfs_s_fullpath (me, entry->dir);
239 if (fullpath) {
240 fullname = g_strconcat (fullpath, "/", linkname, (char *) NULL);
241 linkname = fullname;
242 g_free (fullpath);
246 target =
247 (MEDATA->find_entry) (me, entry->dir->super->root, linkname,
248 follow - 1, 0);
249 g_free (fullname);
250 return target;
254 * Follow > 0: follow links, serves as loop protect,
255 * == -1: do not follow links
257 static struct vfs_s_entry *
258 vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
259 const char *a_path, int follow, int flags)
261 size_t pseg;
262 struct vfs_s_entry *ent = NULL;
263 char * const pathref = g_strdup (a_path);
264 char *path = pathref;
266 canonicalize_pathname (path);
268 while (root) {
269 while (*path == PATH_SEP) /* Strip leading '/' */
270 path++;
272 if (!path[0]) {
273 g_free (pathref);
274 return ent;
277 for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++);
279 for (ent = root->subdir; ent != NULL; ent = ent->next)
280 if (strlen (ent->name) == pseg
281 && (!strncmp (ent->name, path, pseg)))
282 /* FOUND! */
283 break;
285 if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
286 ent = vfs_s_automake (me, root, path, flags);
287 if (!ent) {
288 me->verrno = ENOENT;
289 goto cleanup;
291 path += pseg;
292 /* here we must follow leading directories always;
293 only the actual file is optional */
294 ent =
295 vfs_s_resolve_symlink (me, ent,
296 strchr (path,
297 PATH_SEP) ? LINK_FOLLOW :
298 follow);
299 if (!ent)
300 goto cleanup;
301 root = ent->ino;
303 cleanup:
304 g_free (pathref);
305 return NULL;
308 static void
309 split_dir_name (struct vfs_class *me, char *path, char **dir, char **name, char **save)
311 char *s;
313 (void) me;
315 s = strrchr (path, PATH_SEP);
316 if (s == NULL) {
317 *save = NULL;
318 *name = path;
319 *dir = path + strlen(path); /* an empty string */
320 } else {
321 *save = s;
322 *dir = path;
323 *s++ = '\0';
324 *name = s;
328 static struct vfs_s_entry *
329 vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
330 const char *a_path, int follow, int flags)
332 struct vfs_s_entry *ent = NULL;
333 char * const path = g_strdup (a_path);
334 struct vfs_s_entry *retval = NULL;
336 if (root->super->root != root)
337 vfs_die ("We have to use _real_ root. Always. Sorry.");
339 canonicalize_pathname (path);
341 if (!(flags & FL_DIR)) {
342 char *dirname, *name, *save;
343 struct vfs_s_inode *ino;
344 split_dir_name (me, path, &dirname, &name, &save);
345 ino =
346 vfs_s_find_inode (me, root->super, dirname, follow,
347 flags | FL_DIR);
348 if (save)
349 *save = PATH_SEP;
350 retval = vfs_s_find_entry_tree (me, ino, name, follow, flags);
351 g_free (path);
352 return retval;
355 for (ent = root->subdir; ent != NULL; ent = ent->next)
356 if (!strcmp (ent->name, path))
357 break;
359 if (ent && (!(MEDATA->dir_uptodate) (me, ent->ino))) {
360 #if 1
361 print_vfs_message (_("Directory cache expired for %s"), path);
362 #endif
363 vfs_s_free_entry (me, ent);
364 ent = NULL;
367 if (!ent) {
368 struct vfs_s_inode *ino;
370 ino =
371 vfs_s_new_inode (me, root->super,
372 vfs_s_default_stat (me, S_IFDIR | 0755));
373 ent = vfs_s_new_entry (me, path, ino);
374 if ((MEDATA->dir_load) (me, ino, path) == -1) {
375 vfs_s_free_entry (me, ent);
376 g_free (path);
377 return NULL;
379 vfs_s_insert_entry (me, root, ent);
381 for (ent = root->subdir; ent != NULL; ent = ent->next)
382 if (!strcmp (ent->name, path))
383 break;
385 if (!ent)
386 vfs_die ("find_linear: success but directory is not there\n");
388 #if 0
389 if (!vfs_s_resolve_symlink (me, ent, follow)) {
390 g_free (path);
391 return NULL;
393 #endif
394 g_free (path);
395 return ent;
398 struct vfs_s_inode *
399 vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
400 const char *path, int follow, int flags)
402 struct vfs_s_entry *ent;
404 if (((MEDATA->flags & VFS_S_REMOTE) == 0) && (*path == '\0'))
405 return super->root;
407 ent = (MEDATA->find_entry) (me, super->root, path, follow, flags);
408 return (ent != NULL) ? ent->ino : NULL;
411 /* Ook, these were functions around directory entries / inodes */
412 /* -------------------------------- superblock games -------------------------- */
414 static struct vfs_s_super *
415 vfs_s_new_super (struct vfs_class *me)
417 struct vfs_s_super *super;
419 super = g_new0 (struct vfs_s_super, 1);
420 super->me = me;
421 return super;
424 static void
425 vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
427 super->next = MEDATA->supers;
428 super->prevp = &MEDATA->supers;
430 if (MEDATA->supers != NULL)
431 MEDATA->supers->prevp = &super->next;
432 MEDATA->supers = super;
435 static void
436 vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
438 if (super->root){
439 vfs_s_free_inode (me, super->root);
440 super->root = NULL;
443 #if 0
444 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
445 if (super->ino_usage)
446 message (D_ERROR, " Direntry warning ",
447 "Super ino_usage is %d, memory leak",
448 super->ino_usage);
450 if (super->want_stale)
451 message (D_ERROR, " Direntry warning ", "Super has want_stale set");
452 #endif
454 if (super->prevp){
455 *super->prevp = super->next;
456 if (super->next)
457 super->next->prevp = super->prevp;
460 CALL (free_archive) (me, super);
461 g_free (super->name);
462 g_free(super);
467 * Dissect the path and create corresponding superblock. Note that inname
468 * can be changed and the result may point inside the original string.
470 const char *
471 vfs_s_get_path_mangle (struct vfs_class *me, char *inname,
472 struct vfs_s_super **archive, int flags)
474 const char *retval;
475 char *local, *op;
476 const char *archive_name;
477 int result = -1;
478 struct vfs_s_super *super;
479 void *cookie = NULL;
481 archive_name = inname;
482 vfs_split (inname, &local, &op);
483 retval = (local) ? local : "";
485 if (MEDATA->archive_check)
486 if (!(cookie = MEDATA->archive_check (me, archive_name, op)))
487 return NULL;
489 for (super = MEDATA->supers; super != NULL; super = super->next) {
490 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
491 int i = MEDATA->archive_same (me, super, archive_name, op, cookie);
492 if (i != 0) {
493 if (i == 1)
494 goto return_success;
495 else
496 break;
500 if (flags & FL_NO_OPEN)
501 ERRNOR (EIO, NULL);
503 super = vfs_s_new_super (me);
504 result = MEDATA->open_archive (me, super, archive_name, op);
505 if (result == -1) {
506 vfs_s_free_super (me, super);
507 ERRNOR (EIO, NULL);
509 if (!super->name)
510 vfs_die ("You have to fill name\n");
511 if (!super->root)
512 vfs_die ("You have to fill root inode\n");
514 vfs_s_insert_super (me, super);
515 vfs_stamp_create (me, super);
517 return_success:
518 *archive = super;
519 return retval;
524 * Dissect the path and create corresponding superblock.
525 * The result should be freed.
527 static char *
528 vfs_s_get_path (struct vfs_class *me, const char *inname,
529 struct vfs_s_super **archive, int flags)
531 char *buf, *retval;
533 buf = g_strdup (inname);
534 retval = g_strdup (vfs_s_get_path_mangle (me, buf, archive, flags));
535 g_free (buf);
536 return retval;
539 void
540 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
542 if (!super->want_stale){
543 vfs_s_free_inode (me, super->root);
544 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
548 char *
549 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
551 if (!ino->ent)
552 ERRNOR (EAGAIN, NULL);
554 if (!(MEDATA->flags & VFS_S_REMOTE)) {
555 /* archives */
556 char *newpath;
557 char *path = g_strdup (ino->ent->name);
558 while (1) {
559 ino = ino->ent->dir;
560 if (ino == ino->super->root)
561 break;
562 newpath = g_strconcat (ino->ent->name, "/", path, (char *) NULL);
563 g_free (path);
564 path = newpath;
566 return path;
569 /* remote systems */
570 if ((!ino->ent->dir) || (!ino->ent->dir->ent))
571 return g_strdup (ino->ent->name);
573 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR,
574 ino->ent->name, (char *) NULL);
577 /* Support of archives */
578 /* ------------------------ readdir & friends ----------------------------- */
580 static struct vfs_s_inode *
581 vfs_s_inode_from_path (struct vfs_class *me, const char *name, int flags)
583 struct vfs_s_super *super;
584 struct vfs_s_inode *ino;
585 char *q;
587 if (!(q = vfs_s_get_path (me, name, &super, 0)))
588 return NULL;
590 ino =
591 vfs_s_find_inode (me, super, q,
592 flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW,
593 flags & ~FL_FOLLOW);
594 if ((!ino) && (!*q))
595 /* We are asking about / directory of ftp server: assume it exists */
596 ino =
597 vfs_s_find_inode (me, super, q,
598 flags & FL_FOLLOW ? LINK_FOLLOW :
599 LINK_NO_FOLLOW,
600 FL_DIR | (flags & ~FL_FOLLOW));
601 g_free (q);
602 return ino;
605 struct dirhandle {
606 struct vfs_s_entry *cur;
607 struct vfs_s_inode *dir;
610 static void *
611 vfs_s_opendir (struct vfs_class *me, const char *dirname)
613 struct vfs_s_inode *dir;
614 struct dirhandle *info;
616 dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
617 if (!dir)
618 return NULL;
619 if (!S_ISDIR (dir->st.st_mode))
620 ERRNOR (ENOTDIR, NULL);
622 dir->st.st_nlink++;
623 #if 0
624 if (!dir->subdir) /* This can actually happen if we allow empty directories */
625 ERRNOR (EAGAIN, NULL);
626 #endif
627 info = g_new (struct dirhandle, 1);
628 info->cur = dir->subdir;
629 info->dir = dir;
631 return info;
634 static void *
635 vfs_s_readdir(void *data)
637 static union vfs_dirent dir;
638 struct dirhandle *info = (struct dirhandle *) data;
640 if (!(info->cur))
641 return NULL;
643 if (info->cur->name) {
644 g_strlcpy (dir.dent.d_name, info->cur->name, MC_MAXPATHLEN);
645 } else {
646 vfs_die("Null in structure-cannot happen");
649 compute_namelen(&dir.dent);
650 info->cur = info->cur->next;
652 return (void *) &dir;
655 static int
656 vfs_s_closedir (void *data)
658 struct dirhandle *info = (struct dirhandle *) data;
659 struct vfs_s_inode *dir = info->dir;
661 vfs_s_free_inode (dir->super->me, dir);
662 g_free (data);
663 return 0;
666 static int
667 vfs_s_chdir (struct vfs_class *me, const char *path)
669 void *data;
670 if (!(data = vfs_s_opendir (me, path)))
671 return -1;
672 vfs_s_closedir (data);
673 return 0;
676 /* --------------------------- stat and friends ---------------------------- */
678 static int
679 vfs_s_internal_stat (struct vfs_class *me, const char *path, struct stat *buf, int flag)
681 struct vfs_s_inode *ino;
683 if (!(ino = vfs_s_inode_from_path (me, path, flag)))
684 return -1;
685 *buf = ino->st;
686 return 0;
689 static int
690 vfs_s_stat (struct vfs_class *me, const char *path, struct stat *buf)
692 return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
695 static int
696 vfs_s_lstat (struct vfs_class *me, const char *path, struct stat *buf)
698 return vfs_s_internal_stat (me, path, buf, FL_NONE);
701 static int
702 vfs_s_fstat (void *fh, struct stat *buf)
704 *buf = FH->ino->st;
705 return 0;
708 static int
709 vfs_s_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
711 struct vfs_s_inode *ino;
712 size_t len;
714 ino = vfs_s_inode_from_path (me, path, 0);
715 if (!ino)
716 return -1;
718 if (!S_ISLNK (ino->st.st_mode))
719 ERRNOR (EINVAL, -1);
721 if (ino->linkname == NULL)
722 ERRNOR (EFAULT, -1);
724 len = strlen (ino->linkname);
725 if (size < len)
726 len = size;
727 /* readlink() does not append a NUL character to buf */
728 memcpy (buf, ino->linkname, len);
729 return len;
732 void *
733 vfs_s_open (struct vfs_class *me, const char *file, int flags, int mode)
735 int was_changed = 0;
736 struct vfs_s_fh *fh;
737 struct vfs_s_super *super;
738 char *q;
739 struct vfs_s_inode *ino;
741 if ((q = vfs_s_get_path (me, file, &super, 0)) == NULL)
742 return NULL;
743 ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
744 if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
745 g_free (q);
746 ERRNOR (EEXIST, NULL);
748 if (!ino) {
749 char *dirname, *name, *save;
750 struct vfs_s_entry *ent;
751 struct vfs_s_inode *dir;
752 int tmp_handle;
754 /* If the filesystem is read-only, disable file creation */
755 if (!(flags & O_CREAT) || !(me->write)) {
756 g_free (q);
757 return NULL;
760 split_dir_name (me, q, &dirname, &name, &save);
761 /* FIXME: check if vfs_s_find_inode returns NULL */
762 dir = vfs_s_find_inode (me, super, dirname, LINK_FOLLOW, FL_DIR);
763 if (save)
764 *save = PATH_SEP;
765 ent = vfs_s_generate_entry (me, name, dir, 0755);
766 ino = ent->ino;
767 vfs_s_insert_entry (me, dir, ent);
768 tmp_handle = vfs_mkstemps (&ino->localname, me->name, name);
769 if (tmp_handle == -1) {
770 g_free (q);
771 return NULL;
773 close (tmp_handle);
774 was_changed = 1;
777 g_free (q);
779 if (S_ISDIR (ino->st.st_mode))
780 ERRNOR (EISDIR, NULL);
782 fh = g_new (struct vfs_s_fh, 1);
783 fh->pos = 0;
784 fh->ino = ino;
785 fh->handle = -1;
786 fh->changed = was_changed;
787 fh->linear = 0;
789 if (IS_LINEAR (flags)) {
790 if (MEDATA->linear_start) {
791 print_vfs_message (_("Starting linear transfer..."));
792 fh->linear = LS_LINEAR_PREOPEN;
794 } else if ((MEDATA->fh_open)
795 && (MEDATA->fh_open (me, fh, flags, mode))) {
796 g_free (fh);
797 return NULL;
800 if (fh->ino->localname) {
801 fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
802 if (fh->handle == -1) {
803 g_free (fh);
804 ERRNOR (errno, NULL);
808 /* i.e. we had no open files and now we have one */
809 vfs_rmstamp (me, (vfsid) super);
810 super->fd_usage++;
811 fh->ino->st.st_nlink++;
812 return fh;
815 static ssize_t
816 vfs_s_read (void *fh, char *buffer, int count)
818 int n;
819 struct vfs_class *me = FH_SUPER->me;
821 if (FH->linear == LS_LINEAR_PREOPEN) {
822 if (!MEDATA->linear_start (me, FH, FH->pos))
823 return -1;
826 if (FH->linear == LS_LINEAR_CLOSED)
827 vfs_die ("linear_start() did not set linear_state!");
829 if (FH->linear == LS_LINEAR_OPEN)
830 return MEDATA->linear_read (me, FH, buffer, count);
832 if (FH->handle != -1){
833 n = read (FH->handle, buffer, count);
834 if (n < 0)
835 me->verrno = errno;
836 return n;
838 vfs_die ("vfs_s_read: This should not happen\n");
839 return -1;
842 static ssize_t
843 vfs_s_write (void *fh, const char *buffer, int count)
845 int n;
846 struct vfs_class *me = FH_SUPER->me;
848 if (FH->linear)
849 vfs_die ("no writing to linear files, please");
851 FH->changed = 1;
852 if (FH->handle != -1){
853 n = write (FH->handle, buffer, count);
854 if (n < 0)
855 me->verrno = errno;
856 return n;
858 vfs_die ("vfs_s_write: This should not happen\n");
859 return 0;
862 static off_t
863 vfs_s_lseek (void *fh, off_t offset, int whence)
865 off_t size = FH->ino->st.st_size;
867 if (FH->linear == LS_LINEAR_OPEN)
868 vfs_die ("cannot lseek() after linear_read!");
870 if (FH->handle != -1){ /* If we have local file opened, we want to work with it */
871 int retval = lseek (FH->handle, offset, whence);
872 if (retval == -1)
873 FH->ino->super->me->verrno = errno;
874 return retval;
877 switch (whence){
878 case SEEK_CUR:
879 offset += FH->pos; break;
880 case SEEK_END:
881 offset += size; break;
883 if (offset < 0)
884 FH->pos = 0;
885 else if (offset < size)
886 FH->pos = offset;
887 else
888 FH->pos = size;
889 return FH->pos;
892 static int
893 vfs_s_close (void *fh)
895 int res = 0;
896 struct vfs_class *me = FH_SUPER->me;
898 FH_SUPER->fd_usage--;
899 if (!FH_SUPER->fd_usage)
900 vfs_stamp_create (me, FH_SUPER);
902 if (FH->linear == LS_LINEAR_OPEN)
903 MEDATA->linear_close (me, fh);
904 if (MEDATA->fh_close)
905 res = MEDATA->fh_close (me, fh);
906 if (FH->changed && MEDATA->file_store){
907 char *s = vfs_s_fullpath (me, FH->ino);
908 if (!s)
909 res = -1;
910 else {
911 res = MEDATA->file_store (me, fh, s, FH->ino->localname);
912 g_free (s);
914 vfs_s_invalidate (me, FH_SUPER);
916 if (FH->handle != -1)
917 close (FH->handle);
919 vfs_s_free_inode (me, FH->ino);
920 g_free (fh);
921 return res;
924 static void
925 vfs_s_print_stats (const char *fs_name, const char *action,
926 const char *file_name, off_t have, off_t need)
928 static const char *i18n_percent_transf_format = NULL;
929 static const char *i18n_transf_format = NULL;
931 if (i18n_percent_transf_format == NULL) {
932 i18n_percent_transf_format =
933 _("%s: %s: %s %3d%% (%lu bytes transferred)");
934 i18n_transf_format = _("%s: %s: %s %lu bytes transferred");
937 if (need)
938 print_vfs_message (i18n_percent_transf_format, fs_name, action,
939 file_name, (int) ((double) have * 100 / need),
940 (unsigned long) have);
941 else
942 print_vfs_message (i18n_transf_format, fs_name, action, file_name,
943 (unsigned long) have);
947 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
949 /* If you want reget, you'll have to open file with O_LINEAR */
950 off_t total = 0;
951 char buffer[8192];
952 int handle, n;
953 off_t stat_size = ino->st.st_size;
954 struct vfs_s_fh fh;
956 memset (&fh, 0, sizeof (fh));
958 fh.ino = ino;
959 fh.handle = -1;
961 handle = vfs_mkstemps (&ino->localname, me->name, ino->ent->name);
962 if (handle == -1) {
963 me->verrno = errno;
964 goto error_4;
967 if (!MEDATA->linear_start (me, &fh, 0))
968 goto error_3;
970 /* Clear the interrupt status */
971 tty_got_interrupt ();
972 tty_enable_interrupt_key ();
974 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof (buffer)))) {
975 int t;
976 if (n < 0)
977 goto error_1;
979 total += n;
980 vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name,
981 total, stat_size);
983 if (tty_got_interrupt ())
984 goto error_1;
986 t = write (handle, buffer, n);
987 if (t != n) {
988 if (t == -1)
989 me->verrno = errno;
990 goto error_1;
993 MEDATA->linear_close (me, &fh);
994 close (handle);
996 tty_disable_interrupt_key ();
997 return 0;
999 error_1:
1000 MEDATA->linear_close (me, &fh);
1001 error_3:
1002 tty_disable_interrupt_key ();
1003 close (handle);
1004 unlink (ino->localname);
1005 error_4:
1006 g_free (ino->localname);
1007 ino->localname = NULL;
1008 return -1;
1011 /* ------------------------------- mc support ---------------------------- */
1013 static void
1014 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
1016 struct vfs_s_super *a = MEDATA->supers;
1017 char *name;
1019 while (a){
1020 name = g_strconcat ( a->name, "#", me->prefix, "/",
1021 /* a->current_dir->name, */ (char *) NULL);
1022 (*func)(name);
1023 g_free (name);
1024 a = a->next;
1028 static int
1029 vfs_s_ferrno (struct vfs_class *me)
1031 return me->verrno;
1035 * Get local copy of the given file. We reuse the existing file cache
1036 * for remote filesystems. Archives use standard VFS facilities.
1038 static char *
1039 vfs_s_getlocalcopy (struct vfs_class *me, const char *path)
1041 struct vfs_s_fh *fh;
1042 char *local;
1044 fh = vfs_s_open (me, path, O_RDONLY, 0);
1045 if (!fh || !fh->ino || !fh->ino->localname)
1046 return NULL;
1048 local = g_strdup (fh->ino->localname);
1049 vfs_s_close (fh);
1050 return local;
1054 * Return the local copy. Since we are using our cache, we do nothing -
1055 * the cache will be removed when the archive is closed.
1057 static int
1058 vfs_s_ungetlocalcopy (struct vfs_class *me, const char *path,
1059 const char *local, int has_changed)
1061 (void) me;
1062 (void) path;
1063 (void) local;
1064 (void) has_changed;
1065 return 0;
1068 static int
1069 vfs_s_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
1071 switch (ctlop) {
1072 case VFS_SETCTL_STALE_DATA:
1074 struct vfs_s_inode *ino = vfs_s_inode_from_path (me, path, 0);
1076 if (!ino)
1077 return 0;
1078 if (arg)
1079 ino->super->want_stale = 1;
1080 else {
1081 ino->super->want_stale = 0;
1082 vfs_s_invalidate (me, ino->super);
1084 return 1;
1086 case VFS_SETCTL_LOGFILE:
1087 MEDATA->logfile = fopen ((char *) arg, "w");
1088 return 1;
1089 case VFS_SETCTL_FLUSH:
1090 MEDATA->flush = 1;
1091 return 1;
1093 return 0;
1097 /* ----------------------------- Stamping support -------------------------- */
1099 static vfsid
1100 vfs_s_getid (struct vfs_class *me, const char *path)
1102 struct vfs_s_super *archive;
1103 char *p;
1105 if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
1106 return NULL;
1107 g_free(p);
1108 return (vfsid) archive;
1111 static int
1112 vfs_s_nothingisopen (vfsid id)
1114 (void) id;
1115 /* Our data structures should survive free of superblock at any time */
1116 return 1;
1119 static void
1120 vfs_s_free (vfsid id)
1122 vfs_s_free_super (((struct vfs_s_super *)id)->me, (struct vfs_s_super *)id);
1125 static int
1126 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
1128 struct timeval tim;
1130 if (MEDATA->flush) {
1131 MEDATA->flush = 0;
1132 return 0;
1135 gettimeofday(&tim, NULL);
1136 if (tim.tv_sec < ino->timestamp.tv_sec)
1137 return 1;
1138 return 0;
1141 /* Initialize one of our subclasses - fill common functions */
1142 void
1143 vfs_s_init_class (struct vfs_class *vclass, struct vfs_s_subclass *sub)
1145 vclass->data = sub;
1146 vclass->fill_names = vfs_s_fill_names;
1147 vclass->open = vfs_s_open;
1148 vclass->close = vfs_s_close;
1149 vclass->read = vfs_s_read;
1150 if (!(sub->flags & VFS_S_READONLY)) {
1151 vclass->write = vfs_s_write;
1153 vclass->opendir = vfs_s_opendir;
1154 vclass->readdir = vfs_s_readdir;
1155 vclass->closedir = vfs_s_closedir;
1156 vclass->stat = vfs_s_stat;
1157 vclass->lstat = vfs_s_lstat;
1158 vclass->fstat = vfs_s_fstat;
1159 vclass->readlink = vfs_s_readlink;
1160 vclass->chdir = vfs_s_chdir;
1161 vclass->ferrno = vfs_s_ferrno;
1162 vclass->lseek = vfs_s_lseek;
1163 vclass->getid = vfs_s_getid;
1164 vclass->nothingisopen = vfs_s_nothingisopen;
1165 vclass->free = vfs_s_free;
1166 if (sub->flags & VFS_S_REMOTE) {
1167 vclass->getlocalcopy = vfs_s_getlocalcopy;
1168 vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1169 sub->find_entry = vfs_s_find_entry_linear;
1170 } else {
1171 sub->find_entry = vfs_s_find_entry_tree;
1173 vclass->setctl = vfs_s_setctl;
1174 sub->dir_uptodate = vfs_s_dir_uptodate;
1177 /* ----------- Utility functions for networked filesystems -------------- */
1179 #ifdef USE_NETCODE
1181 vfs_s_select_on_two (int fd1, int fd2)
1183 fd_set set;
1184 struct timeval timeout;
1185 int v;
1186 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1188 timeout.tv_sec = 1;
1189 timeout.tv_usec = 0;
1190 FD_ZERO (&set);
1191 FD_SET (fd1, &set);
1192 FD_SET (fd2, &set);
1193 v = select (maxfd, &set, 0, 0, &timeout);
1194 if (v <= 0)
1195 return v;
1196 if (FD_ISSET (fd1, &set))
1197 return 1;
1198 if (FD_ISSET (fd2, &set))
1199 return 2;
1200 return -1;
1204 vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
1206 FILE *logfile = MEDATA->logfile;
1207 int i;
1208 char c;
1210 for (i = 0; i < buf_len - 1; i++, buf++){
1211 if (read (sock, buf, sizeof(char)) <= 0)
1212 return 0;
1213 if (logfile){
1214 fwrite (buf, 1, 1, logfile);
1215 fflush (logfile);
1217 if (*buf == term){
1218 *buf = 0;
1219 return 1;
1223 /* Line is too long - terminate buffer and discard the rest of line */
1224 *buf = 0;
1225 while (read (sock, &c, sizeof (c)) > 0) {
1226 if (logfile){
1227 fwrite (&c, 1, 1, logfile);
1228 fflush (logfile);
1230 if (c == '\n')
1231 return 1;
1233 return 0;
1237 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
1239 int n;
1240 int i;
1242 (void) me;
1244 tty_enable_interrupt_key ();
1245 for (i = 0; i < size-1; i++){
1246 n = read (fd, buffer+i, 1);
1247 tty_disable_interrupt_key ();
1248 if (n == -1 && errno == EINTR){
1249 buffer [i] = 0;
1250 return EINTR;
1252 if (n == 0){
1253 buffer [i] = 0;
1254 return 0;
1256 if (buffer [i] == '\n'){
1257 buffer [i] = 0;
1258 return 1;
1261 buffer [size-1] = 0;
1262 return 0;
1264 #endif /* USE_NETCODE */