root/lib/vfs/direntry.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. vfs_s_automake
  2. vfs_s_resolve_symlink
  3. vfs_s_find_entry_tree
  4. vfs_s_find_entry_linear
  5. vfs_s_new_super
  6. vfs_s_insert_super
  7. vfs_s_free_super
  8. vfs_s_new_fh
  9. vfs_s_free_fh
  10. vfs_s_inode_from_path
  11. vfs_s_opendir
  12. vfs_s_readdir
  13. vfs_s_closedir
  14. vfs_s_chdir
  15. vfs_s_internal_stat
  16. vfs_s_readlink
  17. vfs_s_read
  18. vfs_s_write
  19. vfs_s_lseek
  20. vfs_s_close
  21. vfs_s_print_stats
  22. vfs_s_fill_names
  23. vfs_s_ferrno
  24. vfs_s_getlocalcopy
  25. vfs_s_ungetlocalcopy
  26. vfs_s_setctl
  27. vfs_s_getid
  28. vfs_s_nothingisopen
  29. vfs_s_free
  30. vfs_s_dir_uptodate
  31. vfs_s_new_inode
  32. vfs_s_free_inode
  33. vfs_s_new_entry
  34. vfs_s_free_entry
  35. vfs_s_insert_entry
  36. vfs_s_entry_compare
  37. vfs_s_default_stat
  38. vfs_adjust_stat
  39. vfs_s_generate_entry
  40. vfs_s_find_inode
  41. vfs_get_super_by_vpath
  42. vfs_s_get_path
  43. vfs_s_invalidate
  44. vfs_s_fullpath
  45. vfs_s_init_fh
  46. vfs_s_open
  47. vfs_s_stat
  48. vfs_s_lstat
  49. vfs_s_fstat
  50. vfs_s_retrieve_file
  51. vfs_init_class
  52. vfs_init_subclass
  53. vfs_getid
  54. vfs_s_select_on_two
  55. vfs_s_get_line
  56. vfs_s_get_line_interruptible
  57. vfs_s_normalize_filename_leading_spaces

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

/* [previous][next][first][last][top][bottom][index][help]  */