mc.sh & mc.csh creation fixed...
[midnight-commander.git] / vfs / direntry.c
blobac7b3b62f619abe5c59562c750133e71b3fcaaf9
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 "utilvfs.h"
30 #include "xdirentry.h"
31 #include "../src/tty.h"
33 #define CALL(x) if (MEDATA->x) MEDATA->x
35 static volatile int total_inodes = 0, total_entries = 0;
37 vfs_s_inode *
38 vfs_s_new_inode (vfs *me, vfs_s_super *super, struct stat *initstat)
40 vfs_s_inode *ino;
42 ino = g_new0 (vfs_s_inode, 1);
43 if (!ino)
44 return NULL;
46 if (initstat)
47 ino->st = *initstat;
48 ino->super = super;
49 ino->st.st_nlink = 0;
50 ino->st.st_ino = MEDATA->inode_counter++;
51 ino->st.st_dev = MEDATA->rdev;
53 super->ino_usage++;
54 total_inodes++;
56 CALL (init_inode) (me, ino);
58 return ino;
61 vfs_s_entry *
62 vfs_s_new_entry (vfs *me, char *name, vfs_s_inode *inode)
64 vfs_s_entry *entry;
66 entry = g_new0 (struct vfs_s_entry, 1);
67 total_entries++;
69 if (name)
70 entry->name = g_strdup (name);
72 entry->ino = inode;
73 entry->ino->ent = entry;
74 CALL (init_entry) (me, entry);
76 return entry;
79 static void
80 vfs_s_free_inode (vfs *me, vfs_s_inode *ino)
82 if (!ino)
83 vfs_die ("Don't pass NULL to me");
85 /* ==0 can happen if freshly created entry is deleted */
86 if (ino->st.st_nlink <= 1){
87 while (ino->subdir){
88 vfs_s_free_entry (me, ino->subdir);
91 CALL (free_inode) (me, ino);
92 g_free (ino->linkname);
93 if (ino->localname){
94 unlink (ino->localname);
95 g_free(ino->localname);
97 total_inodes--;
98 ino->super->ino_usage--;
99 g_free(ino);
100 } else ino->st.st_nlink--;
103 void
104 vfs_s_free_entry (vfs *me, vfs_s_entry *ent)
106 int is_dot = 0;
107 if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
108 *ent->prevp = ent->next;
109 if (ent->next)
110 ent->next->prevp = ent->prevp;
113 if (ent->name){
114 is_dot = (!strcmp (ent->name, ".")) || (!strcmp (ent->name, ".."));
115 g_free (ent->name);
116 ent->name = NULL;
119 if (!is_dot && ent->ino){
120 ent->ino->ent = NULL;
121 vfs_s_free_inode (me, ent->ino);
122 ent->ino = NULL;
125 total_entries--;
126 g_free(ent);
129 void
130 vfs_s_insert_entry (vfs *me, vfs_s_inode *dir, vfs_s_entry *ent)
132 vfs_s_entry **ep;
134 for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
136 ent->prevp = ep;
137 ent->next = NULL;
138 ent->dir = dir;
139 *ep = ent;
141 ent->ino->st.st_nlink++;
144 struct stat *
145 vfs_s_default_stat (vfs *me, mode_t mode)
147 static struct stat st;
148 int myumask;
150 myumask = umask (022);
151 umask (myumask);
152 mode &= ~myumask;
154 st.st_mode = mode;
155 st.st_ino = 0;
156 st.st_dev = 0;
157 st.st_rdev = 0;
158 st.st_uid = getuid ();
159 st.st_gid = getgid ();
160 st.st_size = 0;
161 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
163 return &st;
166 void
167 vfs_s_add_dots (vfs *me, vfs_s_inode *dir, vfs_s_inode *parent)
169 struct vfs_s_entry *dot, *dotdot;
171 if (!parent)
172 parent = dir;
173 dot = vfs_s_new_entry (me, ".", dir);
174 dotdot = vfs_s_new_entry (me, "..", parent);
175 vfs_s_insert_entry (me, dir, dot);
176 vfs_s_insert_entry (me, dir, dotdot);
177 dir->st.st_nlink--;
178 parent->st.st_nlink--; /* We do not count "." and ".." into nlinks */
181 struct vfs_s_entry *
182 vfs_s_generate_entry (vfs *me, char *name, struct vfs_s_inode *parent, mode_t mode)
184 struct vfs_s_inode *inode;
185 struct stat *st;
187 st = vfs_s_default_stat (me, mode);
188 inode = vfs_s_new_inode (me, parent->super, st);
189 if (S_ISDIR (mode))
190 vfs_s_add_dots (me, inode, parent);
192 return vfs_s_new_entry (me, name, inode);
195 /* We were asked to create entries automagically */
196 vfs_s_entry *
197 vfs_s_automake (vfs *me, vfs_s_inode *dir, char *path, int flags)
199 struct vfs_s_entry *res;
200 char *sep = strchr (path, PATH_SEP);
202 if (sep)
203 *sep = 0;
204 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
205 vfs_s_insert_entry (me, dir, res);
207 if (sep)
208 *sep = PATH_SEP;
210 return res;
214 * Follow > 0: follow links, serves as loop protect,
215 * == -1: do not follow links
217 vfs_s_entry *
218 vfs_s_find_entry_tree (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
220 unsigned int pseg;
221 vfs_s_entry *ent = NULL;
222 char p[MC_MAXPATHLEN] = "";
224 while (root){
225 int t;
227 while (*path == PATH_SEP) /* Strip leading '/' */
228 path++;
230 if (!path [0])
231 return ent;
233 for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++)
236 strcat (p, PATH_SEP_STR);
237 strncpy (p + (t = strlen (p)), path, pseg);
238 p[t + pseg] = '\0';
240 for (ent = root->subdir; ent != NULL; ent = ent->next)
241 if (strlen (ent->name) == pseg && (!strncmp (ent->name, path, pseg)))
242 /* FOUND! */
243 break;
245 if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
246 ent = vfs_s_automake (me, root, path, flags);
247 if (!ent) ERRNOR (ENOENT, NULL);
248 path += pseg;
249 /* here we must follow leading directories always; only the actual file is optional */
250 if (!(ent = vfs_s_resolve_symlink (me, ent, p, strchr (path, PATH_SEP) ? LINK_FOLLOW : follow)))
251 return NULL;
252 root = ent->ino;
255 return NULL;
258 static void
259 split_dir_name (vfs *me, char *path, char **dir, char **name, char **save)
261 char *s;
262 s = strrchr (path, PATH_SEP);
263 if (!s){
264 *save = NULL;
265 *name = path;
266 *dir = "";
267 } else {
268 *save = s;
269 *dir = path;
270 *s++ = 0;
271 *name = s;
275 vfs_s_entry *
276 vfs_s_find_entry_linear (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
278 vfs_s_entry* ent = NULL;
280 if (root->super->root != root)
281 vfs_die ("We have to use _real_ root. Always. Sorry." );
283 canonicalize_pathname (path);
285 if (!(flags & FL_DIR)){
286 char *dirname, *name, *save;
287 vfs_s_inode *ino;
288 split_dir_name (me, path, &dirname, &name, &save);
289 ino = vfs_s_find_inode (me, root, dirname, follow, flags | FL_DIR);
290 if (save)
291 *save = PATH_SEP;
292 return vfs_s_find_entry_tree (me, ino, name, follow, flags);
295 for (ent = root->subdir; ent != NULL; ent = ent->next)
296 if (!strcmp (ent->name, path))
297 break;
299 if (ent && (! (MEDATA->dir_uptodate) (me, ent->ino))){
300 #if 1
301 print_vfs_message (_("Dir cache expired for %s"), path);
302 #endif
303 vfs_s_free_entry (me, ent);
304 ent = NULL;
307 if (!ent){
308 vfs_s_inode *ino;
310 ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
311 ent = vfs_s_new_entry (me, path, ino);
312 if ((MEDATA->dir_load) (me, ino, path) == -1){
313 vfs_s_free_entry (me, ent);
314 return NULL;
316 vfs_s_insert_entry (me, root, ent);
318 for (ent = root->subdir; ent != NULL; ent = ent->next)
319 if (!strcmp (ent->name, path))
320 break;
322 if (!ent)
323 vfs_die ("find_linear: success but directory is not there\n");
325 #if 0
326 if (!vfs_s_resolve_symlink (me, ent, follow)) return NULL;
327 #endif
328 return ent;
331 vfs_s_inode *
332 vfs_s_find_inode (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
334 vfs_s_entry *ent;
335 if ((MEDATA->find_entry == vfs_s_find_entry_tree) && (!*path))
336 return root;
337 ent = (MEDATA->find_entry)(me, root, path, follow, flags);
338 if (!ent)
339 return NULL;
340 return ent->ino;
343 vfs_s_entry *
344 vfs_s_resolve_symlink (vfs *me, vfs_s_entry *entry, char *path, int follow)
346 char buf[MC_MAXPATHLEN], *linkname;
348 if (follow == LINK_NO_FOLLOW)
349 return entry;
350 if (follow == 0)
351 ERRNOR (ELOOP, NULL);
352 if (!entry)
353 ERRNOR (ENOENT, NULL);
354 if (!S_ISLNK (entry->ino->st.st_mode))
355 return entry;
357 linkname = entry->ino->linkname;
359 if (linkname == NULL)
360 ERRNOR (EFAULT, NULL);
362 if (MEDATA->find_entry == vfs_s_find_entry_linear) {
363 if (*linkname == PATH_SEP)
364 return (MEDATA->find_entry) (me, entry->dir->super->root,
365 linkname, follow - 1, 0);
366 else {
367 char *fullpath = vfs_s_fullpath (me, entry->dir);
369 g_snprintf (buf, sizeof (buf), "%s/%s", fullpath, linkname);
370 g_free (fullpath);
371 return (MEDATA->find_entry) (me, entry->dir->super->root, buf,
372 follow - 1, 0);
376 /* Convert absolute paths to relative ones */
377 if (*linkname == PATH_SEP) {
378 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;
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 */
952 got_interrupt ();
953 enable_interrupt_key ();
955 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof (buffer)))) {
957 if (n < 0)
958 goto error_1;
960 total += n;
961 vfs_print_stats (me->name, _("Getting file"), ino->ent->name,
962 total, stat_size);
964 if (got_interrupt ())
965 goto error_1;
967 if (write (handle, buffer, n) < 0) {
968 me->verrno = errno;
969 goto error_1;
972 MEDATA->linear_close (me, &fh);
973 close (handle);
975 disable_interrupt_key ();
976 return 0;
978 error_1:
979 MEDATA->linear_close (me, &fh);
980 error_3:
981 disable_interrupt_key ();
982 close (handle);
983 unlink (ino->localname);
984 error_4:
985 g_free (ino->localname);
986 ino->localname = NULL;
987 return -1;
990 /* ------------------------------- mc support ---------------------------- */
992 void
993 vfs_s_fill_names (vfs *me, void (*func)(char *))
995 struct vfs_s_super *a = MEDATA->supers;
996 char *name;
998 while (a){
999 name = g_strconcat ( a->name, "#", me->prefix, "/", /* a->current_dir->name, */ NULL);
1000 (*func)(name);
1001 g_free (name);
1002 a = a->next;
1007 vfs_s_ferrno (vfs *me)
1009 return me->verrno;
1012 void
1013 vfs_s_dump (vfs *me, char *prefix, vfs_s_inode *ino)
1015 printf ("%s %s %d ", prefix, S_ISDIR (ino->st.st_mode) ? "DIR" : "FILE", ino->st.st_mode);
1016 if (!ino->subdir)
1017 printf ("FILE\n");
1018 else
1020 struct vfs_s_entry *ent;
1021 for (ent = ino->subdir; ent ; ent = ent->next){
1022 char *s = g_strconcat (prefix, "/", ent->name, NULL);
1023 if (ent->name[0] == '.')
1024 printf ("%s IGNORED\n", s);
1025 else
1026 vfs_s_dump (me, s, ent->ino);
1027 g_free(s);
1032 char *
1033 vfs_s_getlocalcopy (vfs *me, char *path)
1035 struct vfs_s_inode *ino;
1036 char buf[MC_MAXPATHLEN];
1038 strncpy (buf, path, MC_MAXPATHLEN);
1039 ino = vfs_s_inode_from_path (me, path, FL_FOLLOW | FL_NONE);
1041 if (!ino->localname)
1042 ino->localname = mc_def_getlocalcopy (me, buf);
1043 /* FIXME: fd_usage++ missing */
1044 return g_strdup (ino->localname);
1047 int
1048 vfs_s_setctl (vfs *me, char *path, int ctlop, char *arg)
1050 vfs_s_inode *ino = vfs_s_inode_from_path (me, path, 0);
1051 if (!ino)
1052 return 0;
1053 switch (ctlop){
1054 case MCCTL_WANT_STALE_DATA:
1055 ino->super->want_stale = 1;
1056 return 1;
1057 case MCCTL_NO_STALE_DATA:
1058 ino->super->want_stale = 0;
1059 vfs_s_invalidate(me, ino->super);
1060 return 1;
1061 #if 0 /* FIXME: We should implement these */
1062 case MCCTL_REMOVELOCALCOPY:
1063 return remove_temp_file (path);
1064 case MCCTL_FORGET_ABOUT:
1065 my_forget(path);
1066 return 0;
1067 #endif
1069 return 0;
1073 /* ----------------------------- Stamping support -------------------------- */
1075 vfsid
1076 vfs_s_getid (vfs *me, char *path, struct vfs_stamping **parent)
1078 vfs_s_super *archive;
1079 vfs *v;
1080 char *p;
1081 vfsid id;
1082 struct vfs_stamping *par;
1084 *parent = NULL;
1085 if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
1086 return (vfsid) -1;
1087 g_free(p);
1088 v = vfs_type (archive->name);
1089 id = (*v->getid) (v, archive->name, &par);
1090 if (id != (vfsid)-1){
1091 *parent = g_new (struct vfs_stamping, 1);
1092 (*parent)->v = v;
1093 (*parent)->id = id;
1094 (*parent)->parent = par;
1095 (*parent)->next = NULL;
1097 return (vfsid) archive;
1101 vfs_s_nothingisopen (vfsid id)
1103 /* Our data structures should survive free of superblock at any time */
1104 return 1;
1107 void
1108 vfs_s_free (vfsid id)
1110 vfs_s_free_super (((vfs_s_super *)id)->me, (vfs_s_super *)id);
1113 /* ----------- Utility functions for networked filesystems -------------- */
1115 #ifdef USE_NETCODE
1117 vfs_s_select_on_two (int fd1, int fd2)
1119 fd_set set;
1120 struct timeval timeout;
1121 int v;
1122 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1124 timeout.tv_sec = 1;
1125 timeout.tv_usec = 0;
1126 FD_ZERO (&set);
1127 FD_SET (fd1, &set);
1128 FD_SET (fd2, &set);
1129 v = select (maxfd, &set, 0, 0, &timeout);
1130 if (v <= 0)
1131 return v;
1132 if (FD_ISSET (fd1, &set))
1133 return 1;
1134 if (FD_ISSET (fd2, &set))
1135 return 2;
1136 return -1;
1140 vfs_s_get_line (vfs *me, int sock, char *buf, int buf_len, char term)
1142 FILE *logfile = MEDATA->logfile;
1143 int i, status;
1144 char c;
1146 for (i = 0; i < buf_len - 1; i++, buf++){
1147 if (read (sock, buf, sizeof(char)) <= 0)
1148 return 0;
1149 if (logfile){
1150 fwrite (buf, 1, 1, logfile);
1151 fflush (logfile);
1153 if (*buf == term){
1154 *buf = 0;
1155 return 1;
1159 /* Line is too long - terminate buffer and discard the rest of line */
1160 *buf = 0;
1161 while ((status = read (sock, &c, sizeof (c))) > 0){
1162 if (logfile){
1163 fwrite (&c, 1, 1, logfile);
1164 fflush (logfile);
1166 if (c == '\n')
1167 return 1;
1169 return 0;
1173 vfs_s_get_line_interruptible (vfs *me, char *buffer, int size, int fd)
1175 int n;
1176 int i;
1178 enable_interrupt_key ();
1179 for (i = 0; i < size-1; i++){
1180 n = read (fd, buffer+i, 1);
1181 disable_interrupt_key ();
1182 if (n == -1 && errno == EINTR){
1183 buffer [i] = 0;
1184 return EINTR;
1186 if (n == 0){
1187 buffer [i] = 0;
1188 return 0;
1190 if (buffer [i] == '\n'){
1191 buffer [i] = 0;
1192 return 1;
1195 buffer [size-1] = 0;
1196 return 0;
1198 #endif /* USE_NETCODE */