replaced calls to g_strdup() by mhl_str_dup()
[midnight-commander.git] / vfs / direntry.c
blobd85c1d83370839513101a52ab4b183d360883dd4
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>
29 #include <errno.h>
31 #include <mhl/string.h>
33 #include "../src/global.h"
34 #include "../src/tty.h" /* enable/disable interrupt key */
35 #include "../src/wtools.h" /* message() */
36 #include "../src/main.h" /* print_vfs_message */
37 #include "utilvfs.h"
38 #include "vfs-impl.h"
39 #include "gc.h" /* vfs_rmstamp */
40 #include "xdirentry.h"
42 #define CALL(x) if (MEDATA->x) MEDATA->x
44 static volatile int total_inodes = 0, total_entries = 0;
46 struct vfs_s_inode *
47 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
49 struct vfs_s_inode *ino;
51 ino = g_new0 (struct vfs_s_inode, 1);
52 if (!ino)
53 return NULL;
55 if (initstat)
56 ino->st = *initstat;
57 ino->super = super;
58 ino->st.st_nlink = 0;
59 ino->st.st_ino = MEDATA->inode_counter++;
60 ino->st.st_dev = MEDATA->rdev;
62 super->ino_usage++;
63 total_inodes++;
65 CALL (init_inode) (me, ino);
67 return ino;
70 struct vfs_s_entry *
71 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
73 struct vfs_s_entry *entry;
75 entry = g_new0 (struct vfs_s_entry, 1);
76 total_entries++;
78 if (name)
79 entry->name = mhl_str_dup (name);
81 entry->ino = inode;
82 entry->ino->ent = entry;
83 CALL (init_entry) (me, entry);
85 return entry;
88 static void
89 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
91 if (!ino)
92 vfs_die ("Don't pass NULL to me");
94 /* ==0 can happen if freshly created entry is deleted */
95 if (ino->st.st_nlink <= 1){
96 while (ino->subdir){
97 vfs_s_free_entry (me, ino->subdir);
100 CALL (free_inode) (me, ino);
101 g_free (ino->linkname);
102 if (ino->localname){
103 unlink (ino->localname);
104 g_free(ino->localname);
106 total_inodes--;
107 ino->super->ino_usage--;
108 g_free(ino);
109 } else ino->st.st_nlink--;
112 void
113 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
115 if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
116 *ent->prevp = ent->next;
117 if (ent->next)
118 ent->next->prevp = ent->prevp;
121 g_free (ent->name);
122 ent->name = NULL;
124 if (ent->ino){
125 ent->ino->ent = NULL;
126 vfs_s_free_inode (me, ent->ino);
127 ent->ino = NULL;
130 total_entries--;
131 g_free(ent);
134 void
135 vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
137 struct vfs_s_entry **ep;
139 (void) me;
141 for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
143 ent->prevp = ep;
144 ent->next = NULL;
145 ent->dir = dir;
146 *ep = ent;
148 ent->ino->st.st_nlink++;
151 struct stat *
152 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
154 static struct stat st;
155 int myumask;
157 (void) me;
159 myumask = umask (022);
160 umask (myumask);
161 mode &= ~myumask;
163 st.st_mode = mode;
164 st.st_ino = 0;
165 st.st_dev = 0;
166 st.st_rdev = 0;
167 st.st_uid = getuid ();
168 st.st_gid = getgid ();
169 st.st_size = 0;
170 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
172 return &st;
175 struct vfs_s_entry *
176 vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent, mode_t mode)
178 struct vfs_s_inode *inode;
179 struct stat *st;
181 st = vfs_s_default_stat (me, mode);
182 inode = vfs_s_new_inode (me, parent->super, st);
184 return vfs_s_new_entry (me, name, inode);
187 /* We were asked to create entries automagically */
188 static struct vfs_s_entry *
189 vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
191 struct vfs_s_entry *res;
192 char *sep = strchr (path, PATH_SEP);
194 if (sep)
195 *sep = 0;
196 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
197 vfs_s_insert_entry (me, dir, res);
199 if (sep)
200 *sep = PATH_SEP;
202 return res;
205 /* If the entry is a symlink, find the entry for its target */
206 static struct vfs_s_entry *
207 vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry,
208 int follow)
210 char *linkname;
211 char *fullname = NULL;
212 struct vfs_s_entry *target;
214 if (follow == LINK_NO_FOLLOW)
215 return entry;
216 if (follow == 0)
217 ERRNOR (ELOOP, NULL);
218 if (!entry)
219 ERRNOR (ENOENT, NULL);
220 if (!S_ISLNK (entry->ino->st.st_mode))
221 return entry;
223 linkname = entry->ino->linkname;
224 if (linkname == NULL)
225 ERRNOR (EFAULT, NULL);
227 /* make full path from relative */
228 if (*linkname != PATH_SEP) {
229 char *fullpath = vfs_s_fullpath (me, entry->dir);
230 if (fullpath) {
231 fullname = g_strconcat (fullpath, "/", linkname, NULL);
232 linkname = fullname;
233 g_free (fullpath);
237 target =
238 (MEDATA->find_entry) (me, entry->dir->super->root, linkname,
239 follow - 1, 0);
240 g_free (fullname);
241 return target;
245 * Follow > 0: follow links, serves as loop protect,
246 * == -1: do not follow links
248 static struct vfs_s_entry *
249 vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
250 const char *a_path, int follow, int flags)
252 size_t pseg;
253 struct vfs_s_entry *ent = NULL;
254 char * const pathref = mhl_str_dup (a_path);
255 char *path = pathref;
257 canonicalize_pathname (path);
259 while (root) {
260 while (*path == PATH_SEP) /* Strip leading '/' */
261 path++;
263 if (!path[0]) {
264 g_free (pathref);
265 return ent;
268 for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++);
270 for (ent = root->subdir; ent != NULL; ent = ent->next)
271 if (strlen (ent->name) == pseg
272 && (!strncmp (ent->name, path, pseg)))
273 /* FOUND! */
274 break;
276 if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
277 ent = vfs_s_automake (me, root, path, flags);
278 if (!ent) {
279 me->verrno = ENOENT;
280 goto cleanup;
282 path += pseg;
283 /* here we must follow leading directories always;
284 only the actual file is optional */
285 ent =
286 vfs_s_resolve_symlink (me, ent,
287 strchr (path,
288 PATH_SEP) ? LINK_FOLLOW :
289 follow);
290 if (!ent)
291 goto cleanup;
292 root = ent->ino;
294 cleanup:
295 g_free (pathref);
296 return NULL;
299 static void
300 split_dir_name (struct vfs_class *me, char *path, char **dir, char **name, char **save)
302 char *s;
304 (void) me;
306 s = strrchr (path, PATH_SEP);
307 if (s == NULL) {
308 *save = NULL;
309 *name = path;
310 *dir = path + strlen(path); /* an empty string */
311 } else {
312 *save = s;
313 *dir = path;
314 *s++ = '\0';
315 *name = s;
319 static struct vfs_s_entry *
320 vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
321 const char *a_path, int follow, int flags)
323 struct vfs_s_entry *ent = NULL;
324 char * const path = mhl_str_dup (a_path);
325 struct vfs_s_entry *retval = NULL;
327 if (root->super->root != root)
328 vfs_die ("We have to use _real_ root. Always. Sorry.");
330 canonicalize_pathname (path);
332 if (!(flags & FL_DIR)) {
333 char *dirname, *name, *save;
334 struct vfs_s_inode *ino;
335 split_dir_name (me, path, &dirname, &name, &save);
336 ino =
337 vfs_s_find_inode (me, root->super, dirname, follow,
338 flags | FL_DIR);
339 if (save)
340 *save = PATH_SEP;
341 retval = vfs_s_find_entry_tree (me, ino, name, follow, flags);
342 g_free (path);
343 return retval;
346 for (ent = root->subdir; ent != NULL; ent = ent->next)
347 if (!strcmp (ent->name, path))
348 break;
350 if (ent && (!(MEDATA->dir_uptodate) (me, ent->ino))) {
351 #if 1
352 print_vfs_message (_("Directory cache expired for %s"), path);
353 #endif
354 vfs_s_free_entry (me, ent);
355 ent = NULL;
358 if (!ent) {
359 struct vfs_s_inode *ino;
361 ino =
362 vfs_s_new_inode (me, root->super,
363 vfs_s_default_stat (me, S_IFDIR | 0755));
364 ent = vfs_s_new_entry (me, path, ino);
365 if ((MEDATA->dir_load) (me, ino, path) == -1) {
366 vfs_s_free_entry (me, ent);
367 g_free (path);
368 return NULL;
370 vfs_s_insert_entry (me, root, ent);
372 for (ent = root->subdir; ent != NULL; ent = ent->next)
373 if (!strcmp (ent->name, path))
374 break;
376 if (!ent)
377 vfs_die ("find_linear: success but directory is not there\n");
379 #if 0
380 if (!vfs_s_resolve_symlink (me, ent, follow)) {
381 g_free (path);
382 return NULL;
384 #endif
385 g_free (path);
386 return ent;
389 struct vfs_s_inode *
390 vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
391 const char *path, int follow, int flags)
393 struct vfs_s_entry *ent;
394 if (!(MEDATA->flags & VFS_S_REMOTE) && (!*path))
395 return super->root;
396 ent = (MEDATA->find_entry) (me, super->root, path, follow, flags);
397 if (!ent)
398 return NULL;
399 return ent->ino;
402 /* Ook, these were functions around directory entries / inodes */
403 /* -------------------------------- superblock games -------------------------- */
405 static struct vfs_s_super *
406 vfs_s_new_super (struct vfs_class *me)
408 struct vfs_s_super *super;
410 super = g_new0 (struct vfs_s_super, 1);
411 super->me = me;
412 return super;
415 static void
416 vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
418 super->next = MEDATA->supers;
419 super->prevp = &MEDATA->supers;
421 if (MEDATA->supers != NULL)
422 MEDATA->supers->prevp = &super->next;
423 MEDATA->supers = super;
426 static void
427 vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
429 if (super->root){
430 vfs_s_free_inode (me, super->root);
431 super->root = NULL;
434 #if 0
435 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
436 if (super->ino_usage)
437 message (D_ERROR, " Direntry warning ",
438 "Super ino_usage is %d, memory leak",
439 super->ino_usage);
441 if (super->want_stale)
442 message (D_ERROR, " Direntry warning ", "Super has want_stale set");
443 #endif
445 if (super->prevp){
446 *super->prevp = super->next;
447 if (super->next)
448 super->next->prevp = super->prevp;
451 CALL (free_archive) (me, super);
452 g_free (super->name);
453 g_free(super);
458 * Dissect the path and create corresponding superblock. Note that inname
459 * can be changed and the result may point inside the original string.
461 const char *
462 vfs_s_get_path_mangle (struct vfs_class *me, char *inname,
463 struct vfs_s_super **archive, int flags)
465 const char *retval;
466 char *local, *op;
467 const char *archive_name;
468 int result = -1;
469 struct vfs_s_super *super;
470 void *cookie = NULL;
472 archive_name = inname;
473 vfs_split (inname, &local, &op);
474 retval = (local) ? local : "";
476 if (MEDATA->archive_check)
477 if (!(cookie = MEDATA->archive_check (me, archive_name, op)))
478 return NULL;
480 for (super = MEDATA->supers; super != NULL; super = super->next) {
481 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
482 int i;
483 if ((i =
484 MEDATA->archive_same (me, super, archive_name, op, cookie))) {
485 if (i == 1)
486 goto return_success;
487 else
488 break;
492 if (flags & FL_NO_OPEN)
493 ERRNOR (EIO, NULL);
495 super = vfs_s_new_super (me);
496 result = MEDATA->open_archive (me, super, archive_name, op);
497 if (result == -1) {
498 vfs_s_free_super (me, super);
499 ERRNOR (EIO, NULL);
501 if (!super->name)
502 vfs_die ("You have to fill name\n");
503 if (!super->root)
504 vfs_die ("You have to fill root inode\n");
506 vfs_s_insert_super (me, super);
507 vfs_stamp_create (me, super);
509 return_success:
510 *archive = super;
511 return retval;
516 * Dissect the path and create corresponding superblock.
517 * The result should be freed.
519 static char *
520 vfs_s_get_path (struct vfs_class *me, const char *inname,
521 struct vfs_s_super **archive, int flags)
523 char *buf, *retval;
525 buf = mhl_str_dup (inname);
526 retval = mhl_str_dup (vfs_s_get_path_mangle (me, buf, archive, flags));
527 g_free (buf);
528 return retval;
531 void
532 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
534 if (!super->want_stale){
535 vfs_s_free_inode (me, super->root);
536 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
540 char *
541 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
543 if (!ino->ent)
544 ERRNOR (EAGAIN, NULL);
546 if (!(MEDATA->flags & VFS_S_REMOTE)) {
547 /* archives */
548 char *newpath;
549 char *path = mhl_str_dup (ino->ent->name);
550 while (1) {
551 ino = ino->ent->dir;
552 if (ino == ino->super->root)
553 break;
554 newpath = g_strconcat (ino->ent->name, "/", path, (char *) NULL);
555 g_free (path);
556 path = newpath;
558 return path;
561 /* remote systems */
562 if ((!ino->ent->dir) || (!ino->ent->dir->ent))
563 return mhl_str_dup (ino->ent->name);
565 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR,
566 ino->ent->name, (char *) NULL);
569 /* Support of archives */
570 /* ------------------------ readdir & friends ----------------------------- */
572 static struct vfs_s_inode *
573 vfs_s_inode_from_path (struct vfs_class *me, const char *name, int flags)
575 struct vfs_s_super *super;
576 struct vfs_s_inode *ino;
577 char *q;
579 if (!(q = vfs_s_get_path (me, name, &super, 0)))
580 return NULL;
582 ino =
583 vfs_s_find_inode (me, super, q,
584 flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW,
585 flags & ~FL_FOLLOW);
586 if ((!ino) && (!*q))
587 /* We are asking about / directory of ftp server: assume it exists */
588 ino =
589 vfs_s_find_inode (me, super, q,
590 flags & FL_FOLLOW ? LINK_FOLLOW :
591 LINK_NO_FOLLOW,
592 FL_DIR | (flags & ~FL_FOLLOW));
593 g_free (q);
594 return ino;
597 struct dirhandle {
598 struct vfs_s_entry *cur;
599 struct vfs_s_inode *dir;
602 static void *
603 vfs_s_opendir (struct vfs_class *me, const char *dirname)
605 struct vfs_s_inode *dir;
606 struct dirhandle *info;
608 dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
609 if (!dir)
610 return NULL;
611 if (!S_ISDIR (dir->st.st_mode))
612 ERRNOR (ENOTDIR, NULL);
614 dir->st.st_nlink++;
615 #if 0
616 if (!dir->subdir) /* This can actually happen if we allow empty directories */
617 ERRNOR (EAGAIN, NULL);
618 #endif
619 info = g_new (struct dirhandle, 1);
620 info->cur = dir->subdir;
621 info->dir = dir;
623 return info;
626 static void *
627 vfs_s_readdir(void *data)
629 static union vfs_dirent dir;
630 struct dirhandle *info = (struct dirhandle *) data;
632 if (!(info->cur))
633 return NULL;
635 if (info->cur->name) {
636 g_strlcpy (dir.dent.d_name, info->cur->name, MC_MAXPATHLEN);
637 } else {
638 vfs_die("Null in structure-cannot happen");
641 compute_namelen(&dir.dent);
642 info->cur = info->cur->next;
644 return (void *) &dir;
647 static int
648 vfs_s_closedir (void *data)
650 struct dirhandle *info = (struct dirhandle *) data;
651 struct vfs_s_inode *dir = info->dir;
653 vfs_s_free_inode (dir->super->me, dir);
654 g_free (data);
655 return 0;
658 static int
659 vfs_s_chdir (struct vfs_class *me, const char *path)
661 void *data;
662 if (!(data = vfs_s_opendir (me, path)))
663 return -1;
664 vfs_s_closedir (data);
665 return 0;
668 /* --------------------------- stat and friends ---------------------------- */
670 static int
671 vfs_s_internal_stat (struct vfs_class *me, const char *path, struct stat *buf, int flag)
673 struct vfs_s_inode *ino;
675 if (!(ino = vfs_s_inode_from_path (me, path, flag)))
676 return -1;
677 *buf = ino->st;
678 return 0;
681 static int
682 vfs_s_stat (struct vfs_class *me, const char *path, struct stat *buf)
684 return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
687 static int
688 vfs_s_lstat (struct vfs_class *me, const char *path, struct stat *buf)
690 return vfs_s_internal_stat (me, path, buf, FL_NONE);
693 static int
694 vfs_s_fstat (void *fh, struct stat *buf)
696 *buf = FH->ino->st;
697 return 0;
700 static int
701 vfs_s_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
703 struct vfs_s_inode *ino;
704 size_t len;
706 ino = vfs_s_inode_from_path (me, path, 0);
707 if (!ino)
708 return -1;
710 if (!S_ISLNK (ino->st.st_mode))
711 ERRNOR (EINVAL, -1);
713 if (ino->linkname == NULL)
714 ERRNOR (EFAULT, -1);
716 len = strlen (ino->linkname);
717 if (size < len)
718 len = size;
719 /* readlink() does not append a NUL character to buf */
720 memcpy (buf, ino->linkname, len);
721 return len;
724 static void *
725 vfs_s_open (struct vfs_class *me, const char *file, int flags, int mode)
727 int was_changed = 0;
728 struct vfs_s_fh *fh;
729 struct vfs_s_super *super;
730 char *q;
731 struct vfs_s_inode *ino;
733 if ((q = vfs_s_get_path (me, file, &super, 0)) == NULL)
734 return NULL;
735 ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
736 if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
737 g_free (q);
738 ERRNOR (EEXIST, NULL);
740 if (!ino) {
741 char *dirname, *name, *save;
742 struct vfs_s_entry *ent;
743 struct vfs_s_inode *dir;
744 int tmp_handle;
746 /* If the filesystem is read-only, disable file creation */
747 if (!(flags & O_CREAT) || !(me->write)) {
748 g_free (q);
749 return NULL;
752 split_dir_name (me, q, &dirname, &name, &save);
753 /* FIXME: check if vfs_s_find_inode returns NULL */
754 dir = vfs_s_find_inode (me, super, dirname, LINK_FOLLOW, FL_DIR);
755 if (save)
756 *save = PATH_SEP;
757 ent = vfs_s_generate_entry (me, name, dir, 0755);
758 ino = ent->ino;
759 vfs_s_insert_entry (me, dir, ent);
760 tmp_handle = vfs_mkstemps (&ino->localname, me->name, name);
761 if (tmp_handle == -1) {
762 g_free (q);
763 return NULL;
765 close (tmp_handle);
766 was_changed = 1;
769 g_free (q);
771 if (S_ISDIR (ino->st.st_mode))
772 ERRNOR (EISDIR, NULL);
774 fh = g_new (struct vfs_s_fh, 1);
775 fh->pos = 0;
776 fh->ino = ino;
777 fh->handle = -1;
778 fh->changed = was_changed;
779 fh->linear = 0;
781 if (IS_LINEAR (flags)) {
782 if (MEDATA->linear_start) {
783 print_vfs_message (_("Starting linear transfer..."));
784 fh->linear = LS_LINEAR_PREOPEN;
786 } else if ((MEDATA->fh_open)
787 && (MEDATA->fh_open (me, fh, flags, mode))) {
788 g_free (fh);
789 return NULL;
792 if (fh->ino->localname) {
793 fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
794 if (fh->handle == -1) {
795 g_free (fh);
796 ERRNOR (errno, NULL);
800 /* i.e. we had no open files and now we have one */
801 vfs_rmstamp (me, (vfsid) super);
802 super->fd_usage++;
803 fh->ino->st.st_nlink++;
804 return fh;
807 static ssize_t
808 vfs_s_read (void *fh, char *buffer, int count)
810 int n;
811 struct vfs_class *me = FH_SUPER->me;
813 if (FH->linear == LS_LINEAR_PREOPEN) {
814 if (!MEDATA->linear_start (me, FH, FH->pos))
815 return -1;
818 if (FH->linear == LS_LINEAR_CLOSED)
819 vfs_die ("linear_start() did not set linear_state!");
821 if (FH->linear == LS_LINEAR_OPEN)
822 return MEDATA->linear_read (me, FH, buffer, count);
824 if (FH->handle != -1){
825 n = read (FH->handle, buffer, count);
826 if (n < 0)
827 me->verrno = errno;
828 return n;
830 vfs_die ("vfs_s_read: This should not happen\n");
831 return -1;
834 static int
835 vfs_s_write (void *fh, const char *buffer, int count)
837 int n;
838 struct vfs_class *me = FH_SUPER->me;
840 if (FH->linear)
841 vfs_die ("no writing to linear files, please");
843 FH->changed = 1;
844 if (FH->handle != -1){
845 n = write (FH->handle, buffer, count);
846 if (n < 0)
847 me->verrno = errno;
848 return n;
850 vfs_die ("vfs_s_write: This should not happen\n");
851 return 0;
854 static off_t
855 vfs_s_lseek (void *fh, off_t offset, int whence)
857 off_t size = FH->ino->st.st_size;
859 if (FH->linear == LS_LINEAR_OPEN)
860 vfs_die ("cannot lseek() after linear_read!");
862 if (FH->handle != -1){ /* If we have local file opened, we want to work with it */
863 int retval = lseek (FH->handle, offset, whence);
864 if (retval == -1)
865 FH->ino->super->me->verrno = errno;
866 return retval;
869 switch (whence){
870 case SEEK_CUR:
871 offset += FH->pos; break;
872 case SEEK_END:
873 offset += size; break;
875 if (offset < 0)
876 FH->pos = 0;
877 else if (offset < size)
878 FH->pos = offset;
879 else
880 FH->pos = size;
881 return FH->pos;
884 static int
885 vfs_s_close (void *fh)
887 int res = 0;
888 struct vfs_class *me = FH_SUPER->me;
890 FH_SUPER->fd_usage--;
891 if (!FH_SUPER->fd_usage)
892 vfs_stamp_create (me, FH_SUPER);
894 if (FH->linear == LS_LINEAR_OPEN)
895 MEDATA->linear_close (me, fh);
896 if (MEDATA->fh_close)
897 res = MEDATA->fh_close (me, fh);
898 if (FH->changed && MEDATA->file_store){
899 char *s = vfs_s_fullpath (me, FH->ino);
900 if (!s)
901 res = -1;
902 else {
903 res = MEDATA->file_store (me, fh, s, FH->ino->localname);
904 g_free (s);
906 vfs_s_invalidate (me, FH_SUPER);
908 if (FH->handle != -1)
909 close (FH->handle);
911 vfs_s_free_inode (me, FH->ino);
912 g_free (fh);
913 return res;
916 static void
917 vfs_s_print_stats (const char *fs_name, const char *action,
918 const char *file_name, off_t have, off_t need)
920 static const char *i18n_percent_transf_format = NULL;
921 static const char *i18n_transf_format = NULL;
923 if (i18n_percent_transf_format == NULL) {
924 i18n_percent_transf_format =
925 _("%s: %s: %s %3d%% (%lu bytes transferred)");
926 i18n_transf_format = _("%s: %s: %s %lu bytes transferred");
929 if (need)
930 print_vfs_message (i18n_percent_transf_format, fs_name, action,
931 file_name, (int) ((double) have * 100 / need),
932 (unsigned long) have);
933 else
934 print_vfs_message (i18n_transf_format, fs_name, action, file_name,
935 (unsigned long) have);
939 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
941 /* If you want reget, you'll have to open file with O_LINEAR */
942 off_t total = 0;
943 char buffer[8192];
944 int handle, n;
945 off_t stat_size = ino->st.st_size;
946 struct vfs_s_fh fh;
948 memset (&fh, 0, sizeof (fh));
950 fh.ino = ino;
951 fh.handle = -1;
953 handle = vfs_mkstemps (&ino->localname, me->name, ino->ent->name);
954 if (handle == -1) {
955 me->verrno = errno;
956 goto error_4;
959 if (!MEDATA->linear_start (me, &fh, 0))
960 goto error_3;
962 /* Clear the interrupt status */
963 got_interrupt ();
964 enable_interrupt_key ();
966 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof (buffer)))) {
967 int t;
968 if (n < 0)
969 goto error_1;
971 total += n;
972 vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name,
973 total, stat_size);
975 if (got_interrupt ())
976 goto error_1;
978 t = write (handle, buffer, n);
979 if (t != n) {
980 if (t == -1)
981 me->verrno = errno;
982 goto error_1;
985 MEDATA->linear_close (me, &fh);
986 close (handle);
988 disable_interrupt_key ();
989 return 0;
991 error_1:
992 MEDATA->linear_close (me, &fh);
993 error_3:
994 disable_interrupt_key ();
995 close (handle);
996 unlink (ino->localname);
997 error_4:
998 g_free (ino->localname);
999 ino->localname = NULL;
1000 return -1;
1003 /* ------------------------------- mc support ---------------------------- */
1005 static void
1006 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
1008 struct vfs_s_super *a = MEDATA->supers;
1009 char *name;
1011 while (a){
1012 name = g_strconcat ( a->name, "#", me->prefix, "/", /* a->current_dir->name, */ NULL);
1013 (*func)(name);
1014 g_free (name);
1015 a = a->next;
1019 static int
1020 vfs_s_ferrno (struct vfs_class *me)
1022 return me->verrno;
1026 * Get local copy of the given file. We reuse the existing file cache
1027 * for remote filesystems. Archives use standard VFS facilities.
1029 static char *
1030 vfs_s_getlocalcopy (struct vfs_class *me, const char *path)
1032 struct vfs_s_fh *fh;
1033 char *local;
1035 fh = vfs_s_open (me, path, O_RDONLY, 0);
1036 if (!fh || !fh->ino || !fh->ino->localname)
1037 return NULL;
1039 local = mhl_str_dup (fh->ino->localname);
1040 vfs_s_close (fh);
1041 return local;
1045 * Return the local copy. Since we are using our cache, we do nothing -
1046 * the cache will be removed when the archive is closed.
1048 static int
1049 vfs_s_ungetlocalcopy (struct vfs_class *me, const char *path,
1050 const char *local, int has_changed)
1052 (void) me;
1053 (void) path;
1054 (void) local;
1055 (void) has_changed;
1056 return 0;
1059 static int
1060 vfs_s_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
1062 switch (ctlop) {
1063 case VFS_SETCTL_STALE_DATA:
1065 struct vfs_s_inode *ino = vfs_s_inode_from_path (me, path, 0);
1067 if (!ino)
1068 return 0;
1069 if (arg)
1070 ino->super->want_stale = 1;
1071 else {
1072 ino->super->want_stale = 0;
1073 vfs_s_invalidate (me, ino->super);
1075 return 1;
1077 case VFS_SETCTL_LOGFILE:
1078 MEDATA->logfile = fopen ((char *) arg, "w");
1079 return 1;
1080 case VFS_SETCTL_FLUSH:
1081 MEDATA->flush = 1;
1082 return 1;
1084 return 0;
1088 /* ----------------------------- Stamping support -------------------------- */
1090 static vfsid
1091 vfs_s_getid (struct vfs_class *me, const char *path)
1093 struct vfs_s_super *archive;
1094 char *p;
1096 if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
1097 return NULL;
1098 g_free(p);
1099 return (vfsid) archive;
1102 static int
1103 vfs_s_nothingisopen (vfsid id)
1105 (void) id;
1106 /* Our data structures should survive free of superblock at any time */
1107 return 1;
1110 static void
1111 vfs_s_free (vfsid id)
1113 vfs_s_free_super (((struct vfs_s_super *)id)->me, (struct vfs_s_super *)id);
1116 static int
1117 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
1119 struct timeval tim;
1121 if (MEDATA->flush) {
1122 MEDATA->flush = 0;
1123 return 0;
1126 gettimeofday(&tim, NULL);
1127 if (tim.tv_sec < ino->timestamp.tv_sec)
1128 return 1;
1129 return 0;
1132 /* Initialize one of our subclasses - fill common functions */
1133 void
1134 vfs_s_init_class (struct vfs_class *vclass, struct vfs_s_subclass *sub)
1136 vclass->data = sub;
1137 vclass->fill_names = vfs_s_fill_names;
1138 vclass->open = vfs_s_open;
1139 vclass->close = vfs_s_close;
1140 vclass->read = vfs_s_read;
1141 if (!(sub->flags & VFS_S_READONLY)) {
1142 vclass->write = vfs_s_write;
1144 vclass->opendir = vfs_s_opendir;
1145 vclass->readdir = vfs_s_readdir;
1146 vclass->closedir = vfs_s_closedir;
1147 vclass->stat = vfs_s_stat;
1148 vclass->lstat = vfs_s_lstat;
1149 vclass->fstat = vfs_s_fstat;
1150 vclass->readlink = vfs_s_readlink;
1151 vclass->chdir = vfs_s_chdir;
1152 vclass->ferrno = vfs_s_ferrno;
1153 vclass->lseek = vfs_s_lseek;
1154 vclass->getid = vfs_s_getid;
1155 vclass->nothingisopen = vfs_s_nothingisopen;
1156 vclass->free = vfs_s_free;
1157 if (sub->flags & VFS_S_REMOTE) {
1158 vclass->getlocalcopy = vfs_s_getlocalcopy;
1159 vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1160 sub->find_entry = vfs_s_find_entry_linear;
1161 } else {
1162 sub->find_entry = vfs_s_find_entry_tree;
1164 vclass->setctl = vfs_s_setctl;
1165 sub->dir_uptodate = vfs_s_dir_uptodate;
1168 /* ----------- Utility functions for networked filesystems -------------- */
1170 #ifdef USE_NETCODE
1172 vfs_s_select_on_two (int fd1, int fd2)
1174 fd_set set;
1175 struct timeval timeout;
1176 int v;
1177 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1179 timeout.tv_sec = 1;
1180 timeout.tv_usec = 0;
1181 FD_ZERO (&set);
1182 FD_SET (fd1, &set);
1183 FD_SET (fd2, &set);
1184 v = select (maxfd, &set, 0, 0, &timeout);
1185 if (v <= 0)
1186 return v;
1187 if (FD_ISSET (fd1, &set))
1188 return 1;
1189 if (FD_ISSET (fd2, &set))
1190 return 2;
1191 return -1;
1195 vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
1197 FILE *logfile = MEDATA->logfile;
1198 int i;
1199 char c;
1201 for (i = 0; i < buf_len - 1; i++, buf++){
1202 if (read (sock, buf, sizeof(char)) <= 0)
1203 return 0;
1204 if (logfile){
1205 fwrite (buf, 1, 1, logfile);
1206 fflush (logfile);
1208 if (*buf == term){
1209 *buf = 0;
1210 return 1;
1214 /* Line is too long - terminate buffer and discard the rest of line */
1215 *buf = 0;
1216 while (read (sock, &c, sizeof (c)) > 0) {
1217 if (logfile){
1218 fwrite (&c, 1, 1, logfile);
1219 fflush (logfile);
1221 if (c == '\n')
1222 return 1;
1224 return 0;
1228 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
1230 int n;
1231 int i;
1233 (void) me;
1235 enable_interrupt_key ();
1236 for (i = 0; i < size-1; i++){
1237 n = read (fd, buffer+i, 1);
1238 disable_interrupt_key ();
1239 if (n == -1 && errno == EINTR){
1240 buffer [i] = 0;
1241 return EINTR;
1243 if (n == 0){
1244 buffer [i] = 0;
1245 return 0;
1247 if (buffer [i] == '\n'){
1248 buffer [i] = 0;
1249 return 1;
1252 buffer [size-1] = 0;
1253 return 0;
1255 #endif /* USE_NETCODE */