Traslated some chmod mgs related (for win32 support? not shure)
[midnight-commander.git] / vfs / direntry.c
blob8ea874ff05356e2195bdffe5364b0567b721aaef
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_entry *ent;
91 ent = ino->subdir;
92 vfs_s_free_entry (me, ent);
95 CALL (free_inode) (me, ino);
96 ifree (ino->linkname);
97 if (ino->localname){
98 unlink (ino->localname);
99 g_free(ino->localname);
101 total_inodes--;
102 ino->super->ino_usage--;
103 g_free(ino);
104 } else ino->st.st_nlink--;
107 void
108 vfs_s_free_entry (vfs *me, vfs_s_entry *ent)
110 int is_dot = 0;
111 if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
112 *ent->prevp = ent->next;
113 if (ent->next)
114 ent->next->prevp = ent->prevp;
117 if (ent->name){
118 is_dot = (!strcmp (ent->name, ".")) || (!strcmp (ent->name, ".."));
119 g_free (ent->name);
120 ent->name = NULL;
123 if (!is_dot && ent->ino){
124 ent->ino->ent = NULL;
125 vfs_s_free_inode (me, ent->ino);
126 ent->ino = NULL;
129 total_entries--;
130 g_free(ent);
133 void
134 vfs_s_insert_entry (vfs *me, vfs_s_inode *dir, vfs_s_entry *ent)
136 vfs_s_entry **ep;
138 for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
140 ent->prevp = ep;
141 ent->next = NULL;
142 ent->dir = dir;
143 *ep = ent;
145 ent->ino->st.st_nlink++;
148 struct stat *
149 vfs_s_default_stat (vfs *me, mode_t mode)
151 static struct stat st;
152 int myumask;
154 myumask = umask (022);
155 umask (myumask);
156 mode &= ~myumask;
158 st.st_mode = mode;
159 st.st_ino = 0;
160 st.st_dev = 0;
161 st.st_rdev = 0;
162 st.st_uid = getuid ();
163 st.st_gid = getgid ();
164 st.st_size = 0;
165 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
167 return &st;
170 void
171 vfs_s_add_dots (vfs *me, vfs_s_inode *dir, vfs_s_inode *parent)
173 struct vfs_s_entry *dot, *dotdot;
175 if (!parent)
176 parent = dir;
177 dot = vfs_s_new_entry (me, ".", dir);
178 dotdot = vfs_s_new_entry (me, "..", parent);
179 vfs_s_insert_entry (me, dir, dot);
180 vfs_s_insert_entry (me, dir, dotdot);
181 dir->st.st_nlink--;
182 parent->st.st_nlink--; /* We do not count "." and ".." into nlinks */
185 struct vfs_s_entry *
186 vfs_s_generate_entry (vfs *me, char *name, struct vfs_s_inode *parent, mode_t mode)
188 struct vfs_s_inode *inode;
189 struct stat *st;
191 st = vfs_s_default_stat (me, mode);
192 inode = vfs_s_new_inode (me, parent->super, st);
193 if (S_ISDIR (mode))
194 vfs_s_add_dots (me, inode, parent);
196 return vfs_s_new_entry (me, name, inode);
199 /* We were asked to create entries automagically */
200 vfs_s_entry *
201 vfs_s_automake (vfs *me, vfs_s_inode *dir, char *path, int flags)
203 struct vfs_s_entry *res;
204 char *sep = strchr (path, PATH_SEP);
206 if (sep)
207 *sep = 0;
208 res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
209 vfs_s_insert_entry (me, dir, res);
211 if (sep)
212 *sep = PATH_SEP;
214 return res;
218 * Follow > 0: follow links, serves as loop protect,
219 * == -1: do not follow links
221 vfs_s_entry *
222 vfs_s_find_entry_tree (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
224 unsigned int pseg;
225 vfs_s_entry *ent = NULL;
226 char p[MC_MAXPATHLEN] = "";
228 while (root){
229 int t;
231 while (*path == PATH_SEP) /* Strip leading '/' */
232 path++;
234 if (!path [0])
235 return ent;
237 for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++)
240 strcat (p, PATH_SEP_STR);
241 strncpy (p + (t = strlen (p)), path, pseg);
242 p[t + pseg] = '\0';
244 for (ent = root->subdir; ent != NULL; ent = ent->next)
245 if (strlen (ent->name) == pseg && (!strncmp (ent->name, path, pseg)))
246 /* FOUND! */
247 break;
249 if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
250 ent = vfs_s_automake (me, root, path, flags);
251 if (!ent) ERRNOR (ENOENT, NULL);
252 path += pseg;
253 /* here we must follow leading directories always; only the actual file is optional */
254 if (!(ent = vfs_s_resolve_symlink (me, ent, p, strchr (path, PATH_SEP) ? LINK_FOLLOW : follow)))
255 return NULL;
256 root = ent->ino;
259 return NULL;
262 static void
263 split_dir_name (vfs *me, char *path, char **dir, char **name, char **save)
265 char *s;
266 s = strrchr (path, PATH_SEP);
267 if (!s){
268 *save = NULL;
269 *name = path;
270 *dir = "";
271 } else {
272 *save = s;
273 *dir = path;
274 *s++ = 0;
275 *name = s;
279 vfs_s_entry *
280 vfs_s_find_entry_linear (vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
282 vfs_s_entry* ent = NULL;
284 if (root->super->root != root)
285 vfs_die ("We have to use _real_ root. Always. Sorry." );
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 sprintf(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 direcory 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 ifree (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 struct {
619 struct dirent dir;
620 #ifdef NEED_EXTRA_DIRENT_BUFFER
621 char extra_buffer [MC_MAXPATHLEN];
622 #endif
623 } dir;
625 struct dirhandle *info = (struct dirhandle *) data;
627 if (!(info->cur))
628 return NULL;
630 if (info->cur->name)
631 strcpy (&(dir.dir.d_name [0]), info->cur->name);
632 else
633 vfs_die ("Null in structure-can not happen");
635 #ifndef DIRENT_LENGTH_COMPUTED
636 dir.d_namlen = strlen (dir.dir.d_name);
637 #endif
638 info->cur = info->cur->next;
640 return (void *)&dir;
644 vfs_s_telldir (void *data)
646 struct dirhandle *info = (struct dirhandle *) data;
647 struct vfs_s_entry *cur;
648 int num = 0;
650 cur = info->dir->subdir;
651 while (cur!=NULL){
652 if (cur == info->cur)
653 return num;
654 num++;
655 cur = cur->next;
657 return -1;
660 void
661 vfs_s_seekdir (void *data, int offset)
663 struct dirhandle *info = (struct dirhandle *) data;
664 int i;
665 info->cur = info->dir->subdir;
666 for (i=0; i<offset; i++)
667 vfs_s_readdir (data);
671 vfs_s_closedir (void *data)
673 struct dirhandle *info = (struct dirhandle *) data;
674 struct vfs_s_inode *dir = info->dir;
676 vfs_s_free_inode (dir->super->me, dir);
677 g_free (data);
678 return 0;
682 vfs_s_chdir (vfs *me, char *path)
684 void *data;
685 if (!(data = vfs_s_opendir (me, path)))
686 return -1;
687 vfs_s_closedir (data);
688 return 0;
691 /* --------------------------- stat and friends ---------------------------- */
693 static int
694 vfs_s_internal_stat (vfs *me, char *path, struct stat *buf, int flag)
696 struct vfs_s_inode *ino;
698 if (!(ino = vfs_s_inode_from_path (me, path, flag)))
699 return -1;
700 *buf = ino->st;
701 return 0;
705 vfs_s_stat (vfs *me, char *path, struct stat *buf)
707 return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
711 vfs_s_lstat (vfs *me, char *path, struct stat *buf)
713 return vfs_s_internal_stat (me, path, buf, FL_NONE);
717 vfs_s_fstat (void *fh, struct stat *buf)
719 *buf = FH->ino->st;
720 return 0;
724 vfs_s_readlink (vfs *me, char *path, char *buf, int size)
726 struct vfs_s_inode *ino;
728 ino = vfs_s_inode_from_path (me, path, 0);
729 if (!ino)
730 return -1;
732 if (!S_ISLNK (ino->st.st_mode))
733 ERRNOR (EINVAL, -1);
735 if (ino->linkname == NULL)
736 ERRNOR (EFAULT, -1);
738 strncpy (buf, ino->linkname, size);
739 *(buf+size-1) = 0;
740 return strlen (buf);
743 void *
744 vfs_s_open (vfs *me, char *file, int flags, int mode)
746 int was_changed = 0;
747 struct vfs_s_fh *fh;
748 vfs_s_super *super;
749 char *q;
750 struct vfs_s_inode *ino;
752 if ((q = vfs_s_get_path_mangle (me, file, &super, 0)) == NULL)
753 return NULL;
754 ino = vfs_s_find_inode (me, super->root, q, LINK_FOLLOW, FL_NONE);
755 if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)))
756 ERRNOR (EEXIST, NULL);
757 if (!ino){
758 char *dirname, *name, *save;
759 vfs_s_entry *ent;
760 vfs_s_inode *dir;
761 int tmp_handle;
762 if (!(flags & O_CREAT))
763 return NULL;
765 split_dir_name (me, q, &dirname, &name, &save);
766 /* FIXME: if vfs_s_find_inode returns NULL, this will do rather bad
767 things. */
768 dir = vfs_s_find_inode (me, super->root, dirname, LINK_FOLLOW, FL_DIR);
769 if (save)
770 *save = PATH_SEP;
771 ent = vfs_s_generate_entry (me, name, dir, 0755);
772 ino = ent->ino;
773 vfs_s_insert_entry (me, dir, ent);
774 tmp_handle = mc_mkstemps (&ino->localname, me->name, NULL);
775 if (tmp_handle == -1)
776 return NULL;
777 close (tmp_handle);
778 was_changed = 1;
781 if (S_ISDIR (ino->st.st_mode))
782 ERRNOR (EISDIR, NULL);
784 fh = g_new (struct vfs_s_fh, 1);
785 fh->pos = 0;
786 fh->ino = ino;
787 fh->handle = -1;
788 fh->changed = was_changed;
789 fh->linear = 0;
791 if (IS_LINEAR(flags)) {
792 fh->linear = LS_LINEAR_CLOSED;
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, 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 print_vfs_message (_("Starting linear transfer..."));
821 if (!MEDATA->linear_start (me, FH, 0))
822 return -1;
825 if (FH->linear == LS_LINEAR_CLOSED)
826 vfs_die ("linear_start() did not set linear_state!");
828 if (FH->linear == LS_LINEAR_OPEN)
829 return MEDATA->linear_read (me, FH, buffer, count);
831 if (FH->handle){
832 n = read (FH->handle, buffer, count);
833 if (n < 0)
834 me->verrno = errno;
835 return n;
837 vfs_die ("vfs_s_read: This should not happen\n");
838 return -1;
842 vfs_s_write (void *fh, char *buffer, int count)
844 int n;
845 vfs *me = FH_SUPER->me;
847 if (FH->linear)
848 vfs_die ("no writing to linear files, please");
850 FH->changed = 1;
851 if (FH->handle){
852 n = write (FH->handle, buffer, count);
853 if (n < 0)
854 me->verrno = errno;
855 return n;
857 vfs_die ("vfs_s_write: This should not happen\n");
858 return 0;
862 vfs_s_lseek (void *fh, off_t offset, int whence)
864 off_t size = FH->ino->st.st_size;
866 if (FH->handle != -1){ /* If we have local file opened, we want to work with it */
867 int retval = lseek (FH->handle, offset, whence);
868 if (retval == -1)
869 FH->ino->super->me->verrno = errno;
870 return retval;
873 switch (whence){
874 case SEEK_CUR:
875 offset += FH->pos; break;
876 case SEEK_END:
877 offset += size; break;
879 if (offset < 0)
880 FH->pos = 0;
881 else if (offset < size)
882 FH->pos = offset;
883 else
884 FH->pos = size;
885 return FH->pos;
889 vfs_s_close (void *fh)
891 int res = 0;
892 vfs *me = FH_SUPER->me;
894 FH_SUPER->fd_usage--;
895 if (!FH_SUPER->fd_usage){
896 struct vfs_stamping *parent;
897 vfs *v;
899 v = vfs_type (FH_SUPER->name);
900 if (v == &vfs_local_ops){
901 parent = NULL;
902 } else {
903 parent = g_new (struct vfs_stamping, 1);
904 parent->v = v;
905 parent->next = 0;
906 parent->id = (*v->getid) (v, FH_SUPER->name, &(parent->parent));
908 vfs_add_noncurrent_stamps (me, (vfsid) (FH_SUPER), parent);
909 vfs_rm_parents (parent);
911 if (FH->linear == LS_LINEAR_OPEN)
912 MEDATA->linear_close (me, fh);
913 if (MEDATA->fh_close)
914 res = MEDATA->fh_close (me, fh);
915 if (FH->changed && MEDATA->file_store){
916 char *s = vfs_s_fullpath (me, FH->ino);
917 if (!s)
918 res = -1;
919 else {
920 res = MEDATA->file_store (me, FH_SUPER, s, FH->ino->localname);
921 g_free (s);
923 vfs_s_invalidate (me, FH_SUPER);
925 if (FH->handle)
926 close (FH->handle);
928 vfs_s_free_inode (me, FH->ino);
929 g_free (fh);
930 return res;
933 int
934 vfs_s_retrieve_file(vfs *me, struct vfs_s_inode *ino)
936 /* If you want reget, you'll have to open file with O_LINEAR */
937 int total = 0;
938 char buffer[8192];
939 int handle, n;
940 int stat_size = ino->st.st_size;
941 struct vfs_s_fh fh;
943 memset(&fh, 0, sizeof(fh));
945 fh.ino = ino;
947 handle = mc_mkstemps (&ino->localname, me->name, NULL);
948 if (handle == -1) {
949 me->verrno = errno;
950 goto error_4;
953 if (!MEDATA->linear_start (me, &fh, 0))
954 goto error_3;
956 /* Clear the interrupt status */
958 while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof(buffer)))) {
960 if (n < 0)
961 goto error_1;
963 total += n;
964 vfs_print_stats (me->name, _("Getting file"), ino->ent->name, total, stat_size);
966 if (write(handle, buffer, n) < 0) {
967 me->verrno = errno;
968 goto error_1;
971 MEDATA->linear_close (me, &fh);
972 close(handle);
974 if (stat (ino->localname, &ino->u.fish.local_stat) < 0)
975 ino->u.fish.local_stat.st_mtime = 0;
977 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 strcpy (buf, path);
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 -------------- */
1116 vfs_s_select_on_two (int fd1, int fd2)
1118 fd_set set;
1119 struct timeval timeout;
1120 int v;
1121 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
1123 timeout.tv_sec = 1;
1124 timeout.tv_usec = 0;
1125 FD_ZERO (&set);
1126 FD_SET (fd1, &set);
1127 FD_SET (fd2, &set);
1128 v = select (maxfd, &set, 0, 0, &timeout);
1129 if (v <= 0)
1130 return v;
1131 if (FD_ISSET (fd1, &set))
1132 return 1;
1133 if (FD_ISSET (fd2, &set))
1134 return 2;
1135 return -1;
1139 vfs_s_get_line (vfs *me, int sock, char *buf, int buf_len, char term)
1141 FILE *logfile = MEDATA->logfile;
1142 int i, status;
1143 char c;
1145 for (i = 0; i < buf_len; i++, buf++){
1146 if (read (sock, buf, sizeof(char)) <= 0)
1147 return 0;
1148 if (logfile){
1149 fwrite (buf, 1, 1, logfile);
1150 fflush (logfile);
1152 if (*buf == term){
1153 *buf = 0;
1154 return 1;
1157 *buf = 0;
1158 while ((status = read (sock, &c, sizeof (c))) > 0){
1159 if (logfile){
1160 fwrite (&c, 1, 1, logfile);
1161 fflush (logfile);
1163 if (c == '\n')
1164 return 1;
1166 return 0;
1170 vfs_s_get_line_interruptible (vfs *me, char *buffer, int size, int fd)
1172 int n;
1173 int i;
1175 enable_interrupt_key ();
1176 for (i = 0; i < size-1; i++){
1177 n = read (fd, buffer+i, 1);
1178 disable_interrupt_key ();
1179 if (n == -1 && errno == EINTR){
1180 buffer [i] = 0;
1181 return EINTR;
1183 if (n == 0){
1184 buffer [i] = 0;
1185 return 0;
1187 if (buffer [i] == '\n'){
1188 buffer [i] = 0;
1189 return 1;
1192 buffer [size-1] = 0;
1193 return 0;