This source file includes following definitions.
- vfs_s_automake
- vfs_s_resolve_symlink
- vfs_s_find_entry_tree
- vfs_s_find_entry_linear
- vfs_s_new_super
- vfs_s_insert_super
- vfs_s_free_super
- vfs_s_new_fh
- vfs_s_free_fh
- vfs_s_inode_from_path
- vfs_s_opendir
- vfs_s_readdir
- vfs_s_closedir
- vfs_s_chdir
- vfs_s_internal_stat
- vfs_s_readlink
- vfs_s_read
- vfs_s_write
- vfs_s_lseek
- vfs_s_close
- vfs_s_print_stats
- vfs_s_fill_names
- vfs_s_ferrno
- vfs_s_getlocalcopy
- vfs_s_ungetlocalcopy
- vfs_s_setctl
- vfs_s_getid
- vfs_s_nothingisopen
- vfs_s_free
- vfs_s_dir_uptodate
- vfs_s_new_inode
- vfs_s_free_inode
- vfs_s_new_entry
- vfs_s_free_entry
- vfs_s_insert_entry
- vfs_s_entry_compare
- vfs_s_default_stat
- vfs_adjust_stat
- vfs_s_generate_entry
- vfs_s_find_inode
- vfs_get_super_by_vpath
- vfs_s_get_path
- vfs_s_invalidate
- vfs_s_fullpath
- vfs_s_init_fh
- vfs_s_open
- vfs_s_stat
- vfs_s_lstat
- vfs_s_fstat
- vfs_s_retrieve_file
- vfs_init_class
- vfs_init_subclass
- vfs_getid
- vfs_s_select_on_two
- vfs_s_get_line
- vfs_s_get_line_interruptible
- vfs_s_normalize_filename_leading_spaces
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 #include <config.h>
60
61 #include <errno.h>
62 #include <inttypes.h>
63 #include <stdarg.h>
64 #ifdef HAVE_SYS_SELECT_H
65 #include <sys/select.h>
66 #endif
67 #include <sys/types.h>
68 #include <unistd.h>
69
70 #include "lib/global.h"
71
72 #include "lib/tty/tty.h"
73 #include "lib/util.h"
74 #if 0
75 #include "lib/widget.h"
76 #endif
77
78 #include "vfs.h"
79 #include "utilvfs.h"
80 #include "xdirentry.h"
81 #include "gc.h"
82
83
84
85
86
87 #define CALL(x) \
88 if (VFS_SUBCLASS (me)->x != NULL) \
89 VFS_SUBCLASS (me)->x
90
91
92
93 struct dirhandle
94 {
95 GList *cur;
96 struct vfs_s_inode *dir;
97 };
98
99
100
101
102
103
104
105
106
107
108
109 static struct vfs_s_entry *
110 vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
111 {
112 struct vfs_s_entry *res;
113 char *sep;
114
115 sep = strchr (path, PATH_SEP);
116 if (sep != NULL)
117 *sep = '\0';
118
119 res = vfs_s_generate_entry (me, path, dir, (flags & FL_MKDIR) != 0 ? (0777 | S_IFDIR) : 0777);
120 vfs_s_insert_entry (me, dir, res);
121
122 if (sep != NULL)
123 *sep = PATH_SEP;
124
125 return res;
126 }
127
128
129
130
131 static struct vfs_s_entry *
132 vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry, int follow)
133 {
134 char *linkname;
135 char *fullname = NULL;
136 struct vfs_s_entry *target;
137
138 if (follow == LINK_NO_FOLLOW)
139 return entry;
140 if (follow == 0)
141 ERRNOR (ELOOP, NULL);
142 if (entry == NULL)
143 ERRNOR (ENOENT, NULL);
144 if (!S_ISLNK (entry->ino->st.st_mode))
145 return entry;
146
147 linkname = entry->ino->linkname;
148 if (linkname == NULL)
149 ERRNOR (EFAULT, NULL);
150
151
152 if (!IS_PATH_SEP (*linkname))
153 {
154 char *fullpath;
155
156 fullpath = vfs_s_fullpath (me, entry->dir);
157 if (fullpath != NULL)
158 {
159 fullname = g_strconcat (fullpath, PATH_SEP_STR, linkname, (char *) NULL);
160 linkname = fullname;
161 g_free (fullpath);
162 }
163 }
164
165 target =
166 VFS_SUBCLASS (me)->find_entry (me, entry->dir->super->root, linkname, follow - 1, FL_NONE);
167 g_free (fullname);
168 return target;
169 }
170
171
172
173
174
175
176
177 static struct vfs_s_entry *
178 vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
179 const char *a_path, int follow, int flags)
180 {
181 size_t pseg;
182 struct vfs_s_entry *ent = NULL;
183 char *const pathref = g_strdup (a_path);
184 char *path = pathref;
185
186
187 canonicalize_pathname_custom (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
188
189 while (root != NULL)
190 {
191 GList *iter;
192
193 while (IS_PATH_SEP (*path))
194 path++;
195
196 if (path[0] == '\0')
197 {
198 g_free (pathref);
199 return ent;
200 }
201
202 for (pseg = 0; path[pseg] != '\0' && !IS_PATH_SEP (path[pseg]); pseg++)
203 ;
204
205 for (iter = g_queue_peek_head_link (root->subdir); iter != NULL; iter = g_list_next (iter))
206 {
207 ent = VFS_ENTRY (iter->data);
208 if (strlen (ent->name) == pseg && strncmp (ent->name, path, pseg) == 0)
209
210 break;
211 }
212
213 ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
214
215 if (ent == NULL && (flags & (FL_MKFILE | FL_MKDIR)) != 0)
216 ent = vfs_s_automake (me, root, path, flags);
217 if (ent == NULL)
218 {
219 me->verrno = ENOENT;
220 goto cleanup;
221 }
222
223 path += pseg;
224
225
226 ent = vfs_s_resolve_symlink (me, ent,
227 strchr (path, PATH_SEP) != NULL ? LINK_FOLLOW : follow);
228 if (ent == NULL)
229 goto cleanup;
230 root = ent->ino;
231 }
232 cleanup:
233 g_free (pathref);
234 return NULL;
235 }
236
237
238
239 static struct vfs_s_entry *
240 vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
241 const char *a_path, int follow, int flags)
242 {
243 struct vfs_s_entry *ent = NULL;
244 char *const path = g_strdup (a_path);
245 GList *iter;
246
247 if (root->super->root != root)
248 vfs_die ("We have to use _real_ root. Always. Sorry.");
249
250
251 canonicalize_pathname_custom (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
252
253 if ((flags & FL_DIR) == 0)
254 {
255 char *dirname, *name;
256 struct vfs_s_inode *ino;
257
258 dirname = g_path_get_dirname (path);
259 name = g_path_get_basename (path);
260 ino = vfs_s_find_inode (me, root->super, dirname, follow, flags | FL_DIR);
261 ent = vfs_s_find_entry_tree (me, ino, name, follow, flags);
262 g_free (dirname);
263 g_free (name);
264 g_free (path);
265 return ent;
266 }
267
268 iter = g_queue_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
269 ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
270
271 if (ent != NULL && !VFS_SUBCLASS (me)->dir_uptodate (me, ent->ino))
272 {
273 #if 1
274 vfs_print_message (_("Directory cache expired for %s"), path);
275 #endif
276 vfs_s_free_entry (me, ent);
277 ent = NULL;
278 }
279
280 if (ent == NULL)
281 {
282 struct vfs_s_inode *ino;
283
284 ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
285 ent = vfs_s_new_entry (me, path, ino);
286 if (VFS_SUBCLASS (me)->dir_load (me, ino, path) == -1)
287 {
288 vfs_s_free_entry (me, ent);
289 g_free (path);
290 return NULL;
291 }
292
293 vfs_s_insert_entry (me, root, ent);
294
295 iter = g_queue_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
296 ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
297 }
298 if (ent == NULL)
299 vfs_die ("find_linear: success but directory is not there\n");
300
301 #if 0
302 if (vfs_s_resolve_symlink (me, ent, follow) == NULL)
303 {
304 g_free (path);
305 return NULL;
306 }
307 #endif
308 g_free (path);
309 return ent;
310 }
311
312
313
314
315
316 static struct vfs_s_super *
317 vfs_s_new_super (struct vfs_class *me)
318 {
319 struct vfs_s_super *super;
320
321 super = g_new0 (struct vfs_s_super, 1);
322 super->me = me;
323 return super;
324 }
325
326
327
328 static inline void
329 vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
330 {
331 VFS_SUBCLASS (me)->supers = g_list_prepend (VFS_SUBCLASS (me)->supers, super);
332 }
333
334
335
336 static void
337 vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
338 {
339 if (super->root != NULL)
340 {
341 vfs_s_free_inode (me, super->root);
342 super->root = NULL;
343 }
344
345 #if 0
346
347 if (super->ino_usage != 0)
348 message (D_ERROR, "Direntry warning",
349 "Super ino_usage is %d, memory leak", super->ino_usage);
350
351 if (super->want_stale)
352 message (D_ERROR, "Direntry warning", "%s", "Super has want_stale set");
353 #endif
354
355 VFS_SUBCLASS (me)->supers = g_list_remove (VFS_SUBCLASS (me)->supers, super);
356
357 CALL (free_archive) (me, super);
358 #ifdef ENABLE_VFS_NET
359 vfs_path_element_free (super->path_element);
360 #endif
361 g_free (super->name);
362 g_free (super);
363 }
364
365
366
367 static vfs_file_handler_t *
368 vfs_s_new_fh (struct vfs_s_inode *ino, gboolean changed)
369 {
370 vfs_file_handler_t *fh;
371
372 fh = g_new0 (vfs_file_handler_t, 1);
373 vfs_s_init_fh (fh, ino, changed);
374
375 return fh;
376 }
377
378
379
380 static void
381 vfs_s_free_fh (struct vfs_s_subclass *s, vfs_file_handler_t * fh)
382 {
383 if (s->fh_free != NULL)
384 s->fh_free (fh);
385
386 g_free (fh);
387 }
388
389
390
391
392
393 static struct vfs_s_inode *
394 vfs_s_inode_from_path (const vfs_path_t * vpath, int flags)
395 {
396 struct vfs_s_super *super;
397 struct vfs_s_inode *ino;
398 const char *q;
399 struct vfs_class *me;
400
401 q = vfs_s_get_path (vpath, &super, 0);
402 if (q == NULL)
403 return NULL;
404
405 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
406
407 ino =
408 vfs_s_find_inode (me, super, q,
409 (flags & FL_FOLLOW) != 0 ? LINK_FOLLOW : LINK_NO_FOLLOW,
410 flags & ~FL_FOLLOW);
411 if (ino == NULL && *q == '\0')
412
413 ino =
414 vfs_s_find_inode (me, super, q,
415 (flags & FL_FOLLOW) != 0 ? LINK_FOLLOW : LINK_NO_FOLLOW,
416 FL_DIR | (flags & ~FL_FOLLOW));
417 return ino;
418 }
419
420
421
422 static void *
423 vfs_s_opendir (const vfs_path_t * vpath)
424 {
425 struct vfs_s_inode *dir;
426 struct dirhandle *info;
427 struct vfs_class *me;
428
429 dir = vfs_s_inode_from_path (vpath, FL_DIR | FL_FOLLOW);
430 if (dir == NULL)
431 return NULL;
432
433 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
434
435 if (!S_ISDIR (dir->st.st_mode))
436 {
437 me->verrno = ENOTDIR;
438 return NULL;
439 }
440
441 dir->st.st_nlink++;
442 #if 0
443 if (dir->subdir == NULL)
444 {
445 me->verrno = EAGAIN;
446 return NULL;
447 }
448 #endif
449 info = g_new (struct dirhandle, 1);
450 info->cur = g_queue_peek_head_link (dir->subdir);
451 info->dir = dir;
452
453 return info;
454 }
455
456
457
458 static struct vfs_dirent *
459 vfs_s_readdir (void *data)
460 {
461 struct vfs_dirent *dir = NULL;
462 struct dirhandle *info = (struct dirhandle *) data;
463 const char *name;
464
465 if (info->cur == NULL || info->cur->data == NULL)
466 return NULL;
467
468 name = VFS_ENTRY (info->cur->data)->name;
469 if (name != NULL)
470 dir = vfs_dirent_init (NULL, name, 0);
471 else
472 vfs_die ("Null in structure-cannot happen");
473
474 info->cur = g_list_next (info->cur);
475
476 return dir;
477 }
478
479
480
481 static int
482 vfs_s_closedir (void *data)
483 {
484 struct dirhandle *info = (struct dirhandle *) data;
485 struct vfs_s_inode *dir = info->dir;
486
487 vfs_s_free_inode (dir->super->me, dir);
488 g_free (data);
489 return 0;
490 }
491
492
493
494 static int
495 vfs_s_chdir (const vfs_path_t * vpath)
496 {
497 void *data;
498
499 data = vfs_s_opendir (vpath);
500 if (data == NULL)
501 return (-1);
502 vfs_s_closedir (data);
503 return 0;
504 }
505
506
507
508
509 static int
510 vfs_s_internal_stat (const vfs_path_t * vpath, struct stat *buf, int flag)
511 {
512 struct vfs_s_inode *ino;
513
514 ino = vfs_s_inode_from_path (vpath, flag);
515 if (ino == NULL)
516 return (-1);
517 *buf = ino->st;
518 return 0;
519 }
520
521
522
523 static int
524 vfs_s_readlink (const vfs_path_t * vpath, char *buf, size_t size)
525 {
526 struct vfs_s_inode *ino;
527 size_t len;
528 struct vfs_class *me;
529
530 ino = vfs_s_inode_from_path (vpath, 0);
531 if (ino == NULL)
532 return (-1);
533
534 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
535
536 if (!S_ISLNK (ino->st.st_mode))
537 {
538 me->verrno = EINVAL;
539 return (-1);
540 }
541
542 if (ino->linkname == NULL)
543 {
544 me->verrno = EFAULT;
545 return (-1);
546 }
547
548 len = strlen (ino->linkname);
549 if (size < len)
550 len = size;
551
552 memcpy (buf, ino->linkname, len);
553 return len;
554 }
555
556
557
558 static ssize_t
559 vfs_s_read (void *fh, char *buffer, size_t count)
560 {
561 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
562 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
563
564 if (file->linear == LS_LINEAR_PREOPEN)
565 {
566 if (VFS_SUBCLASS (me)->linear_start (me, file, file->pos) == 0)
567 return (-1);
568 }
569
570 if (file->linear == LS_LINEAR_CLOSED)
571 vfs_die ("linear_start() did not set linear_state!");
572
573 if (file->linear == LS_LINEAR_OPEN)
574 return VFS_SUBCLASS (me)->linear_read (me, file, buffer, count);
575
576 if (file->handle != -1)
577 {
578 ssize_t n;
579
580 n = read (file->handle, buffer, count);
581 if (n < 0)
582 me->verrno = errno;
583 return n;
584 }
585 vfs_die ("vfs_s_read: This should not happen\n");
586 return (-1);
587 }
588
589
590
591 static ssize_t
592 vfs_s_write (void *fh, const char *buffer, size_t count)
593 {
594 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
595 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
596
597 if (file->linear != LS_NOT_LINEAR)
598 vfs_die ("no writing to linear files, please");
599
600 file->changed = TRUE;
601 if (file->handle != -1)
602 {
603 ssize_t n;
604
605 n = write (file->handle, buffer, count);
606 if (n < 0)
607 me->verrno = errno;
608 return n;
609 }
610 vfs_die ("vfs_s_write: This should not happen\n");
611 return 0;
612 }
613
614
615
616 static off_t
617 vfs_s_lseek (void *fh, off_t offset, int whence)
618 {
619 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
620 off_t size = file->ino->st.st_size;
621
622 if (file->linear == LS_LINEAR_OPEN)
623 vfs_die ("cannot lseek() after linear_read!");
624
625 if (file->handle != -1)
626 {
627 off_t retval;
628
629 retval = lseek (file->handle, offset, whence);
630 if (retval == -1)
631 VFS_FILE_HANDLER_SUPER (fh)->me->verrno = errno;
632 return retval;
633 }
634
635 switch (whence)
636 {
637 case SEEK_CUR:
638 offset += file->pos;
639 break;
640 case SEEK_END:
641 offset += size;
642 break;
643 default:
644 break;
645 }
646 if (offset < 0)
647 file->pos = 0;
648 else if (offset < size)
649 file->pos = offset;
650 else
651 file->pos = size;
652 return file->pos;
653 }
654
655
656
657 static int
658 vfs_s_close (void *fh)
659 {
660 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
661 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
662 struct vfs_class *me = super->me;
663 struct vfs_s_subclass *sub = VFS_SUBCLASS (me);
664 int res = 0;
665
666 if (me == NULL)
667 return (-1);
668
669 super->fd_usage--;
670 if (super->fd_usage == 0)
671 vfs_stamp_create (me, VFS_FILE_HANDLER_SUPER (fh));
672
673 if (file->linear == LS_LINEAR_OPEN)
674 sub->linear_close (me, fh);
675 if (sub->fh_close != NULL)
676 res = sub->fh_close (me, fh);
677 if ((me->flags & VFSF_USETMP) != 0 && file->changed && sub->file_store != NULL)
678 {
679 char *s;
680
681 s = vfs_s_fullpath (me, file->ino);
682
683 if (s == NULL)
684 res = -1;
685 else
686 {
687 res = sub->file_store (me, fh, s, file->ino->localname);
688 g_free (s);
689 }
690 vfs_s_invalidate (me, super);
691 }
692
693 if (file->handle != -1)
694 {
695 close (file->handle);
696 file->handle = -1;
697 }
698
699 vfs_s_free_inode (me, file->ino);
700 vfs_s_free_fh (sub, fh);
701
702 return res;
703 }
704
705
706
707 static void
708 vfs_s_print_stats (const char *fs_name, const char *action,
709 const char *file_name, off_t have, off_t need)
710 {
711 if (need != 0)
712 vfs_print_message (_("%s: %s: %s %3d%% (%lld) bytes transferred"), fs_name, action,
713 file_name, (int) ((double) have * 100 / need), (long long) have);
714 else
715 vfs_print_message (_("%s: %s: %s %lld bytes transferred"), fs_name, action, file_name,
716 (long long) have);
717 }
718
719
720
721
722 static void
723 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
724 {
725 GList *iter;
726
727 for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
728 {
729 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
730 char *name;
731
732 name = g_strconcat (super->name, PATH_SEP_STR, me->prefix, VFS_PATH_URL_DELIMITER,
733 (char *) NULL);
734 func (name);
735 g_free (name);
736 }
737 }
738
739
740
741 static int
742 vfs_s_ferrno (struct vfs_class *me)
743 {
744 return me->verrno;
745 }
746
747
748
749
750
751
752
753 static vfs_path_t *
754 vfs_s_getlocalcopy (const vfs_path_t * vpath)
755 {
756 vfs_file_handler_t *fh;
757 vfs_path_t *local = NULL;
758
759 if (vpath == NULL)
760 return NULL;
761
762 fh = vfs_s_open (vpath, O_RDONLY, 0);
763
764 if (fh != NULL)
765 {
766 const struct vfs_class *me;
767
768 me = vfs_path_get_last_path_vfs (vpath);
769 if ((me->flags & VFSF_USETMP) != 0 && fh->ino != NULL)
770 local = vfs_path_from_str_flags (fh->ino->localname, VPF_NO_CANON);
771
772 vfs_s_close (fh);
773 }
774
775 return local;
776 }
777
778
779
780
781
782
783
784 static int
785 vfs_s_ungetlocalcopy (const vfs_path_t * vpath, const vfs_path_t * local, gboolean has_changed)
786 {
787 (void) vpath;
788 (void) local;
789 (void) has_changed;
790 return 0;
791 }
792
793
794
795 static int
796 vfs_s_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
797 {
798 struct vfs_class *me;
799
800 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
801
802 switch (ctlop)
803 {
804 case VFS_SETCTL_STALE_DATA:
805 {
806 struct vfs_s_inode *ino;
807
808 ino = vfs_s_inode_from_path (vpath, 0);
809 if (ino == NULL)
810 return 0;
811 if (arg != NULL)
812 ino->super->want_stale = TRUE;
813 else
814 {
815 ino->super->want_stale = FALSE;
816 vfs_s_invalidate (me, ino->super);
817 }
818 return 1;
819 }
820 case VFS_SETCTL_LOGFILE:
821 me->logfile = fopen ((char *) arg, "w");
822 return 1;
823 case VFS_SETCTL_FLUSH:
824 me->flush = TRUE;
825 return 1;
826 default:
827 return 0;
828 }
829 }
830
831
832
833
834 static vfsid
835 vfs_s_getid (const vfs_path_t * vpath)
836 {
837 struct vfs_s_super *archive = NULL;
838 const char *p;
839
840 p = vfs_s_get_path (vpath, &archive, FL_NO_OPEN);
841 if (p == NULL)
842 return NULL;
843
844 return (vfsid) archive;
845 }
846
847
848
849 static gboolean
850 vfs_s_nothingisopen (vfsid id)
851 {
852 return (VFS_SUPER (id)->fd_usage <= 0);
853 }
854
855
856
857 static void
858 vfs_s_free (vfsid id)
859 {
860 vfs_s_free_super (VFS_SUPER (id)->me, VFS_SUPER (id));
861 }
862
863
864
865 static gboolean
866 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
867 {
868 gint64 tim;
869
870 if (me->flush)
871 {
872 me->flush = FALSE;
873 return 0;
874 }
875
876 tim = g_get_monotonic_time ();
877
878 return (tim < ino->timestamp);
879 }
880
881
882
883
884
885 struct vfs_s_inode *
886 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
887 {
888 struct vfs_s_inode *ino;
889
890 ino = g_try_new0 (struct vfs_s_inode, 1);
891 if (ino == NULL)
892 return NULL;
893
894 if (initstat != NULL)
895 ino->st = *initstat;
896 ino->super = super;
897 ino->subdir = g_queue_new ();
898 ino->st.st_nlink = 0;
899 ino->st.st_ino = VFS_SUBCLASS (me)->inode_counter++;
900 ino->st.st_dev = VFS_SUBCLASS (me)->rdev;
901
902 super->ino_usage++;
903
904 CALL (init_inode) (me, ino);
905
906 return ino;
907 }
908
909
910
911 void
912 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
913 {
914 if (ino == NULL)
915 vfs_die ("Don't pass NULL to me");
916
917
918 if (ino->st.st_nlink > 1)
919 {
920 ino->st.st_nlink--;
921 return;
922 }
923
924 while (g_queue_get_length (ino->subdir) != 0)
925 {
926 struct vfs_s_entry *entry;
927
928 entry = VFS_ENTRY (g_queue_peek_head (ino->subdir));
929 vfs_s_free_entry (me, entry);
930 }
931
932 g_queue_free (ino->subdir);
933 ino->subdir = NULL;
934
935 CALL (free_inode) (me, ino);
936 g_free (ino->linkname);
937 if ((me->flags & VFSF_USETMP) != 0 && ino->localname != NULL)
938 {
939 unlink (ino->localname);
940 g_free (ino->localname);
941 }
942 ino->super->ino_usage--;
943 g_free (ino);
944 }
945
946
947
948 struct vfs_s_entry *
949 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
950 {
951 struct vfs_s_entry *entry;
952
953 entry = g_new0 (struct vfs_s_entry, 1);
954
955 entry->name = g_strdup (name);
956 entry->ino = inode;
957 entry->ino->ent = entry;
958 CALL (init_entry) (me, entry);
959
960 return entry;
961 }
962
963
964
965 void
966 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
967 {
968 if (ent->dir != NULL)
969 g_queue_remove (ent->dir->subdir, ent);
970
971 MC_PTR_FREE (ent->name);
972
973 if (ent->ino != NULL)
974 {
975 ent->ino->ent = NULL;
976 vfs_s_free_inode (me, ent->ino);
977 }
978
979 g_free (ent);
980 }
981
982
983
984 void
985 vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
986 {
987 (void) me;
988
989 ent->dir = dir;
990
991 ent->ino->st.st_nlink++;
992 g_queue_push_tail (dir->subdir, ent);
993 }
994
995
996
997 int
998 vfs_s_entry_compare (const void *a, const void *b)
999 {
1000 const struct vfs_s_entry *e = (const struct vfs_s_entry *) a;
1001 const char *name = (const char *) b;
1002
1003 return strcmp (e->name, name);
1004 }
1005
1006
1007
1008 struct stat *
1009 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
1010 {
1011 static struct stat st;
1012 mode_t myumask;
1013
1014 (void) me;
1015
1016 myumask = umask (022);
1017 umask (myumask);
1018 mode &= ~myumask;
1019
1020 st.st_mode = mode;
1021 st.st_ino = 0;
1022 st.st_dev = 0;
1023 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1024 st.st_rdev = 0;
1025 #endif
1026 st.st_uid = getuid ();
1027 st.st_gid = getgid ();
1028 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1029 st.st_blksize = 512;
1030 #endif
1031 st.st_size = 0;
1032
1033 st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
1034 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1035 st.st_atim.tv_nsec = st.st_mtim.tv_nsec = st.st_ctim.tv_nsec = 0;
1036 #endif
1037
1038 vfs_adjust_stat (&st);
1039
1040 return &st;
1041 }
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051 void
1052 vfs_adjust_stat (struct stat *s)
1053 {
1054 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
1055 if (s->st_size == 0)
1056 s->st_blocks = 0;
1057 else
1058 {
1059 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1060 blkcnt_t ioblocks;
1061 blksize_t ioblock_size;
1062
1063
1064 ioblocks = 1 + (s->st_size - 1) / s->st_blksize;
1065
1066 ioblock_size = 1 + (s->st_blksize - 1) / 512;
1067
1068 s->st_blocks = ioblocks * ioblock_size;
1069 #else
1070
1071 s->st_blocks = 1 + (s->st_size - 1) / 512;
1072 #endif
1073 }
1074 #endif
1075 }
1076
1077
1078
1079 struct vfs_s_entry *
1080 vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent,
1081 mode_t mode)
1082 {
1083 struct vfs_s_inode *inode;
1084 struct stat *st;
1085
1086 st = vfs_s_default_stat (me, mode);
1087 inode = vfs_s_new_inode (me, parent->super, st);
1088
1089 return vfs_s_new_entry (me, name, inode);
1090 }
1091
1092
1093
1094 struct vfs_s_inode *
1095 vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
1096 const char *path, int follow, int flags)
1097 {
1098 struct vfs_s_entry *ent;
1099
1100 if (((me->flags & VFSF_REMOTE) == 0) && (*path == '\0'))
1101 return super->root;
1102
1103 ent = VFS_SUBCLASS (me)->find_entry (me, super->root, path, follow, flags);
1104 return (ent != NULL ? ent->ino : NULL);
1105 }
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 struct vfs_s_super *
1118 vfs_get_super_by_vpath (const vfs_path_t * vpath)
1119 {
1120 GList *iter;
1121 void *cookie = NULL;
1122 const vfs_path_element_t *path_element;
1123 struct vfs_s_subclass *subclass;
1124 struct vfs_s_super *super = NULL;
1125 vfs_path_t *vpath_archive;
1126
1127 path_element = vfs_path_get_by_index (vpath, -1);
1128 subclass = VFS_SUBCLASS (path_element->class);
1129
1130 vpath_archive = vfs_path_clone (vpath);
1131 vfs_path_remove_element_by_index (vpath_archive, -1);
1132
1133 if (subclass->archive_check != NULL)
1134 {
1135 cookie = subclass->archive_check (vpath_archive);
1136 if (cookie == NULL)
1137 goto ret;
1138 }
1139
1140 if (subclass->archive_same == NULL)
1141 goto ret;
1142
1143 for (iter = subclass->supers; iter != NULL; iter = g_list_next (iter))
1144 {
1145 int i;
1146
1147 super = VFS_SUPER (iter->data);
1148
1149
1150 i = subclass->archive_same (path_element, super, vpath_archive, cookie);
1151 if (i == 1)
1152 goto ret;
1153 if (i != 0)
1154 break;
1155
1156 super = NULL;
1157 }
1158
1159 ret:
1160 vfs_path_free (vpath_archive, TRUE);
1161 return super;
1162 }
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174 const char *
1175 vfs_s_get_path (const vfs_path_t * vpath, struct vfs_s_super **archive, int flags)
1176 {
1177 const char *retval = "";
1178 int result = -1;
1179 struct vfs_s_super *super;
1180 const vfs_path_element_t *path_element;
1181 struct vfs_s_subclass *subclass;
1182
1183 path_element = vfs_path_get_by_index (vpath, -1);
1184
1185 if (path_element->path != NULL)
1186 retval = path_element->path;
1187
1188 super = vfs_get_super_by_vpath (vpath);
1189 if (super != NULL)
1190 goto return_success;
1191
1192 if ((flags & FL_NO_OPEN) != 0)
1193 {
1194 path_element->class->verrno = EIO;
1195 return NULL;
1196 }
1197
1198 subclass = VFS_SUBCLASS (path_element->class);
1199
1200 super = subclass->new_archive != NULL ?
1201 subclass->new_archive (path_element->class) : vfs_s_new_super (path_element->class);
1202
1203 if (subclass->open_archive != NULL)
1204 {
1205 vfs_path_t *vpath_archive;
1206
1207 vpath_archive = vfs_path_clone (vpath);
1208 vfs_path_remove_element_by_index (vpath_archive, -1);
1209
1210 result = subclass->open_archive (super, vpath_archive, path_element);
1211 vfs_path_free (vpath_archive, TRUE);
1212 }
1213 if (result == -1)
1214 {
1215 vfs_s_free_super (path_element->class, super);
1216 path_element->class->verrno = EIO;
1217 return NULL;
1218 }
1219 if (super->name == NULL)
1220 vfs_die ("You have to fill name\n");
1221 if (super->root == NULL)
1222 vfs_die ("You have to fill root inode\n");
1223
1224 vfs_s_insert_super (path_element->class, super);
1225 vfs_stamp_create (path_element->class, super);
1226
1227 return_success:
1228 *archive = super;
1229 return retval;
1230 }
1231
1232
1233
1234 void
1235 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
1236 {
1237 if (!super->want_stale)
1238 {
1239 vfs_s_free_inode (me, super->root);
1240 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
1241 }
1242 }
1243
1244
1245
1246 char *
1247 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
1248 {
1249 if (ino->ent == NULL)
1250 ERRNOR (EAGAIN, NULL);
1251
1252 if ((me->flags & VFSF_USETMP) == 0)
1253 {
1254
1255 char *path;
1256
1257 path = g_strdup (ino->ent->name);
1258
1259 while (TRUE)
1260 {
1261 char *newpath;
1262
1263 ino = ino->ent->dir;
1264 if (ino == ino->super->root)
1265 break;
1266
1267 newpath = g_strconcat (ino->ent->name, PATH_SEP_STR, path, (char *) NULL);
1268 g_free (path);
1269 path = newpath;
1270 }
1271 return path;
1272 }
1273
1274
1275 if (ino->ent->dir == NULL || ino->ent->dir->ent == NULL)
1276 return g_strdup (ino->ent->name);
1277
1278 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, ino->ent->name, (char *) NULL);
1279 }
1280
1281
1282
1283 void
1284 vfs_s_init_fh (vfs_file_handler_t * fh, struct vfs_s_inode *ino, gboolean changed)
1285 {
1286 fh->ino = ino;
1287 fh->handle = -1;
1288 fh->changed = changed;
1289 fh->linear = LS_NOT_LINEAR;
1290 }
1291
1292
1293
1294
1295 void *
1296 vfs_s_open (const vfs_path_t * vpath, int flags, mode_t mode)
1297 {
1298 gboolean was_changed = FALSE;
1299 vfs_file_handler_t *fh;
1300 struct vfs_s_super *super;
1301 const char *q;
1302 struct vfs_s_inode *ino;
1303 struct vfs_class *me;
1304 struct vfs_s_subclass *s;
1305
1306 q = vfs_s_get_path (vpath, &super, 0);
1307 if (q == NULL)
1308 return NULL;
1309
1310 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
1311
1312 ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
1313 if (ino != NULL && (flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
1314 {
1315 me->verrno = EEXIST;
1316 return NULL;
1317 }
1318
1319 s = VFS_SUBCLASS (me);
1320
1321 if (ino == NULL)
1322 {
1323 char *name;
1324 struct vfs_s_entry *ent;
1325 struct vfs_s_inode *dir;
1326
1327
1328 if ((flags & O_CREAT) == 0 || me->write == NULL)
1329 return NULL;
1330
1331 name = g_path_get_dirname (q);
1332 dir = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_DIR);
1333 g_free (name);
1334 if (dir == NULL)
1335 return NULL;
1336
1337 name = g_path_get_basename (q);
1338 ent = vfs_s_generate_entry (me, name, dir, 0755);
1339 ino = ent->ino;
1340 vfs_s_insert_entry (me, dir, ent);
1341 if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0)
1342 {
1343 int tmp_handle;
1344 vfs_path_t *tmp_vpath;
1345
1346 tmp_handle = vfs_mkstemps (&tmp_vpath, me->name, name);
1347 ino->localname = vfs_path_free (tmp_vpath, FALSE);
1348 if (tmp_handle == -1)
1349 {
1350 g_free (name);
1351 return NULL;
1352 }
1353
1354 close (tmp_handle);
1355 }
1356
1357 g_free (name);
1358 was_changed = TRUE;
1359 }
1360
1361 if (S_ISDIR (ino->st.st_mode))
1362 {
1363 me->verrno = EISDIR;
1364 return NULL;
1365 }
1366
1367 fh = s->fh_new != NULL ? s->fh_new (ino, was_changed) : vfs_s_new_fh (ino, was_changed);
1368
1369 if (IS_LINEAR (flags))
1370 {
1371 if (s->linear_start != NULL)
1372 {
1373 vfs_print_message ("%s", _("Starting linear transfer..."));
1374 fh->linear = LS_LINEAR_PREOPEN;
1375 }
1376 }
1377 else
1378 {
1379 if (s->fh_open != NULL && s->fh_open (me, fh, flags, mode) != 0)
1380 {
1381 vfs_s_free_fh (s, fh);
1382 return NULL;
1383 }
1384 }
1385
1386 if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0 && fh->ino->localname != NULL)
1387 {
1388 fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
1389 if (fh->handle == -1)
1390 {
1391 vfs_s_free_fh (s, fh);
1392 me->verrno = errno;
1393 return NULL;
1394 }
1395 }
1396
1397
1398 vfs_rmstamp (me, (vfsid) super);
1399 super->fd_usage++;
1400 fh->ino->st.st_nlink++;
1401 return fh;
1402 }
1403
1404
1405
1406 int
1407 vfs_s_stat (const vfs_path_t * vpath, struct stat *buf)
1408 {
1409 return vfs_s_internal_stat (vpath, buf, FL_FOLLOW);
1410 }
1411
1412
1413
1414 int
1415 vfs_s_lstat (const vfs_path_t * vpath, struct stat *buf)
1416 {
1417 return vfs_s_internal_stat (vpath, buf, FL_NONE);
1418 }
1419
1420
1421
1422 int
1423 vfs_s_fstat (void *fh, struct stat *buf)
1424 {
1425 *buf = VFS_FILE_HANDLER (fh)->ino->st;
1426 return 0;
1427 }
1428
1429
1430
1431 int
1432 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
1433 {
1434
1435 off_t total = 0;
1436 char buffer[BUF_8K];
1437 int handle;
1438 ssize_t n;
1439 off_t stat_size = ino->st.st_size;
1440 vfs_file_handler_t *fh = NULL;
1441 vfs_path_t *tmp_vpath;
1442 struct vfs_s_subclass *s = VFS_SUBCLASS (me);
1443
1444 if ((me->flags & VFSF_USETMP) == 0)
1445 return (-1);
1446
1447 handle = vfs_mkstemps (&tmp_vpath, me->name, ino->ent->name);
1448 ino->localname = vfs_path_free (tmp_vpath, FALSE);
1449 if (handle == -1)
1450 {
1451 me->verrno = errno;
1452 goto error_4;
1453 }
1454
1455 fh = s->fh_new != NULL ? s->fh_new (ino, FALSE) : vfs_s_new_fh (ino, FALSE);
1456
1457 if (s->linear_start (me, fh, 0) == 0)
1458 goto error_3;
1459
1460
1461 tty_got_interrupt ();
1462 tty_enable_interrupt_key ();
1463
1464 while ((n = s->linear_read (me, fh, buffer, sizeof (buffer))) != 0)
1465 {
1466 int t;
1467
1468 if (n < 0)
1469 goto error_1;
1470
1471 total += n;
1472 vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name, total, stat_size);
1473
1474 if (tty_got_interrupt ())
1475 goto error_1;
1476
1477 t = write (handle, buffer, n);
1478 if (t != n)
1479 {
1480 if (t == -1)
1481 me->verrno = errno;
1482 goto error_1;
1483 }
1484 }
1485 s->linear_close (me, fh);
1486 close (handle);
1487
1488 tty_disable_interrupt_key ();
1489 vfs_s_free_fh (s, fh);
1490 return 0;
1491
1492 error_1:
1493 s->linear_close (me, fh);
1494 error_3:
1495 tty_disable_interrupt_key ();
1496 close (handle);
1497 unlink (ino->localname);
1498 error_4:
1499 MC_PTR_FREE (ino->localname);
1500 if (fh != NULL)
1501 vfs_s_free_fh (s, fh);
1502 return (-1);
1503 }
1504
1505
1506
1507
1508
1509 void
1510 vfs_init_class (struct vfs_class *vclass, const char *name, vfs_flags_t flags, const char *prefix)
1511 {
1512 memset (vclass, 0, sizeof (struct vfs_class));
1513
1514 vclass->name = name;
1515 vclass->flags = flags;
1516 vclass->prefix = prefix;
1517
1518 vclass->fill_names = vfs_s_fill_names;
1519 vclass->open = vfs_s_open;
1520 vclass->close = vfs_s_close;
1521 vclass->read = vfs_s_read;
1522 if ((vclass->flags & VFSF_READONLY) == 0)
1523 vclass->write = vfs_s_write;
1524 vclass->opendir = vfs_s_opendir;
1525 vclass->readdir = vfs_s_readdir;
1526 vclass->closedir = vfs_s_closedir;
1527 vclass->stat = vfs_s_stat;
1528 vclass->lstat = vfs_s_lstat;
1529 vclass->fstat = vfs_s_fstat;
1530 vclass->readlink = vfs_s_readlink;
1531 vclass->chdir = vfs_s_chdir;
1532 vclass->ferrno = vfs_s_ferrno;
1533 vclass->lseek = vfs_s_lseek;
1534 vclass->getid = vfs_s_getid;
1535 vclass->nothingisopen = vfs_s_nothingisopen;
1536 vclass->free = vfs_s_free;
1537 vclass->setctl = vfs_s_setctl;
1538 if ((vclass->flags & VFSF_USETMP) != 0)
1539 {
1540 vclass->getlocalcopy = vfs_s_getlocalcopy;
1541 vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1542 }
1543 }
1544
1545
1546
1547 void
1548 vfs_init_subclass (struct vfs_s_subclass *sub, const char *name, vfs_flags_t flags,
1549 const char *prefix)
1550 {
1551 struct vfs_class *vclass = VFS_CLASS (sub);
1552 size_t len;
1553 char *start;
1554
1555 vfs_init_class (vclass, name, flags, prefix);
1556
1557 len = sizeof (struct vfs_s_subclass) - sizeof (struct vfs_class);
1558 start = (char *) sub + sizeof (struct vfs_class);
1559 memset (start, 0, len);
1560
1561 if ((vclass->flags & VFSF_USETMP) != 0)
1562 sub->find_entry = vfs_s_find_entry_linear;
1563 else if ((vclass->flags & VFSF_REMOTE) != 0)
1564 sub->find_entry = vfs_s_find_entry_linear;
1565 else
1566 sub->find_entry = vfs_s_find_entry_tree;
1567 sub->dir_uptodate = vfs_s_dir_uptodate;
1568 }
1569
1570
1571
1572
1573 vfsid
1574 vfs_getid (const vfs_path_t * vpath)
1575 {
1576 const struct vfs_class *me;
1577
1578 me = vfs_path_get_last_path_vfs (vpath);
1579 if (me == NULL || me->getid == NULL)
1580 return NULL;
1581
1582 return me->getid (vpath);
1583 }
1584
1585
1586
1587
1588 #ifdef ENABLE_VFS_NET
1589 int
1590 vfs_s_select_on_two (int fd1, int fd2)
1591 {
1592 fd_set set;
1593 struct timeval time_out;
1594 int v;
1595 int maxfd = MAX (fd1, fd2) + 1;
1596
1597 time_out.tv_sec = 1;
1598 time_out.tv_usec = 0;
1599 FD_ZERO (&set);
1600 FD_SET (fd1, &set);
1601 FD_SET (fd2, &set);
1602
1603 v = select (maxfd, &set, 0, 0, &time_out);
1604 if (v <= 0)
1605 return v;
1606 if (FD_ISSET (fd1, &set))
1607 return 1;
1608 if (FD_ISSET (fd2, &set))
1609 return 2;
1610 return (-1);
1611 }
1612
1613
1614
1615 int
1616 vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
1617 {
1618 FILE *logfile = me->logfile;
1619 int i;
1620 char c;
1621
1622 for (i = 0; i < buf_len - 1; i++, buf++)
1623 {
1624 if (read (sock, buf, sizeof (char)) <= 0)
1625 return 0;
1626
1627 if (logfile != NULL)
1628 {
1629 size_t ret1;
1630 int ret2;
1631
1632 ret1 = fwrite (buf, 1, 1, logfile);
1633 ret2 = fflush (logfile);
1634 (void) ret1;
1635 (void) ret2;
1636 }
1637
1638 if (*buf == term)
1639 {
1640 *buf = '\0';
1641 return 1;
1642 }
1643 }
1644
1645
1646 *buf = '\0';
1647 while (read (sock, &c, sizeof (c)) > 0)
1648 {
1649 if (logfile != NULL)
1650 {
1651 size_t ret1;
1652 int ret2;
1653
1654 ret1 = fwrite (&c, 1, 1, logfile);
1655 ret2 = fflush (logfile);
1656 (void) ret1;
1657 (void) ret2;
1658 }
1659 if (c == '\n')
1660 return 1;
1661 }
1662 return 0;
1663 }
1664
1665
1666
1667 int
1668 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
1669 {
1670 int i;
1671 int res = 0;
1672
1673 (void) me;
1674
1675 tty_enable_interrupt_key ();
1676
1677 for (i = 0; i < size - 1; i++)
1678 {
1679 ssize_t n;
1680
1681 n = read (fd, &buffer[i], 1);
1682 if (n == -1 && errno == EINTR)
1683 {
1684 buffer[i] = '\0';
1685 res = EINTR;
1686 goto ret;
1687 }
1688 if (n == 0)
1689 {
1690 buffer[i] = '\0';
1691 goto ret;
1692 }
1693 if (buffer[i] == '\n')
1694 {
1695 buffer[i] = '\0';
1696 res = 1;
1697 goto ret;
1698 }
1699 }
1700
1701 buffer[size - 1] = '\0';
1702
1703 ret:
1704 tty_disable_interrupt_key ();
1705
1706 return res;
1707 }
1708 #endif
1709
1710
1711
1712
1713
1714
1715 void
1716 vfs_s_normalize_filename_leading_spaces (struct vfs_s_inode *root_inode, size_t final_num_spaces)
1717 {
1718 GList *iter;
1719
1720 for (iter = g_queue_peek_head_link (root_inode->subdir); iter != NULL;
1721 iter = g_list_next (iter))
1722 {
1723 struct vfs_s_entry *entry = VFS_ENTRY (iter->data);
1724
1725 if ((size_t) entry->leading_spaces > final_num_spaces)
1726 {
1727 char *source_name, *spacer;
1728
1729 source_name = entry->name;
1730 spacer = g_strnfill ((size_t) entry->leading_spaces - final_num_spaces, ' ');
1731 entry->name = g_strconcat (spacer, source_name, (char *) NULL);
1732 g_free (spacer);
1733 g_free (source_name);
1734 }
1735
1736 entry->leading_spaces = -1;
1737 }
1738 }
1739
1740