* global.h: Move fcntl.h inclusion here. Define O_BINARY.
[midnight-commander.git] / vfs / direntry.c
blobbaf17734b0b214b63dc74cd1df80c882fb51db8e
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 * $Id$
8 * Very loosely based on tar.c from midnight and archives.[ch] from
9 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
11 * Unfortunately, I was unable to keep all filesystems
12 * uniform. tar-like filesystems use tree structure where each
13 * directory has pointers to its subdirectories. We can do this
14 * because we have full information about our archive.
16 * At ftp-like filesystems, situation is a little bit different. When
17 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
18 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
19 * listed. That means that we do not have complete information, and if
20 * /usr is symlink to /4, we will not know. Also we have to time out
21 * entries and things would get messy with tree-like approach. So we
22 * do different trick: root directory is completely special and
23 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
24 * and we'll try to use custom find_entry function.
26 * Paths here do _not_ begin with '/', so root directory of
27 * archive/site is simply "". Beware. */
29 #include <config.h>
31 #include "utilvfs.h"
32 #include "xdirentry.h"
33 #include "../src/tty.h"
35 #define CALL(x) if (MEDATA->x) MEDATA->x
37 static volatile int total_inodes = 0, total_entries = 0;
39 vfs_s_inode *
40 vfs_s_new_inode (vfs *me, vfs_s_super *super, struct stat *initstat)
42 vfs_s_inode *ino;
44 ino = g_new0 (vfs_s_inode, 1);
45 if (!ino)
46 return NULL;
48 if (initstat)
49 ino->st = *initstat;
50 ino->super = super;
51 ino->st.st_nlink = 0;
52 ino->st.st_ino = MEDATA->inode_counter++;
53 ino->st.st_dev = MEDATA->rdev;
55 super->ino_usage++;
56 total_inodes++;
58 CALL (init_inode) (me, ino);
60 return ino;
63 vfs_s_entry *
64 vfs_s_new_entry (vfs *me, char *name, vfs_s_inode *inode)
66 vfs_s_entry *entry;
68 entry = g_new0 (struct vfs_s_entry, 1);
69 total_entries++;
71 if (name)
72 entry->name = g_strdup (name);
74 entry->ino = inode;
75 entry->ino->ent = entry;
76 CALL (init_entry) (me, entry);
78 return entry;
81 static void
82 vfs_s_free_inode (vfs *me, vfs_s_inode *ino)
84 if (!ino)
85 vfs_die ("Don't pass NULL to me");
87 /* ==0 can happen if freshly created entry is deleted */
88 if (ino->st.st_nlink <= 1){
89 while (ino->subdir){
90 vfs_s_free_entry (me, ino->subdir);
93 CALL (free_inode) (me, ino);
94 g_free (ino->linkname);
95 if (ino->localname){
96 unlink (ino->localname);
97 g_free(ino->localname);
99 total_inodes--;
100 ino->super->ino_usage--;
101 g_free(ino);
102 } else ino->st.st_nlink--;
105 void
106 vfs_s_free_entry (vfs *me, vfs_s_entry *ent)
108 int is_dot = 0;
109 if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
110 *ent->prevp = ent->next;
111 if (ent->next)
112 ent->next->prevp = ent->prevp;
115 if (ent->name){
116 is_dot = (!strcmp (ent->name, ".")) || (!strcmp (ent->name, ".."));
117 g_free (ent->name);
118 ent->name = NULL;
121 if (!is_dot && 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 (vfs *me, vfs_s_inode *dir, vfs_s_entry *ent)
134 vfs_s_entry **ep;
136 for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
138 ent->prevp = ep;
139 ent->next = NULL;
140 ent->dir = dir;
141 *ep = ent;
143 ent->ino->st.st_nlink++;
146 struct stat *
147 vfs_s_default_stat (vfs *me, mode_t mode)
149 static struct stat st;
150 int myumask;
152 myumask = umask (022);
153 umask (myumask);
154 mode &= ~myumask;
156 st.st_mode = mode;
157 st.st_ino = 0;
158 st.st_dev = 0;
159 st.st_rdev = 0;
160 st.st_uid = getuid ();
161 st.st_gid = getgid ();
162 st.st_size = 0;
163 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
165 return &st;
168 void
169 vfs_s_add_dots (vfs *me, vfs_s_inode *dir, vfs_s_inode *parent)
171 struct vfs_s_entry *dot, *dotdot;
173 if (!parent)
174 parent = dir;
175 dot = vfs_s_new_entry (me, ".", dir);
176 dotdot = vfs_s_new_entry (me, "..", parent);
177 vfs_s_insert_entry (me, dir, dot);
178 vfs_s_insert_entry (me, dir, dotdot);
179 dir->st.st_nlink--;
180 parent->st.st_nlink--; /* We do not count "." and ".." into nlinks */
183 struct vfs_s_entry *
184 vfs_s_generate_entry (vfs *me, char *name, struct vfs_s_inode *parent, mode_t mode)
186 struct vfs_s_inode *inode;
187 struct stat *st;
189 st = vfs_s_default_stat (me, mode);
190 inode = vfs_s_new_inode (me, parent->super, st);
191 if (S_ISDIR (mode))
192 vfs_s_add_dots (me, inode, parent);
194 return vfs_s_new_entry (me, name, inode);
197 /* We were asked to create entries automagically */
198 vfs_s_entry *
199 vfs_s_automake (vfs *me, vfs_s_inode *dir, char *path, int flags)
201 struct vfs_s_entry *res;
202 char *sep = strchr (path, PATH_SEP);
204 if (sep)
205 *sep = 0;
206 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
207 vfs_s_insert_entry (me, dir, res);
209 if (sep)
210 *sep = PATH_SEP;
212 return res;
216 * Follow > 0: follow links, serves as loop protect,
217 * == -1: do not follow links
219 vfs_s_entry *
220 vfs_s_find_entry_tree (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
222 unsigned int pseg;
223 vfs_s_entry *ent = NULL;
224 char p[MC_MAXPATHLEN] = "";
226 while (root){
227 int t;
229 while (*path == PATH_SEP) /* Strip leading '/' */
230 path++;
232 if (!path [0])
233 return ent;
235 for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++)
238 strcat (p, PATH_SEP_STR);
239 strncpy (p + (t = strlen (p)), path, pseg);
240 p[t + pseg] = '\0';
242 for (ent = root->subdir; ent != NULL; ent = ent->next)
243 if (strlen (ent->name) == pseg && (!strncmp (ent->name, path, pseg)))
244 /* FOUND! */
245 break;
247 if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
248 ent = vfs_s_automake (me, root, path, flags);
249 if (!ent) ERRNOR (ENOENT, NULL);
250 path += pseg;
251 /* here we must follow leading directories always; only the actual file is optional */
252 if (!(ent = vfs_s_resolve_symlink (me, ent, p, strchr (path, PATH_SEP) ? LINK_FOLLOW : follow)))
253 return NULL;
254 root = ent->ino;
257 return NULL;
260 static void
261 split_dir_name (vfs *me, char *path, char **dir, char **name, char **save)
263 char *s;
264 s = strrchr (path, PATH_SEP);
265 if (!s){
266 *save = NULL;
267 *name = path;
268 *dir = "";
269 } else {
270 *save = s;
271 *dir = path;
272 *s++ = 0;
273 *name = s;
277 vfs_s_entry *
278 vfs_s_find_entry_linear (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
280 vfs_s_entry* ent = NULL;
282 if (root->super->root != root)
283 vfs_die ("We have to use _real_ root. Always. Sorry." );
285 canonicalize_pathname (path);
287 if (!(flags & FL_DIR)){
288 char *dirname, *name, *save;
289 vfs_s_inode *ino;
290 split_dir_name (me, path, &dirname, &name, &save);
291 ino = vfs_s_find_inode (me, root, dirname, follow, flags | FL_DIR);
292 if (save)
293 *save = PATH_SEP;
294 return vfs_s_find_entry_tree (me, ino, name, follow, flags);
297 for (ent = root->subdir; ent != NULL; ent = ent->next)
298 if (!strcmp (ent->name, path))
299 break;
301 if (ent && (! (MEDATA->dir_uptodate) (me, ent->ino))){
302 #if 1
303 print_vfs_message (_("Dir cache expired for %s"), path);
304 #endif
305 vfs_s_free_entry (me, ent);
306 ent = NULL;
309 if (!ent){
310 vfs_s_inode *ino;
312 ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
313 ent = vfs_s_new_entry (me, path, ino);
314 if ((MEDATA->dir_load) (me, ino, path) == -1){
315 vfs_s_free_entry (me, ent);
316 return NULL;
318 vfs_s_insert_entry (me, root, ent);
320 for (ent = root->subdir; ent != NULL; ent = ent->next)
321 if (!strcmp (ent->name, path))
322 break;
324 if (!ent)
325 vfs_die ("find_linear: success but directory is not there\n");
327 #if 0
328 if (!vfs_s_resolve_symlink (me, ent, follow)) return NULL;
329 #endif
330 return ent;
333 vfs_s_inode *
334 vfs_s_find_inode (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
336 vfs_s_entry *ent;
337 if ((MEDATA->find_entry == vfs_s_find_entry_tree) && (!*path))
338 return root;
339 ent = (MEDATA->find_entry)(me, root, path, follow, flags);
340 if (!ent)
341 return NULL;
342 return ent->ino;
345 /* Ouch - vfs_s_resolve symlink does not work for filesystems like ftp & fish:
346 you may not lookup with some other root! */
347 vfs_s_entry *
348 vfs_s_resolve_symlink (vfs *me, vfs_s_entry *entry, char *path, int follow)
350 char buf[MC_MAXPATHLEN], *linkname;
352 if (follow == LINK_NO_FOLLOW)
353 return entry;
354 if (follow == 0)
355 ERRNOR (ELOOP, NULL);
356 if (!entry)
357 ERRNOR (ENOENT, NULL);
358 if (!S_ISLNK (entry->ino->st.st_mode))
359 return entry;
361 linkname = entry->ino->linkname;
363 if (linkname == NULL)
364 ERRNOR (EFAULT, NULL);
366 if (MEDATA->find_entry == vfs_s_find_entry_linear) {
367 if (*linkname == PATH_SEP)
368 return (MEDATA->find_entry) (me, entry->dir->super->root, linkname, follow - 1, 0);
369 else { /* FIXME: this does not work */
370 char *fullpath = vfs_s_fullpath(me, entry->dir);
371 snprintf(buf, sizeof (buf), "%s/%s", fullpath, linkname);
372 g_free (fullpath);
373 return (MEDATA->find_entry) (me, entry->dir->super->root, buf, follow - 1, 0);
377 /* Convert absolute paths to relative ones */
378 if (*linkname == PATH_SEP) {
379 char *p, *q;
380 for (p = path, q = entry->ino->linkname; *p == *q; p++, q++);
381 while (*(--q) != PATH_SEP);
382 q++;
383 for (;; p++){
384 p = strchr (p, PATH_SEP);
385 if (!p){
386 strcat (buf, q);
387 break;
389 strcat (buf, "..");
390 strcat (buf, PATH_SEP_STR);
392 linkname = buf;
395 return (MEDATA->find_entry) (me, entry->dir, linkname, follow - 1, 0);
398 /* Ook, these were functions around directory entries / inodes */
399 /* -------------------------------- superblock games -------------------------- */
401 vfs_s_super *
402 vfs_s_new_super (vfs *me)
404 vfs_s_super *super;
406 super = g_new0 (struct vfs_s_super, 1);
407 super->me = me;
408 return super;
411 static void
412 vfs_s_insert_super (vfs *me, vfs_s_super *super)
414 super->next = MEDATA->supers;
415 super->prevp = &MEDATA->supers;
417 if (MEDATA->supers != NULL)
418 MEDATA->supers->prevp = &super->next;
419 MEDATA->supers = super;
422 void
423 vfs_s_free_super (vfs *me, vfs_s_super *super)
425 if (super->root){
426 vfs_s_free_inode (me, super->root);
427 super->root = NULL;
430 #if 0
431 /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
432 if (super->ino_usage)
433 message_1s1d (1, " Direntry warning ",
434 "Super ino_usage is %d, memory leak",
435 super->ino_usage);
437 if (super->want_stale)
438 message_1s (1, " Direntry warning ", "Super has want_stale set");
439 #endif
441 if (super->prevp){
442 *super->prevp = super->next;
443 if (super->next)
444 super->next->prevp = super->prevp;
447 CALL (free_archive) (me, super);
448 g_free (super->name);
449 super->name = NULL;
450 g_free(super);
453 /* ------------------------------------------------------------------------= */
455 static void
456 vfs_s_stamp_me (vfs *me, struct vfs_s_super *psup, char *fs_name)
458 struct vfs_stamping *parent;
459 vfs *v;
461 v = vfs_type (fs_name);
462 if (v == &vfs_local_ops){
463 parent = NULL;
464 } else {
465 parent = g_new (struct vfs_stamping, 1);
466 parent->v = v;
467 parent->next = 0;
468 parent->id = (*v->getid) (v, fs_name, &(parent->parent));
470 vfs_add_noncurrent_stamps (me, (vfsid) psup, parent);
471 vfs_rm_parents (parent);
474 char *
475 vfs_s_get_path_mangle (vfs *me, char *inname, struct vfs_s_super **archive, int flags)
477 char *local, *op, *archive_name;
478 int result = -1;
479 struct vfs_s_super *super;
480 void *cookie = NULL;
482 archive_name = inname;
483 vfs_split (inname, &local, &op);
484 if (!local)
485 local = "";
487 if (MEDATA->archive_check)
488 if (! (cookie = MEDATA->archive_check (me, archive_name, op)))
489 return NULL;
491 for (super = MEDATA->supers; super != NULL; super = super->next){
492 int i; /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
493 if ((i = MEDATA->archive_same (me, super, archive_name, op, cookie))){
494 if (i==1) goto return_success;
495 else break;
499 if (flags & FL_NO_OPEN)
500 ERRNOR (EIO, NULL);
502 super = vfs_s_new_super (me);
503 result = MEDATA->open_archive (me, super, archive_name, op);
504 if (result == -1){
505 vfs_s_free_super (me, super);
506 ERRNOR (EIO, NULL);
508 if (!super->name)
509 vfs_die ("You have to fill name\n");
510 if (!super->root)
511 vfs_die ("You have to fill root inode\n");
513 vfs_s_insert_super (me, super);
514 vfs_s_stamp_me (me, super, archive_name);
516 return_success:
517 *archive = super;
518 return local;
521 char *
522 vfs_s_get_path (vfs *me, char *inname, struct vfs_s_super **archive, int flags)
524 char *buf = g_strdup( inname );
525 char *res = vfs_s_get_path_mangle (me, buf, archive, flags);
526 if (res)
527 res = g_strdup(res);
528 g_free(buf);
529 return res;
532 void
533 vfs_s_invalidate (vfs *me, vfs_s_super *super)
535 if (!super->want_stale){
536 vfs_s_free_inode (me, super->root);
537 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
541 char *
542 vfs_s_fullpath (vfs *me, vfs_s_inode *ino)
544 /* For now, usable only on filesystems with _linear structure */
545 if (MEDATA->find_entry != vfs_s_find_entry_linear)
546 vfs_die ("Implement me!");
547 if (!ino->ent) /* That must be directory... */
548 ERRNOR (EAGAIN, NULL);
550 if ((!ino->ent->dir) || (!ino->ent->dir->ent)) /* It must be directory */
551 return g_strdup (ino->ent->name);
553 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR,
554 ino->ent->name, NULL);
557 /* Support of archives */
558 /* ------------------------ readdir & friends ----------------------------- */
560 vfs_s_super *vfs_s_super_from_path (vfs *me, char *name)
562 struct vfs_s_super *super;
564 if (!vfs_s_get_path_mangle (me, name, &super, 0))
565 return NULL;
566 return super;
569 vfs_s_inode *
570 vfs_s_inode_from_path (vfs *me, 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_mangle (me, name, &super, 0)))
577 return NULL;
579 ino = vfs_s_find_inode (me, super->root, q, flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW, flags & ~FL_FOLLOW);
580 if ((!ino) && (!*q))
581 /* We are asking about / directory of ftp server: assume it exists */
582 ino = vfs_s_find_inode (me, super->root, q, flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW, FL_DIR | (flags & ~FL_FOLLOW));
583 return ino;
586 struct dirhandle {
587 vfs_s_entry *cur;
588 vfs_s_inode *dir;
591 void *
592 vfs_s_opendir (vfs *me, char *dirname)
594 struct vfs_s_inode *dir;
595 struct dirhandle *info;
597 dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
598 if (!dir)
599 return NULL;
600 if (!S_ISDIR (dir->st.st_mode))
601 ERRNOR (ENOTDIR, NULL);
603 dir->st.st_nlink++;
604 #if 0
605 if (!dir->subdir) /* This can actually happen if we allow empty directories */
606 ERRNOR (EAGAIN, NULL);
607 #endif
608 info = g_new (struct dirhandle, 1);
609 info->cur = dir->subdir;
610 info->dir = dir;
612 return info;
615 void *
616 vfs_s_readdir(void *data)
618 static union vfs_dirent dir;
619 struct dirhandle *info = (struct dirhandle *) data;
621 if (!(info->cur))
622 return NULL;
624 if (info->cur->name) {
625 strncpy(dir.dent.d_name, info->cur->name, MC_MAXPATHLEN);
626 dir.dent.d_name[MC_MAXPATHLEN] = 0;
627 } else {
628 vfs_die("Null in structure-can not happen");
631 compute_namelen(&dir.dent);
632 info->cur = info->cur->next;
634 return (void *) &dir;
638 vfs_s_telldir (void *data)
640 struct dirhandle *info = (struct dirhandle *) data;
641 struct vfs_s_entry *cur;
642 int num = 0;
644 cur = info->dir->subdir;
645 while (cur!=NULL){
646 if (cur == info->cur)
647 return num;
648 num++;
649 cur = cur->next;
651 return -1;
654 void
655 vfs_s_seekdir (void *data, int offset)
657 struct dirhandle *info = (struct dirhandle *) data;
658 int i;
659 info->cur = info->dir->subdir;
660 for (i=0; i<offset; i++)
661 vfs_s_readdir (data);
665 vfs_s_closedir (void *data)
667 struct dirhandle *info = (struct dirhandle *) data;
668 struct vfs_s_inode *dir = info->dir;
670 vfs_s_free_inode (dir->super->me, dir);
671 g_free (data);
672 return 0;
676 vfs_s_chdir (vfs *me, char *path)
678 void *data;
679 if (!(data = vfs_s_opendir (me, path)))
680 return -1;
681 vfs_s_closedir (data);
682 return 0;
685 /* --------------------------- stat and friends ---------------------------- */
687 static int
688 vfs_s_internal_stat (vfs *me, char *path, struct stat *buf, int flag)
690 struct vfs_s_inode *ino;
692 if (!(ino = vfs_s_inode_from_path (me, path, flag)))
693 return -1;
694 *buf = ino->st;
695 return 0;
699 vfs_s_stat (vfs *me, char *path, struct stat *buf)
701 return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
705 vfs_s_lstat (vfs *me, char *path, struct stat *buf)
707 return vfs_s_internal_stat (me, path, buf, FL_NONE);
711 vfs_s_fstat (void *fh, struct stat *buf)
713 *buf = FH->ino->st;
714 return 0;
718 vfs_s_readlink (vfs *me, char *path, char *buf, int size)
720 struct vfs_s_inode *ino;
722 ino = vfs_s_inode_from_path (me, path, 0);
723 if (!ino)
724 return -1;
726 if (!S_ISLNK (ino->st.st_mode))
727 ERRNOR (EINVAL, -1);
729 if (ino->linkname == NULL)
730 ERRNOR (EFAULT, -1);
732 strncpy (buf, ino->linkname, size);
733 *(buf+size-1) = 0;
734 return strlen (buf);
737 void *
738 vfs_s_open (vfs *me, char *file, int flags, int mode)
740 int was_changed = 0;
741 struct vfs_s_fh *fh;
742 vfs_s_super *super;
743 char *q;
744 struct vfs_s_inode *ino;
746 if ((q = vfs_s_get_path_mangle (me, file, &super, 0)) == NULL)
747 return NULL;
748 ino = vfs_s_find_inode (me, super->root, q, LINK_FOLLOW, FL_NONE);
749 if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)))
750 ERRNOR (EEXIST, NULL);
751 if (!ino){
752 char *dirname, *name, *save;
753 vfs_s_entry *ent;
754 vfs_s_inode *dir;
755 int tmp_handle;
756 if (!(flags & O_CREAT))
757 return NULL;
759 split_dir_name (me, q, &dirname, &name, &save);
760 /* FIXME: if vfs_s_find_inode returns NULL, this will do rather bad
761 things. */
762 dir = vfs_s_find_inode (me, super->root, 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 = mc_mkstemps (&ino->localname, me->name, NULL);
769 if (tmp_handle == -1)
770 return NULL;
771 close (tmp_handle);
772 was_changed = 1;
775 if (S_ISDIR (ino->st.st_mode))
776 ERRNOR (EISDIR, NULL);
778 fh = g_new (struct vfs_s_fh, 1);
779 fh->pos = 0;
780 fh->ino = ino;
781 fh->handle = -1;
782 fh->changed = was_changed;
783 fh->linear = 0;
785 if (IS_LINEAR(flags)) {
786 if (MEDATA->linear_start) {
787 print_vfs_message (_("Starting linear transfer..."));
788 if (!MEDATA->linear_start (me, fh, 0)){
789 g_free(fh);
790 return NULL;
793 } else if ((MEDATA->fh_open) && (MEDATA->fh_open (me, fh, flags, mode))){
794 g_free(fh);
795 return NULL;
798 if (fh->ino->localname){
799 fh->handle = open (fh->ino->localname, NO_LINEAR(flags), mode);
800 if (fh->handle == -1){
801 g_free(fh);
802 ERRNOR (errno, NULL);
806 /* i.e. we had no open files and now we have one */
807 vfs_rmstamp (me, (vfsid) super, 1);
808 super->fd_usage++;
809 fh->ino->st.st_nlink++;
810 return fh;
814 vfs_s_read (void *fh, char *buffer, int count)
816 int n;
817 vfs *me = FH_SUPER->me;
819 if (FH->linear == LS_LINEAR_CLOSED)
820 vfs_die ("linear_start() did not set linear_state!");
822 if (FH->linear == LS_LINEAR_OPEN)
823 return MEDATA->linear_read (me, FH, buffer, count);
825 if (FH->handle != -1){
826 n = read (FH->handle, buffer, count);
827 if (n < 0)
828 me->verrno = errno;
829 return n;
831 vfs_die ("vfs_s_read: This should not happen\n");
832 return -1;
836 vfs_s_write (void *fh, char *buffer, int count)
838 int n;
839 vfs *me = FH_SUPER->me;
841 if (FH->linear)
842 vfs_die ("no writing to linear files, please");
844 FH->changed = 1;
845 if (FH->handle != -1){
846 n = write (FH->handle, buffer, count);
847 if (n < 0)
848 me->verrno = errno;
849 return n;
851 vfs_die ("vfs_s_write: This should not happen\n");
852 return 0;
856 vfs_s_lseek (void *fh, off_t offset, int whence)
858 off_t size = FH->ino->st.st_size;
860 if (FH->handle != -1){ /* If we have local file opened, we want to work with it */
861 int retval = lseek (FH->handle, offset, whence);
862 if (retval == -1)
863 FH->ino->super->me->verrno = errno;
864 return retval;
867 switch (whence){
868 case SEEK_CUR:
869 offset += FH->pos; break;
870 case SEEK_END:
871 offset += size; break;
873 if (offset < 0)
874 FH->pos = 0;
875 else if (offset < size)
876 FH->pos = offset;
877 else
878 FH->pos = size;
879 return FH->pos;
883 vfs_s_close (void *fh)
885 int res = 0;
886 vfs *me = FH_SUPER->me;
888 FH_SUPER->fd_usage--;
889 if (!FH_SUPER->fd_usage){
890 struct vfs_stamping *parent;
891 vfs *v;
893 v = vfs_type (FH_SUPER->name);
894 if (v == &vfs_local_ops){
895 parent = NULL;
896 } else {
897 parent = g_new (struct vfs_stamping, 1);
898 parent->v = v;
899 parent->next = 0;
900 parent->id = (*v->getid) (v, FH_SUPER->name, &(parent->parent));
902 vfs_add_noncurrent_stamps (me, (vfsid) (FH_SUPER), parent);
903 vfs_rm_parents (parent);
905 if (FH->linear == LS_LINEAR_OPEN)
906 MEDATA->linear_close (me, fh);
907 if (MEDATA->fh_close)
908 res = MEDATA->fh_close (me, fh);
909 if (FH->changed && MEDATA->file_store){
910 char *s = vfs_s_fullpath (me, FH->ino);
911 if (!s)
912 res = -1;
913 else {
914 res = MEDATA->file_store (me, fh, s, FH->ino->localname);
915 g_free (s);
917 vfs_s_invalidate (me, FH_SUPER);
919 if (FH->handle != -1)
920 close (FH->handle);
922 vfs_s_free_inode (me, FH->ino);
923 g_free (fh);
924 return res;
927 int
928 vfs_s_retrieve_file(vfs *me, struct vfs_s_inode *ino)
930 /* If you want reget, you'll have to open file with O_LINEAR */
931 off_t total = 0;
932 char buffer[8192];
933 int handle, n;
934 off_t stat_size = ino->st.st_size;
935 struct vfs_s_fh fh;
937 memset(&fh, 0, sizeof(fh));
939 fh.ino = ino;
940 fh.handle = -1;
942 handle = mc_mkstemps (&ino->localname, me->name, NULL);
943 if (handle == -1) {
944 me->verrno = errno;
945 goto error_4;
948 if (!MEDATA->linear_start (me, &fh, 0))
949 goto error_3;
951 /* Clear the interrupt status */
953 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof(buffer)))) {
955 if (n < 0)
956 goto error_1;
958 total += n;
959 vfs_print_stats (me->name, _("Getting file"), ino->ent->name, total, stat_size);
961 if (write(handle, buffer, n) < 0) {
962 me->verrno = errno;
963 goto error_1;
966 MEDATA->linear_close (me, &fh);
967 close(handle);
969 return 0;
970 error_1:
971 MEDATA->linear_close (me, &fh);
972 error_3:
973 disable_interrupt_key();
974 close(handle);
975 unlink(ino->localname);
976 error_4:
977 g_free(ino->localname);
978 ino->localname = NULL;
979 return -1;
982 /* ------------------------------- mc support ---------------------------- */
984 void
985 vfs_s_fill_names (vfs *me, void (*func)(char *))
987 struct vfs_s_super *a = MEDATA->supers;
988 char *name;
990 while (a){
991 name = g_strconcat ( a->name, "#", me->prefix, "/", /* a->current_dir->name, */ NULL);
992 (*func)(name);
993 g_free (name);
994 a = a->next;
999 vfs_s_ferrno (vfs *me)
1001 return me->verrno;
1004 void
1005 vfs_s_dump (vfs *me, char *prefix, vfs_s_inode *ino)
1007 printf ("%s %s %d ", prefix, S_ISDIR (ino->st.st_mode) ? "DIR" : "FILE", ino->st.st_mode);
1008 if (!ino->subdir)
1009 printf ("FILE\n");
1010 else
1012 struct vfs_s_entry *ent;
1013 for (ent = ino->subdir; ent ; ent = ent->next){
1014 char *s = g_strconcat (prefix, "/", ent->name, NULL);
1015 if (ent->name[0] == '.')
1016 printf ("%s IGNORED\n", s);
1017 else
1018 vfs_s_dump (me, s, ent->ino);
1019 g_free(s);
1024 char *
1025 vfs_s_getlocalcopy (vfs *me, char *path)
1027 struct vfs_s_inode *ino;
1028 char buf[MC_MAXPATHLEN];
1030 strncpy (buf, path, MC_MAXPATHLEN);
1031 ino = vfs_s_inode_from_path (me, path, FL_FOLLOW | FL_NONE);
1033 if (!ino->localname)
1034 ino->localname = mc_def_getlocalcopy (me, buf);
1035 /* FIXME: fd_usage++ missing */
1036 return g_strdup (ino->localname);
1039 int
1040 vfs_s_setctl (vfs *me, char *path, int ctlop, char *arg)
1042 vfs_s_inode *ino = vfs_s_inode_from_path (me, path, 0);
1043 if (!ino)
1044 return 0;
1045 switch (ctlop){
1046 case MCCTL_WANT_STALE_DATA:
1047 ino->super->want_stale = 1;
1048 return 1;
1049 case MCCTL_NO_STALE_DATA:
1050 ino->super->want_stale = 0;
1051 vfs_s_invalidate(me, ino->super);
1052 return 1;
1053 #if 0 /* FIXME: We should implement these */
1054 case MCCTL_REMOVELOCALCOPY:
1055 return remove_temp_file (path);
1056 case MCCTL_FORGET_ABOUT:
1057 my_forget(path);
1058 return 0;
1059 #endif
1061 return 0;
1065 /* ----------------------------- Stamping support -------------------------- */
1067 vfsid
1068 vfs_s_getid (vfs *me, char *path, struct vfs_stamping **parent)
1070 vfs_s_super *archive;
1071 vfs *v;
1072 char *p;
1073 vfsid id;
1074 struct vfs_stamping *par;
1076 *parent = NULL;
1077 if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
1078 return (vfsid) -1;
1079 g_free(p);
1080 v = vfs_type (archive->name);
1081 id = (*v->getid) (v, archive->name, &par);
1082 if (id != (vfsid)-1){
1083 *parent = g_new (struct vfs_stamping, 1);
1084 (*parent)->v = v;
1085 (*parent)->id = id;
1086 (*parent)->parent = par;
1087 (*parent)->next = NULL;
1089 return (vfsid) archive;
1093 vfs_s_nothingisopen (vfsid id)
1095 /* Our data structures should survive free of superblock at any time */
1096 return 1;
1099 void
1100 vfs_s_free (vfsid id)
1102 vfs_s_free_super (((vfs_s_super *)id)->me, (vfs_s_super *)id);
1105 /* ----------- Utility functions for networked filesystems -------------- */
1107 #ifdef USE_NETCODE
1109 vfs_s_select_on_two (int fd1, int fd2)
1111 fd_set set;
1112 struct timeval timeout;
1113 int v;
1114 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1116 timeout.tv_sec = 1;
1117 timeout.tv_usec = 0;
1118 FD_ZERO (&set);
1119 FD_SET (fd1, &set);
1120 FD_SET (fd2, &set);
1121 v = select (maxfd, &set, 0, 0, &timeout);
1122 if (v <= 0)
1123 return v;
1124 if (FD_ISSET (fd1, &set))
1125 return 1;
1126 if (FD_ISSET (fd2, &set))
1127 return 2;
1128 return -1;
1132 vfs_s_get_line (vfs *me, int sock, char *buf, int buf_len, char term)
1134 FILE *logfile = MEDATA->logfile;
1135 int i, status;
1136 char c;
1138 for (i = 0; i < buf_len - 1; i++, buf++){
1139 if (read (sock, buf, sizeof(char)) <= 0)
1140 return 0;
1141 if (logfile){
1142 fwrite (buf, 1, 1, logfile);
1143 fflush (logfile);
1145 if (*buf == term){
1146 *buf = 0;
1147 return 1;
1151 /* Line is too long - terminate buffer and discard the rest of line */
1152 *buf = 0;
1153 while ((status = read (sock, &c, sizeof (c))) > 0){
1154 if (logfile){
1155 fwrite (&c, 1, 1, logfile);
1156 fflush (logfile);
1158 if (c == '\n')
1159 return 1;
1161 return 0;
1165 vfs_s_get_line_interruptible (vfs *me, char *buffer, int size, int fd)
1167 int n;
1168 int i;
1170 enable_interrupt_key ();
1171 for (i = 0; i < size-1; i++){
1172 n = read (fd, buffer+i, 1);
1173 disable_interrupt_key ();
1174 if (n == -1 && errno == EINTR){
1175 buffer [i] = 0;
1176 return EINTR;
1178 if (n == 0){
1179 buffer [i] = 0;
1180 return 0;
1182 if (buffer [i] == '\n'){
1183 buffer [i] = 0;
1184 return 1;
1187 buffer [size-1] = 0;
1188 return 0;
1190 #endif /* USE_NETCODE */