Ticket #4536: skins: add root variant of julia256 skin.
[midnight-commander.git] / lib / vfs / direntry.c
blob5f9a8efbf109c19b40b6a8c9193c17efd0aaea5e
1 /*
2 Directory cache support
4 Copyright (C) 1998-2024
5 Free Software Foundation, Inc.
7 Written by:
8 Pavel Machek <pavel@ucw.cz>, 1998
9 Slava Zanko <slavazanko@gmail.com>, 2010-2013
10 Andrew Borodin <aborodin@vmail.ru> 2010-2022
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 \warning Paths here do _not_ begin with '/', so root directory of
28 archive/site is simply "".
31 /** \file
32 * \brief Source: directory cache support
34 * So that you do not have copy of this in each and every filesystem.
36 * Very loosely based on tar.c from midnight and archives.[ch] from
37 * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
39 * Unfortunately, I was unable to keep all filesystems
40 * uniform. tar-like filesystems use tree structure where each
41 * directory has pointers to its subdirectories. We can do this
42 * because we have full information about our archive.
44 * At ftp-like filesystems, situation is a little bit different. When
45 * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
46 * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
47 * listed. That means that we do not have complete information, and if
48 * /usr is symlink to /4, we will not know. Also we have to time out
49 * entries and things would get messy with tree-like approach. So we
50 * do different trick: root directory is completely special and
51 * completely fake, it contains entries such as 'usr', 'usr/src', ...,
52 * and we'll try to use custom find_entry function.
54 * \author Pavel Machek <pavel@ucw.cz>
55 * \date 1998
59 #include <config.h>
61 #include <errno.h>
62 #include <inttypes.h> /* uintmax_t */
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>
70 #include "lib/global.h"
72 #include "lib/tty/tty.h" /* enable/disable interrupt key */
73 #include "lib/util.h" /* canonicalize_pathname_custom() */
74 #if 0
75 #include "lib/widget.h" /* message() */
76 #endif
78 #include "vfs.h"
79 #include "utilvfs.h"
80 #include "xdirentry.h"
81 #include "gc.h" /* vfs_rmstamp */
83 /*** global variables ****************************************************************************/
85 /*** file scope macro definitions ****************************************************************/
87 #define CALL(x) \
88 if (VFS_SUBCLASS (me)->x != NULL) \
89 VFS_SUBCLASS (me)->x
91 /*** file scope type declarations ****************************************************************/
93 struct dirhandle
95 GList *cur;
96 struct vfs_s_inode *dir;
99 /*** file scope variables ************************************************************************/
101 /*** forward declarations (file scope functions) *************************************************/
103 /* --------------------------------------------------------------------------------------------- */
104 /*** file scope functions ************************************************************************/
105 /* --------------------------------------------------------------------------------------------- */
107 /* We were asked to create entries automagically */
109 static struct vfs_s_entry *
110 vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
112 struct vfs_s_entry *res;
113 char *sep;
115 sep = strchr (path, PATH_SEP);
116 if (sep != NULL)
117 *sep = '\0';
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);
122 if (sep != NULL)
123 *sep = PATH_SEP;
125 return res;
128 /* --------------------------------------------------------------------------------------------- */
129 /* If the entry is a symlink, find the entry for its target */
131 static struct vfs_s_entry *
132 vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry, int follow)
134 char *linkname;
135 char *fullname = NULL;
136 struct vfs_s_entry *target;
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;
147 linkname = entry->ino->linkname;
148 if (linkname == NULL)
149 ERRNOR (EFAULT, NULL);
151 /* make full path from relative */
152 if (!IS_PATH_SEP (*linkname))
154 char *fullpath;
156 fullpath = vfs_s_fullpath (me, entry->dir);
157 if (fullpath != NULL)
159 fullname = g_strconcat (fullpath, PATH_SEP_STR, linkname, (char *) NULL);
160 linkname = fullname;
161 g_free (fullpath);
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;
171 /* --------------------------------------------------------------------------------------------- */
173 * Follow > 0: follow links, serves as loop protect,
174 * == -1: do not follow links
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)
181 size_t pseg;
182 struct vfs_s_entry *ent = NULL;
183 char *const pathref = g_strdup (a_path);
184 char *path = pathref;
186 /* canonicalize as well, but don't remove '../' from path */
187 canonicalize_pathname_custom (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
189 while (root != NULL)
191 GList *iter;
193 while (IS_PATH_SEP (*path)) /* Strip leading '/' */
194 path++;
196 if (path[0] == '\0')
198 g_free (pathref);
199 return ent;
202 for (pseg = 0; path[pseg] != '\0' && !IS_PATH_SEP (path[pseg]); pseg++)
205 for (iter = g_queue_peek_head_link (root->subdir); iter != NULL; iter = g_list_next (iter))
207 ent = VFS_ENTRY (iter->data);
208 if (strlen (ent->name) == pseg && strncmp (ent->name, path, pseg) == 0)
209 /* FOUND! */
210 break;
213 ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
215 if (ent == NULL && (flags & (FL_MKFILE | FL_MKDIR)) != 0)
216 ent = vfs_s_automake (me, root, path, flags);
217 if (ent == NULL)
219 me->verrno = ENOENT;
220 goto cleanup;
223 path += pseg;
224 /* here we must follow leading directories always;
225 only the actual file is optional */
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;
232 cleanup:
233 g_free (pathref);
234 return NULL;
237 /* --------------------------------------------------------------------------------------------- */
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)
243 struct vfs_s_entry *ent = NULL;
244 char *const path = g_strdup (a_path);
245 GList *iter;
247 if (root->super->root != root)
248 vfs_die ("We have to use _real_ root. Always. Sorry.");
250 /* canonicalize as well, but don't remove '../' from path */
251 canonicalize_pathname_custom (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
253 if ((flags & FL_DIR) == 0)
255 char *dirname, *name;
256 struct vfs_s_inode *ino;
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;
268 iter = g_queue_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
269 ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
271 if (ent != NULL && !VFS_SUBCLASS (me)->dir_uptodate (me, ent->ino))
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;
280 if (ent == NULL)
282 struct vfs_s_inode *ino;
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)
288 vfs_s_free_entry (me, ent);
289 g_free (path);
290 return NULL;
293 vfs_s_insert_entry (me, root, ent);
295 iter = g_queue_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
296 ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
298 if (ent == NULL)
299 vfs_die ("find_linear: success but directory is not there\n");
301 #if 0
302 if (vfs_s_resolve_symlink (me, ent, follow) == NULL)
304 g_free (path);
305 return NULL;
307 #endif
308 g_free (path);
309 return ent;
312 /* --------------------------------------------------------------------------------------------- */
313 /* Ook, these were functions around directory entries / inodes */
314 /* -------------------------------- superblock games -------------------------- */
316 static struct vfs_s_super *
317 vfs_s_new_super (struct vfs_class *me)
319 struct vfs_s_super *super;
321 super = g_new0 (struct vfs_s_super, 1);
322 super->me = me;
323 return super;
326 /* --------------------------------------------------------------------------------------------- */
328 static inline void
329 vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
331 VFS_SUBCLASS (me)->supers = g_list_prepend (VFS_SUBCLASS (me)->supers, super);
334 /* --------------------------------------------------------------------------------------------- */
336 static void
337 vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
339 if (super->root != NULL)
341 vfs_s_free_inode (me, super->root);
342 super->root = NULL;
345 #if 0
346 /* FIXME: We currently leak small amount of memory, sometimes. Fix it if you can. */
347 if (super->ino_usage != 0)
348 message (D_ERROR, "Direntry warning",
349 "Super ino_usage is %d, memory leak", super->ino_usage);
351 if (super->want_stale)
352 message (D_ERROR, "Direntry warning", "%s", "Super has want_stale set");
353 #endif
355 VFS_SUBCLASS (me)->supers = g_list_remove (VFS_SUBCLASS (me)->supers, super);
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);
365 /* --------------------------------------------------------------------------------------------- */
367 static vfs_file_handler_t *
368 vfs_s_new_fh (struct vfs_s_inode *ino, gboolean changed)
370 vfs_file_handler_t *fh;
372 fh = g_new0 (vfs_file_handler_t, 1);
373 vfs_s_init_fh (fh, ino, changed);
375 return fh;
378 /* --------------------------------------------------------------------------------------------- */
380 static void
381 vfs_s_free_fh (struct vfs_s_subclass *s, vfs_file_handler_t * fh)
383 if (s->fh_free != NULL)
384 s->fh_free (fh);
386 g_free (fh);
389 /* --------------------------------------------------------------------------------------------- */
390 /* Support of archives */
391 /* ------------------------ readdir & friends ----------------------------- */
393 static struct vfs_s_inode *
394 vfs_s_inode_from_path (const vfs_path_t * vpath, int flags)
396 struct vfs_s_super *super;
397 struct vfs_s_inode *ino;
398 const char *q;
399 struct vfs_class *me;
401 q = vfs_s_get_path (vpath, &super, 0);
402 if (q == NULL)
403 return NULL;
405 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
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 /* We are asking about / directory of ftp server: assume it exists */
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;
420 /* --------------------------------------------------------------------------------------------- */
422 static void *
423 vfs_s_opendir (const vfs_path_t * vpath)
425 struct vfs_s_inode *dir;
426 struct dirhandle *info;
427 struct vfs_class *me;
429 dir = vfs_s_inode_from_path (vpath, FL_DIR | FL_FOLLOW);
430 if (dir == NULL)
431 return NULL;
433 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
435 if (!S_ISDIR (dir->st.st_mode))
437 me->verrno = ENOTDIR;
438 return NULL;
441 dir->st.st_nlink++;
442 #if 0
443 if (dir->subdir == NULL) /* This can actually happen if we allow empty directories */
445 me->verrno = EAGAIN;
446 return NULL;
448 #endif
449 info = g_new (struct dirhandle, 1);
450 info->cur = g_queue_peek_head_link (dir->subdir);
451 info->dir = dir;
453 return info;
456 /* --------------------------------------------------------------------------------------------- */
458 static struct vfs_dirent *
459 vfs_s_readdir (void *data)
461 struct vfs_dirent *dir = NULL;
462 struct dirhandle *info = (struct dirhandle *) data;
463 const char *name;
465 if (info->cur == NULL || info->cur->data == NULL)
466 return NULL;
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");
474 info->cur = g_list_next (info->cur);
476 return dir;
479 /* --------------------------------------------------------------------------------------------- */
481 static int
482 vfs_s_closedir (void *data)
484 struct dirhandle *info = (struct dirhandle *) data;
485 struct vfs_s_inode *dir = info->dir;
487 vfs_s_free_inode (dir->super->me, dir);
488 g_free (data);
489 return 0;
492 /* --------------------------------------------------------------------------------------------- */
494 static int
495 vfs_s_chdir (const vfs_path_t * vpath)
497 void *data;
499 data = vfs_s_opendir (vpath);
500 if (data == NULL)
501 return (-1);
502 vfs_s_closedir (data);
503 return 0;
506 /* --------------------------------------------------------------------------------------------- */
507 /* --------------------------- stat and friends ---------------------------- */
509 static int
510 vfs_s_internal_stat (const vfs_path_t * vpath, struct stat *buf, int flag)
512 struct vfs_s_inode *ino;
514 ino = vfs_s_inode_from_path (vpath, flag);
515 if (ino == NULL)
516 return (-1);
517 *buf = ino->st;
518 return 0;
521 /* --------------------------------------------------------------------------------------------- */
523 static int
524 vfs_s_readlink (const vfs_path_t * vpath, char *buf, size_t size)
526 struct vfs_s_inode *ino;
527 size_t len;
528 struct vfs_class *me;
530 ino = vfs_s_inode_from_path (vpath, 0);
531 if (ino == NULL)
532 return (-1);
534 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
536 if (!S_ISLNK (ino->st.st_mode))
538 me->verrno = EINVAL;
539 return (-1);
542 if (ino->linkname == NULL)
544 me->verrno = EFAULT;
545 return (-1);
548 len = strlen (ino->linkname);
549 if (size < len)
550 len = size;
551 /* readlink() does not append a NUL character to buf */
552 memcpy (buf, ino->linkname, len);
553 return len;
556 /* --------------------------------------------------------------------------------------------- */
558 static ssize_t
559 vfs_s_read (void *fh, char *buffer, size_t count)
561 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
562 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
564 if (file->linear == LS_LINEAR_PREOPEN)
566 if (VFS_SUBCLASS (me)->linear_start (me, file, file->pos) == 0)
567 return (-1);
570 if (file->linear == LS_LINEAR_CLOSED)
571 vfs_die ("linear_start() did not set linear_state!");
573 if (file->linear == LS_LINEAR_OPEN)
574 return VFS_SUBCLASS (me)->linear_read (me, file, buffer, count);
576 if (file->handle != -1)
578 ssize_t n;
580 n = read (file->handle, buffer, count);
581 if (n < 0)
582 me->verrno = errno;
583 return n;
585 vfs_die ("vfs_s_read: This should not happen\n");
586 return (-1);
589 /* --------------------------------------------------------------------------------------------- */
591 static ssize_t
592 vfs_s_write (void *fh, const char *buffer, size_t count)
594 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
595 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
597 if (file->linear != LS_NOT_LINEAR)
598 vfs_die ("no writing to linear files, please");
600 file->changed = TRUE;
601 if (file->handle != -1)
603 ssize_t n;
605 n = write (file->handle, buffer, count);
606 if (n < 0)
607 me->verrno = errno;
608 return n;
610 vfs_die ("vfs_s_write: This should not happen\n");
611 return 0;
614 /* --------------------------------------------------------------------------------------------- */
616 static off_t
617 vfs_s_lseek (void *fh, off_t offset, int whence)
619 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
620 off_t size = file->ino->st.st_size;
622 if (file->linear == LS_LINEAR_OPEN)
623 vfs_die ("cannot lseek() after linear_read!");
625 if (file->handle != -1)
626 { /* If we have local file opened, we want to work with it */
627 off_t retval;
629 retval = lseek (file->handle, offset, whence);
630 if (retval == -1)
631 VFS_FILE_HANDLER_SUPER (fh)->me->verrno = errno;
632 return retval;
635 switch (whence)
637 case SEEK_CUR:
638 offset += file->pos;
639 break;
640 case SEEK_END:
641 offset += size;
642 break;
643 default:
644 break;
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;
655 /* --------------------------------------------------------------------------------------------- */
657 static int
658 vfs_s_close (void *fh)
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;
666 if (me == NULL)
667 return (-1);
669 super->fd_usage--;
670 if (super->fd_usage == 0)
671 vfs_stamp_create (me, VFS_FILE_HANDLER_SUPER (fh));
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)
679 char *s;
681 s = vfs_s_fullpath (me, file->ino);
683 if (s == NULL)
684 res = -1;
685 else
687 res = sub->file_store (me, fh, s, file->ino->localname);
688 g_free (s);
690 vfs_s_invalidate (me, super);
693 if (file->handle != -1)
695 close (file->handle);
696 file->handle = -1;
699 vfs_s_free_inode (me, file->ino);
700 vfs_s_free_fh (sub, fh);
702 return res;
705 /* --------------------------------------------------------------------------------------------- */
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)
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);
719 /* --------------------------------------------------------------------------------------------- */
720 /* ------------------------------- mc support ---------------------------- */
722 static void
723 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
725 GList *iter;
727 for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
729 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
730 char *name;
732 name = g_strconcat (super->name, PATH_SEP_STR, me->prefix, VFS_PATH_URL_DELIMITER,
733 /* super->current_dir->name, */ (char *) NULL);
734 func (name);
735 g_free (name);
739 /* --------------------------------------------------------------------------------------------- */
741 static int
742 vfs_s_ferrno (struct vfs_class *me)
744 return me->verrno;
747 /* --------------------------------------------------------------------------------------------- */
749 * Get local copy of the given file. We reuse the existing file cache
750 * for remote filesystems. Archives use standard VFS facilities.
753 static vfs_path_t *
754 vfs_s_getlocalcopy (const vfs_path_t * vpath)
756 vfs_file_handler_t *fh;
757 vfs_path_t *local = NULL;
759 if (vpath == NULL)
760 return NULL;
762 fh = vfs_s_open (vpath, O_RDONLY, 0);
764 if (fh != NULL)
766 const struct vfs_class *me;
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);
772 vfs_s_close (fh);
775 return local;
778 /* --------------------------------------------------------------------------------------------- */
780 * Return the local copy. Since we are using our cache, we do nothing -
781 * the cache will be removed when the archive is closed.
784 static int
785 vfs_s_ungetlocalcopy (const vfs_path_t * vpath, const vfs_path_t * local, gboolean has_changed)
787 (void) vpath;
788 (void) local;
789 (void) has_changed;
790 return 0;
793 /* --------------------------------------------------------------------------------------------- */
795 static int
796 vfs_s_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
798 struct vfs_class *me;
800 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
802 switch (ctlop)
804 case VFS_SETCTL_STALE_DATA:
806 struct vfs_s_inode *ino;
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
815 ino->super->want_stale = FALSE;
816 vfs_s_invalidate (me, ino->super);
818 return 1;
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;
831 /* --------------------------------------------------------------------------------------------- */
832 /* ----------------------------- Stamping support -------------------------- */
834 static vfsid
835 vfs_s_getid (const vfs_path_t * vpath)
837 struct vfs_s_super *archive = NULL;
838 const char *p;
840 p = vfs_s_get_path (vpath, &archive, FL_NO_OPEN);
841 if (p == NULL)
842 return NULL;
844 return (vfsid) archive;
847 /* --------------------------------------------------------------------------------------------- */
849 static gboolean
850 vfs_s_nothingisopen (vfsid id)
852 return (VFS_SUPER (id)->fd_usage <= 0);
855 /* --------------------------------------------------------------------------------------------- */
857 static void
858 vfs_s_free (vfsid id)
860 vfs_s_free_super (VFS_SUPER (id)->me, VFS_SUPER (id));
863 /* --------------------------------------------------------------------------------------------- */
865 static gboolean
866 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
868 gint64 tim;
870 if (me->flush)
872 me->flush = FALSE;
873 return 0;
876 tim = g_get_monotonic_time ();
878 return (tim < ino->timestamp);
881 /* --------------------------------------------------------------------------------------------- */
882 /*** public functions ****************************************************************************/
883 /* --------------------------------------------------------------------------------------------- */
885 struct vfs_s_inode *
886 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
888 struct vfs_s_inode *ino;
890 ino = g_try_new0 (struct vfs_s_inode, 1);
891 if (ino == NULL)
892 return NULL;
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;
902 super->ino_usage++;
904 CALL (init_inode) (me, ino);
906 return ino;
909 /* --------------------------------------------------------------------------------------------- */
911 void
912 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
914 if (ino == NULL)
915 vfs_die ("Don't pass NULL to me");
917 /* ==0 can happen if freshly created entry is deleted */
918 if (ino->st.st_nlink > 1)
920 ino->st.st_nlink--;
921 return;
924 while (g_queue_get_length (ino->subdir) != 0)
926 struct vfs_s_entry *entry;
928 entry = VFS_ENTRY (g_queue_peek_head (ino->subdir));
929 vfs_s_free_entry (me, entry);
932 g_queue_free (ino->subdir);
933 ino->subdir = NULL;
935 CALL (free_inode) (me, ino);
936 g_free (ino->linkname);
937 if ((me->flags & VFSF_USETMP) != 0 && ino->localname != NULL)
939 unlink (ino->localname);
940 g_free (ino->localname);
942 ino->super->ino_usage--;
943 g_free (ino);
946 /* --------------------------------------------------------------------------------------------- */
948 struct vfs_s_entry *
949 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
951 struct vfs_s_entry *entry;
953 entry = g_new0 (struct vfs_s_entry, 1);
955 entry->name = g_strdup (name);
956 entry->ino = inode;
957 entry->ino->ent = entry;
958 CALL (init_entry) (me, entry);
960 return entry;
963 /* --------------------------------------------------------------------------------------------- */
965 void
966 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
968 if (ent->dir != NULL)
969 g_queue_remove (ent->dir->subdir, ent);
971 MC_PTR_FREE (ent->name);
973 if (ent->ino != NULL)
975 ent->ino->ent = NULL;
976 vfs_s_free_inode (me, ent->ino);
979 g_free (ent);
982 /* --------------------------------------------------------------------------------------------- */
984 void
985 vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
987 (void) me;
989 ent->dir = dir;
991 ent->ino->st.st_nlink++;
992 g_queue_push_tail (dir->subdir, ent);
995 /* --------------------------------------------------------------------------------------------- */
998 vfs_s_entry_compare (const void *a, const void *b)
1000 const struct vfs_s_entry *e = (const struct vfs_s_entry *) a;
1001 const char *name = (const char *) b;
1003 return strcmp (e->name, name);
1006 /* --------------------------------------------------------------------------------------------- */
1008 struct stat *
1009 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
1011 static struct stat st;
1012 mode_t myumask;
1014 (void) me;
1016 myumask = umask (022);
1017 umask (myumask);
1018 mode &= ~myumask;
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;
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
1038 vfs_adjust_stat (&st);
1040 return &st;
1043 /* --------------------------------------------------------------------------------------------- */
1045 * Calculate number of st_blocks using st_size and st_blksize.
1046 * In according to stat(2), st_blocks is the size in 512-byte units.
1048 * @param s stat info
1051 void
1052 vfs_adjust_stat (struct stat *s)
1054 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
1055 if (s->st_size == 0)
1056 s->st_blocks = 0;
1057 else
1059 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1060 blkcnt_t ioblocks;
1061 blksize_t ioblock_size;
1063 /* 1. Calculate how many IO blocks are occupied */
1064 ioblocks = 1 + (s->st_size - 1) / s->st_blksize;
1065 /* 2. Calculate size of st_blksize in 512-byte units */
1066 ioblock_size = 1 + (s->st_blksize - 1) / 512;
1067 /* 3. Calculate number of blocks */
1068 s->st_blocks = ioblocks * ioblock_size;
1069 #else
1070 /* Let IO block size is 512 bytes */
1071 s->st_blocks = 1 + (s->st_size - 1) / 512;
1072 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1074 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
1077 /* --------------------------------------------------------------------------------------------- */
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)
1083 struct vfs_s_inode *inode;
1084 struct stat *st;
1086 st = vfs_s_default_stat (me, mode);
1087 inode = vfs_s_new_inode (me, parent->super, st);
1089 return vfs_s_new_entry (me, name, inode);
1092 /* --------------------------------------------------------------------------------------------- */
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)
1098 struct vfs_s_entry *ent;
1100 if (((me->flags & VFSF_REMOTE) == 0) && (*path == '\0'))
1101 return super->root;
1103 ent = VFS_SUBCLASS (me)->find_entry (me, super->root, path, follow, flags);
1104 return (ent != NULL ? ent->ino : NULL);
1107 /* --------------------------------------------------------------------------------------------- */
1108 /* Ook, these were functions around directory entries / inodes */
1109 /* -------------------------------- superblock games -------------------------- */
1111 * get superlock object by vpath
1113 * @param vpath path
1114 * @return superlock object or NULL if not found
1117 struct vfs_s_super *
1118 vfs_get_super_by_vpath (const vfs_path_t * vpath)
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;
1127 path_element = vfs_path_get_by_index (vpath, -1);
1128 subclass = VFS_SUBCLASS (path_element->class);
1130 vpath_archive = vfs_path_clone (vpath);
1131 vfs_path_remove_element_by_index (vpath_archive, -1);
1133 if (subclass->archive_check != NULL)
1135 cookie = subclass->archive_check (vpath_archive);
1136 if (cookie == NULL)
1137 goto ret;
1140 if (subclass->archive_same == NULL)
1141 goto ret;
1143 for (iter = subclass->supers; iter != NULL; iter = g_list_next (iter))
1145 int i;
1147 super = VFS_SUPER (iter->data);
1149 /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1150 i = subclass->archive_same (path_element, super, vpath_archive, cookie);
1151 if (i == 1)
1152 goto ret;
1153 if (i != 0)
1154 break;
1156 super = NULL;
1159 ret:
1160 vfs_path_free (vpath_archive, TRUE);
1161 return super;
1164 /* --------------------------------------------------------------------------------------------- */
1166 * get path from last VFS-element and create corresponding superblock
1168 * @param vpath source path object
1169 * @param archive pointer to object for store newly created superblock
1170 * @param flags flags
1172 * @return path from last VFS-element
1174 const char *
1175 vfs_s_get_path (const vfs_path_t * vpath, struct vfs_s_super **archive, int flags)
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;
1183 path_element = vfs_path_get_by_index (vpath, -1);
1185 if (path_element->path != NULL)
1186 retval = path_element->path;
1188 super = vfs_get_super_by_vpath (vpath);
1189 if (super != NULL)
1190 goto return_success;
1192 if ((flags & FL_NO_OPEN) != 0)
1194 path_element->class->verrno = EIO;
1195 return NULL;
1198 subclass = VFS_SUBCLASS (path_element->class);
1200 super = subclass->new_archive != NULL ?
1201 subclass->new_archive (path_element->class) : vfs_s_new_super (path_element->class);
1203 if (subclass->open_archive != NULL)
1205 vfs_path_t *vpath_archive;
1207 vpath_archive = vfs_path_clone (vpath);
1208 vfs_path_remove_element_by_index (vpath_archive, -1);
1210 result = subclass->open_archive (super, vpath_archive, path_element);
1211 vfs_path_free (vpath_archive, TRUE);
1213 if (result == -1)
1215 vfs_s_free_super (path_element->class, super);
1216 path_element->class->verrno = EIO;
1217 return NULL;
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");
1224 vfs_s_insert_super (path_element->class, super);
1225 vfs_stamp_create (path_element->class, super);
1227 return_success:
1228 *archive = super;
1229 return retval;
1232 /* --------------------------------------------------------------------------------------------- */
1234 void
1235 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
1237 if (!super->want_stale)
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));
1244 /* --------------------------------------------------------------------------------------------- */
1246 char *
1247 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
1249 if (ino->ent == NULL)
1250 ERRNOR (EAGAIN, NULL);
1252 if ((me->flags & VFSF_USETMP) == 0)
1254 /* archives */
1255 char *path;
1257 path = g_strdup (ino->ent->name);
1259 while (TRUE)
1261 char *newpath;
1263 ino = ino->ent->dir;
1264 if (ino == ino->super->root)
1265 break;
1267 newpath = g_strconcat (ino->ent->name, PATH_SEP_STR, path, (char *) NULL);
1268 g_free (path);
1269 path = newpath;
1271 return path;
1274 /* remote systems */
1275 if (ino->ent->dir == NULL || ino->ent->dir->ent == NULL)
1276 return g_strdup (ino->ent->name);
1278 return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, ino->ent->name, (char *) NULL);
1281 /* --------------------------------------------------------------------------------------------- */
1283 void
1284 vfs_s_init_fh (vfs_file_handler_t * fh, struct vfs_s_inode *ino, gboolean changed)
1286 fh->ino = ino;
1287 fh->handle = -1;
1288 fh->changed = changed;
1289 fh->linear = LS_NOT_LINEAR;
1292 /* --------------------------------------------------------------------------------------------- */
1293 /* --------------------------- stat and friends ---------------------------- */
1295 void *
1296 vfs_s_open (const vfs_path_t * vpath, int flags, mode_t mode)
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;
1306 q = vfs_s_get_path (vpath, &super, 0);
1307 if (q == NULL)
1308 return NULL;
1310 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
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))
1315 me->verrno = EEXIST;
1316 return NULL;
1319 s = VFS_SUBCLASS (me);
1321 if (ino == NULL)
1323 char *name;
1324 struct vfs_s_entry *ent;
1325 struct vfs_s_inode *dir;
1327 /* If the filesystem is read-only, disable file creation */
1328 if ((flags & O_CREAT) == 0 || me->write == NULL)
1329 return NULL;
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;
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)
1343 int tmp_handle;
1344 vfs_path_t *tmp_vpath;
1346 tmp_handle = vfs_mkstemps (&tmp_vpath, me->name, name);
1347 ino->localname = vfs_path_free (tmp_vpath, FALSE);
1348 if (tmp_handle == -1)
1350 g_free (name);
1351 return NULL;
1354 close (tmp_handle);
1357 g_free (name);
1358 was_changed = TRUE;
1361 if (S_ISDIR (ino->st.st_mode))
1363 me->verrno = EISDIR;
1364 return NULL;
1367 fh = s->fh_new != NULL ? s->fh_new (ino, was_changed) : vfs_s_new_fh (ino, was_changed);
1369 if (IS_LINEAR (flags))
1371 if (s->linear_start != NULL)
1373 vfs_print_message ("%s", _("Starting linear transfer..."));
1374 fh->linear = LS_LINEAR_PREOPEN;
1377 else
1379 if (s->fh_open != NULL && s->fh_open (me, fh, flags, mode) != 0)
1381 vfs_s_free_fh (s, fh);
1382 return NULL;
1386 if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0 && fh->ino->localname != NULL)
1388 fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
1389 if (fh->handle == -1)
1391 vfs_s_free_fh (s, fh);
1392 me->verrno = errno;
1393 return NULL;
1397 /* i.e. we had no open files and now we have one */
1398 vfs_rmstamp (me, (vfsid) super);
1399 super->fd_usage++;
1400 fh->ino->st.st_nlink++;
1401 return fh;
1404 /* --------------------------------------------------------------------------------------------- */
1407 vfs_s_stat (const vfs_path_t * vpath, struct stat *buf)
1409 return vfs_s_internal_stat (vpath, buf, FL_FOLLOW);
1412 /* --------------------------------------------------------------------------------------------- */
1415 vfs_s_lstat (const vfs_path_t * vpath, struct stat *buf)
1417 return vfs_s_internal_stat (vpath, buf, FL_NONE);
1420 /* --------------------------------------------------------------------------------------------- */
1423 vfs_s_fstat (void *fh, struct stat *buf)
1425 *buf = VFS_FILE_HANDLER (fh)->ino->st;
1426 return 0;
1429 /* --------------------------------------------------------------------------------------------- */
1432 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
1434 /* If you want reget, you'll have to open file with O_LINEAR */
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);
1444 if ((me->flags & VFSF_USETMP) == 0)
1445 return (-1);
1447 handle = vfs_mkstemps (&tmp_vpath, me->name, ino->ent->name);
1448 ino->localname = vfs_path_free (tmp_vpath, FALSE);
1449 if (handle == -1)
1451 me->verrno = errno;
1452 goto error_4;
1455 fh = s->fh_new != NULL ? s->fh_new (ino, FALSE) : vfs_s_new_fh (ino, FALSE);
1457 if (s->linear_start (me, fh, 0) == 0)
1458 goto error_3;
1460 /* Clear the interrupt status */
1461 tty_got_interrupt ();
1462 tty_enable_interrupt_key ();
1464 while ((n = s->linear_read (me, fh, buffer, sizeof (buffer))) != 0)
1466 int t;
1468 if (n < 0)
1469 goto error_1;
1471 total += n;
1472 vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name, total, stat_size);
1474 if (tty_got_interrupt ())
1475 goto error_1;
1477 t = write (handle, buffer, n);
1478 if (t != n)
1480 if (t == -1)
1481 me->verrno = errno;
1482 goto error_1;
1485 s->linear_close (me, fh);
1486 close (handle);
1488 tty_disable_interrupt_key ();
1489 vfs_s_free_fh (s, fh);
1490 return 0;
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);
1505 /* --------------------------------------------------------------------------------------------- */
1506 /* ----------------------------- Stamping support -------------------------- */
1508 /* Initialize one of our subclasses - fill common functions */
1509 void
1510 vfs_init_class (struct vfs_class *vclass, const char *name, vfs_flags_t flags, const char *prefix)
1512 memset (vclass, 0, sizeof (struct vfs_class));
1514 vclass->name = name;
1515 vclass->flags = flags;
1516 vclass->prefix = prefix;
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)
1540 vclass->getlocalcopy = vfs_s_getlocalcopy;
1541 vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1545 /* --------------------------------------------------------------------------------------------- */
1547 void
1548 vfs_init_subclass (struct vfs_s_subclass *sub, const char *name, vfs_flags_t flags,
1549 const char *prefix)
1551 struct vfs_class *vclass = VFS_CLASS (sub);
1552 size_t len;
1553 char *start;
1555 vfs_init_class (vclass, name, flags, prefix);
1557 len = sizeof (struct vfs_s_subclass) - sizeof (struct vfs_class);
1558 start = (char *) sub + sizeof (struct vfs_class);
1559 memset (start, 0, len);
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;
1570 /* --------------------------------------------------------------------------------------------- */
1571 /** Find VFS id for given directory name */
1573 vfsid
1574 vfs_getid (const vfs_path_t * vpath)
1576 const struct vfs_class *me;
1578 me = vfs_path_get_last_path_vfs (vpath);
1579 if (me == NULL || me->getid == NULL)
1580 return NULL;
1582 return me->getid (vpath);
1585 /* --------------------------------------------------------------------------------------------- */
1586 /* ----------- Utility functions for networked filesystems -------------- */
1588 #ifdef ENABLE_VFS_NET
1590 vfs_s_select_on_two (int fd1, int fd2)
1592 fd_set set;
1593 struct timeval time_out;
1594 int v;
1595 int maxfd = MAX (fd1, fd2) + 1;
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);
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);
1613 /* --------------------------------------------------------------------------------------------- */
1616 vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
1618 FILE *logfile = me->logfile;
1619 int i;
1620 char c;
1622 for (i = 0; i < buf_len - 1; i++, buf++)
1624 if (read (sock, buf, sizeof (char)) <= 0)
1625 return 0;
1627 if (logfile != NULL)
1629 size_t ret1;
1630 int ret2;
1632 ret1 = fwrite (buf, 1, 1, logfile);
1633 ret2 = fflush (logfile);
1634 (void) ret1;
1635 (void) ret2;
1638 if (*buf == term)
1640 *buf = '\0';
1641 return 1;
1645 /* Line is too long - terminate buffer and discard the rest of line */
1646 *buf = '\0';
1647 while (read (sock, &c, sizeof (c)) > 0)
1649 if (logfile != NULL)
1651 size_t ret1;
1652 int ret2;
1654 ret1 = fwrite (&c, 1, 1, logfile);
1655 ret2 = fflush (logfile);
1656 (void) ret1;
1657 (void) ret2;
1659 if (c == '\n')
1660 return 1;
1662 return 0;
1665 /* --------------------------------------------------------------------------------------------- */
1668 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
1670 int i;
1671 int res = 0;
1673 (void) me;
1675 tty_enable_interrupt_key ();
1677 for (i = 0; i < size - 1; i++)
1679 ssize_t n;
1681 n = read (fd, &buffer[i], 1);
1682 if (n == -1 && errno == EINTR)
1684 buffer[i] = '\0';
1685 res = EINTR;
1686 goto ret;
1688 if (n == 0)
1690 buffer[i] = '\0';
1691 goto ret;
1693 if (buffer[i] == '\n')
1695 buffer[i] = '\0';
1696 res = 1;
1697 goto ret;
1701 buffer[size - 1] = '\0';
1703 ret:
1704 tty_disable_interrupt_key ();
1706 return res;
1708 #endif /* ENABLE_VFS_NET */
1710 /* --------------------------------------------------------------------------------------------- */
1712 * Normalize filenames start position
1715 void
1716 vfs_s_normalize_filename_leading_spaces (struct vfs_s_inode *root_inode, size_t final_num_spaces)
1718 GList *iter;
1720 for (iter = g_queue_peek_head_link (root_inode->subdir); iter != NULL;
1721 iter = g_list_next (iter))
1723 struct vfs_s_entry *entry = VFS_ENTRY (iter->data);
1725 if ((size_t) entry->leading_spaces > final_num_spaces)
1727 char *source_name, *spacer;
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);
1736 entry->leading_spaces = -1;
1740 /* --------------------------------------------------------------------------------------------- */