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