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-2025
   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 <https://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, const char *a_path,
     /* [previous][next][first][last][top][bottom][index][help]  */
 179                        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 =
 227             vfs_s_resolve_symlink (me, ent, 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, const char *a_path,
     /* [previous][next][first][last][top][bottom][index][help]  */
 241                          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 = vfs_s_find_inode (me, super, q, (flags & FL_FOLLOW) != 0 ? LINK_FOLLOW : LINK_NO_FOLLOW,
 408                             flags & ~FL_FOLLOW);
 409     if (ino == NULL && *q == '\0')
 410         // We are asking about / directory of ftp server: assume it exists
 411         ino =
 412             vfs_s_find_inode (me, super, q, (flags & FL_FOLLOW) != 0 ? LINK_FOLLOW : LINK_NO_FOLLOW,
 413                               FL_DIR | (flags & ~FL_FOLLOW));
 414     return ino;
 415 }
 416 
 417 /* --------------------------------------------------------------------------------------------- */
 418 
 419 static void *
 420 vfs_s_opendir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 421 {
 422     struct vfs_s_inode *dir;
 423     struct dirhandle *info;
 424     struct vfs_class *me;
 425 
 426     dir = vfs_s_inode_from_path (vpath, FL_DIR | FL_FOLLOW);
 427     if (dir == NULL)
 428         return NULL;
 429 
 430     me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
 431 
 432     if (!S_ISDIR (dir->st.st_mode))
 433     {
 434         me->verrno = ENOTDIR;
 435         return NULL;
 436     }
 437 
 438     dir->st.st_nlink++;
 439 #if 0
 440     if (dir->subdir == NULL)    // This can actually happen if we allow empty directories 
 441     {
 442         me->verrno = EAGAIN;
 443         return NULL;
 444     }
 445 #endif
 446     info = g_new (struct dirhandle, 1);
 447     info->cur = g_queue_peek_head_link (dir->subdir);
 448     info->dir = dir;
 449 
 450     return info;
 451 }
 452 
 453 /* --------------------------------------------------------------------------------------------- */
 454 
 455 static struct vfs_dirent *
 456 vfs_s_readdir (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 457 {
 458     struct vfs_dirent *dir = NULL;
 459     struct dirhandle *info = (struct dirhandle *) data;
 460     const char *name;
 461 
 462     if (info->cur == NULL || info->cur->data == NULL)
 463         return NULL;
 464 
 465     name = VFS_ENTRY (info->cur->data)->name;
 466     if (name != NULL)
 467         dir = vfs_dirent_init (NULL, name, 0);
 468     else
 469         vfs_die ("Null in structure-cannot happen");
 470 
 471     info->cur = g_list_next (info->cur);
 472 
 473     return dir;
 474 }
 475 
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 static int
 479 vfs_s_closedir (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 480 {
 481     struct dirhandle *info = (struct dirhandle *) data;
 482     struct vfs_s_inode *dir = info->dir;
 483 
 484     vfs_s_free_inode (dir->super->me, dir);
 485     g_free (data);
 486     return 0;
 487 }
 488 
 489 /* --------------------------------------------------------------------------------------------- */
 490 
 491 static int
 492 vfs_s_chdir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 493 {
 494     void *data;
 495 
 496     data = vfs_s_opendir (vpath);
 497     if (data == NULL)
 498         return (-1);
 499     vfs_s_closedir (data);
 500     return 0;
 501 }
 502 
 503 /* --------------------------------------------------------------------------------------------- */
 504 /* --------------------------- stat and friends ---------------------------- */
 505 
 506 static int
 507 vfs_s_internal_stat (const vfs_path_t *vpath, struct stat *buf, int flag)
     /* [previous][next][first][last][top][bottom][index][help]  */
 508 {
 509     struct vfs_s_inode *ino;
 510 
 511     ino = vfs_s_inode_from_path (vpath, flag);
 512     if (ino == NULL)
 513         return (-1);
 514     *buf = ino->st;
 515     return 0;
 516 }
 517 
 518 /* --------------------------------------------------------------------------------------------- */
 519 
 520 static int
 521 vfs_s_readlink (const vfs_path_t *vpath, char *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 522 {
 523     struct vfs_s_inode *ino;
 524     size_t len;
 525     struct vfs_class *me;
 526 
 527     ino = vfs_s_inode_from_path (vpath, 0);
 528     if (ino == NULL)
 529         return (-1);
 530 
 531     me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
 532 
 533     if (!S_ISLNK (ino->st.st_mode))
 534     {
 535         me->verrno = EINVAL;
 536         return (-1);
 537     }
 538 
 539     if (ino->linkname == NULL)
 540     {
 541         me->verrno = EFAULT;
 542         return (-1);
 543     }
 544 
 545     len = strlen (ino->linkname);
 546     if (size < len)
 547         len = size;
 548     // readlink() does not append a NUL character to buf
 549     memcpy (buf, ino->linkname, len);
 550     return len;
 551 }
 552 
 553 /* --------------------------------------------------------------------------------------------- */
 554 
 555 static ssize_t
 556 vfs_s_read (void *fh, char *buffer, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 557 {
 558     vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
 559     struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
 560 
 561     if (file->linear == LS_LINEAR_PREOPEN)
 562         if (VFS_SUBCLASS (me)->linear_start (me, file, file->pos) == 0)
 563             return (-1);
 564 
 565     if (file->linear == LS_LINEAR_CLOSED)
 566         vfs_die ("linear_start() did not set linear_state!");
 567 
 568     if (file->linear == LS_LINEAR_OPEN)
 569         return VFS_SUBCLASS (me)->linear_read (me, file, buffer, count);
 570 
 571     if (file->handle != -1)
 572     {
 573         ssize_t n;
 574 
 575         n = read (file->handle, buffer, count);
 576         if (n < 0)
 577             me->verrno = errno;
 578         return n;
 579     }
 580     vfs_die ("vfs_s_read: This should not happen\n");
 581     return (-1);
 582 }
 583 
 584 /* --------------------------------------------------------------------------------------------- */
 585 
 586 static ssize_t
 587 vfs_s_write (void *fh, const char *buffer, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 588 {
 589     vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
 590     struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
 591 
 592     if (file->linear != LS_NOT_LINEAR)
 593         vfs_die ("no writing to linear files, please");
 594 
 595     file->changed = TRUE;
 596     if (file->handle != -1)
 597     {
 598         ssize_t n;
 599 
 600         n = write (file->handle, buffer, count);
 601         if (n < 0)
 602             me->verrno = errno;
 603         return n;
 604     }
 605     vfs_die ("vfs_s_write: This should not happen\n");
 606     return 0;
 607 }
 608 
 609 /* --------------------------------------------------------------------------------------------- */
 610 
 611 static off_t
 612 vfs_s_lseek (void *fh, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 613 {
 614     vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
 615     off_t size = file->ino->st.st_size;
 616 
 617     if (file->linear == LS_LINEAR_OPEN)
 618         vfs_die ("cannot lseek() after linear_read!");
 619 
 620     if (file->handle != -1)
 621     {  // If we have local file opened, we want to work with it
 622         off_t retval;
 623 
 624         retval = lseek (file->handle, offset, whence);
 625         if (retval == -1)
 626             VFS_FILE_HANDLER_SUPER (fh)->me->verrno = errno;
 627         return retval;
 628     }
 629 
 630     switch (whence)
 631     {
 632     case SEEK_CUR:
 633         offset += file->pos;
 634         break;
 635     case SEEK_END:
 636         offset += size;
 637         break;
 638     default:
 639         break;
 640     }
 641     if (offset < 0)
 642         file->pos = 0;
 643     else if (offset < size)
 644         file->pos = offset;
 645     else
 646         file->pos = size;
 647     return file->pos;
 648 }
 649 
 650 /* --------------------------------------------------------------------------------------------- */
 651 
 652 static int
 653 vfs_s_close (void *fh)
     /* [previous][next][first][last][top][bottom][index][help]  */
 654 {
 655     vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
 656     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
 657     struct vfs_class *me = super->me;
 658     struct vfs_s_subclass *sub = VFS_SUBCLASS (me);
 659     int res = 0;
 660 
 661     if (me == NULL)
 662         return (-1);
 663 
 664     super->fd_usage--;
 665     if (super->fd_usage == 0)
 666         vfs_stamp_create (me, VFS_FILE_HANDLER_SUPER (fh));
 667 
 668     if (file->linear == LS_LINEAR_OPEN)
 669         sub->linear_close (me, fh);
 670     if (sub->fh_close != NULL)
 671         res = sub->fh_close (me, fh);
 672     if ((me->flags & VFSF_USETMP) != 0 && file->changed && sub->file_store != NULL)
 673     {
 674         char *s;
 675 
 676         s = vfs_s_fullpath (me, file->ino);
 677 
 678         if (s == NULL)
 679             res = -1;
 680         else
 681         {
 682             res = sub->file_store (me, fh, s, file->ino->localname);
 683             g_free (s);
 684         }
 685         vfs_s_invalidate (me, super);
 686     }
 687 
 688     if (file->handle != -1)
 689     {
 690         close (file->handle);
 691         file->handle = -1;
 692     }
 693 
 694     vfs_s_free_inode (me, file->ino);
 695     vfs_s_free_fh (sub, fh);
 696 
 697     return res;
 698 }
 699 
 700 /* --------------------------------------------------------------------------------------------- */
 701 
 702 static void
 703 vfs_s_print_stats (const char *fs_name, const char *action, const char *file_name, off_t have,
     /* [previous][next][first][last][top][bottom][index][help]  */
 704                    off_t need)
 705 {
 706     if (need != 0)
 707         vfs_print_message (_ ("%s: %s: %s %3d%% (%lld) bytes transferred"), fs_name, action,
 708                            file_name, (int) ((double) have * 100 / need), (long long) have);
 709     else
 710         vfs_print_message (_ ("%s: %s: %s %lld bytes transferred"), fs_name, action, file_name,
 711                            (long long) have);
 712 }
 713 
 714 /* --------------------------------------------------------------------------------------------- */
 715 /* ------------------------------- mc support ---------------------------- */
 716 
 717 static void
 718 vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
 719 {
 720     GList *iter;
 721 
 722     for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
 723     {
 724         const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
 725         char *name;
 726 
 727         name = g_strconcat (super->name, PATH_SEP_STR, me->prefix, VFS_PATH_URL_DELIMITER,
 728                             (char *) NULL);
 729         func (name);
 730         g_free (name);
 731     }
 732 }
 733 
 734 /* --------------------------------------------------------------------------------------------- */
 735 
 736 static int
 737 vfs_s_ferrno (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 738 {
 739     return me->verrno;
 740 }
 741 
 742 /* --------------------------------------------------------------------------------------------- */
 743 /**
 744  * Get local copy of the given file.  We reuse the existing file cache
 745  * for remote filesystems.  Archives use standard VFS facilities.
 746  */
 747 
 748 static vfs_path_t *
 749 vfs_s_getlocalcopy (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 750 {
 751     vfs_file_handler_t *fh;
 752     vfs_path_t *local = NULL;
 753 
 754     if (vpath == NULL)
 755         return NULL;
 756 
 757     fh = vfs_s_open (vpath, O_RDONLY, 0);
 758 
 759     if (fh != NULL)
 760     {
 761         const struct vfs_class *me;
 762 
 763         me = vfs_path_get_last_path_vfs (vpath);
 764         if ((me->flags & VFSF_USETMP) != 0 && fh->ino != NULL)
 765             local = vfs_path_from_str_flags (fh->ino->localname, VPF_NO_CANON);
 766 
 767         vfs_s_close (fh);
 768     }
 769 
 770     return local;
 771 }
 772 
 773 /* --------------------------------------------------------------------------------------------- */
 774 /**
 775  * Return the local copy.  Since we are using our cache, we do nothing -
 776  * the cache will be removed when the archive is closed.
 777  */
 778 
 779 static int
 780 vfs_s_ungetlocalcopy (const vfs_path_t *vpath, const vfs_path_t *local, gboolean has_changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
 781 {
 782     (void) vpath;
 783     (void) local;
 784     (void) has_changed;
 785     return 0;
 786 }
 787 
 788 /* --------------------------------------------------------------------------------------------- */
 789 
 790 static int
 791 vfs_s_setctl (const vfs_path_t *vpath, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 792 {
 793     struct vfs_class *me;
 794 
 795     me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
 796 
 797     switch (ctlop)
 798     {
 799     case VFS_SETCTL_STALE_DATA:
 800     {
 801         struct vfs_s_inode *ino;
 802 
 803         ino = vfs_s_inode_from_path (vpath, 0);
 804         if (ino == NULL)
 805             return 0;
 806         if (arg != NULL)
 807             ino->super->want_stale = TRUE;
 808         else
 809         {
 810             ino->super->want_stale = FALSE;
 811             vfs_s_invalidate (me, ino->super);
 812         }
 813         return 1;
 814     }
 815     case VFS_SETCTL_LOGFILE:
 816         me->logfile = fopen ((char *) arg, "w");
 817         return 1;
 818     case VFS_SETCTL_FLUSH:
 819         me->flush = TRUE;
 820         return 1;
 821     default:
 822         return 0;
 823     }
 824 }
 825 
 826 /* --------------------------------------------------------------------------------------------- */
 827 /* ----------------------------- Stamping support -------------------------- */
 828 
 829 static vfsid
 830 vfs_s_getid (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 831 {
 832     struct vfs_s_super *archive = NULL;
 833     const char *p;
 834 
 835     p = vfs_s_get_path (vpath, &archive, FL_NO_OPEN);
 836     return (p == NULL ? NULL : (vfsid) archive);
 837 }
 838 
 839 /* --------------------------------------------------------------------------------------------- */
 840 
 841 static gboolean
 842 vfs_s_nothingisopen (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 843 {
 844     return (VFS_SUPER (id)->fd_usage <= 0);
 845 }
 846 
 847 /* --------------------------------------------------------------------------------------------- */
 848 
 849 static void
 850 vfs_s_free (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 851 {
 852     vfs_s_free_super (VFS_SUPER (id)->me, VFS_SUPER (id));
 853 }
 854 
 855 /* --------------------------------------------------------------------------------------------- */
 856 
 857 static gboolean
 858 vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
 859 {
 860     gint64 tim;
 861 
 862     if (me->flush)
 863     {
 864         me->flush = FALSE;
 865         return 0;
 866     }
 867 
 868     tim = g_get_monotonic_time ();
 869 
 870     return (tim < ino->timestamp);
 871 }
 872 
 873 /* --------------------------------------------------------------------------------------------- */
 874 /*** public functions ****************************************************************************/
 875 /* --------------------------------------------------------------------------------------------- */
 876 
 877 struct vfs_s_inode *
 878 vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
     /* [previous][next][first][last][top][bottom][index][help]  */
 879 {
 880     struct vfs_s_inode *ino;
 881 
 882     ino = g_try_new0 (struct vfs_s_inode, 1);
 883     if (ino == NULL)
 884         return NULL;
 885 
 886     if (initstat != NULL)
 887         ino->st = *initstat;
 888     ino->super = super;
 889     ino->subdir = g_queue_new ();
 890     ino->st.st_nlink = 0;
 891     ino->st.st_ino = VFS_SUBCLASS (me)->inode_counter++;
 892     ino->st.st_dev = VFS_SUBCLASS (me)->rdev;
 893 
 894     super->ino_usage++;
 895 
 896     CALL (init_inode) (me, ino);
 897 
 898     return ino;
 899 }
 900 
 901 /* --------------------------------------------------------------------------------------------- */
 902 
 903 void
 904 vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
 905 {
 906     if (ino == NULL)
 907         vfs_die ("Don't pass NULL to me");
 908 
 909     // ==0 can happen if freshly created entry is deleted
 910     if (ino->st.st_nlink > 1)
 911     {
 912         ino->st.st_nlink--;
 913         return;
 914     }
 915 
 916     while (g_queue_get_length (ino->subdir) != 0)
 917     {
 918         struct vfs_s_entry *entry;
 919 
 920         entry = VFS_ENTRY (g_queue_peek_head (ino->subdir));
 921         vfs_s_free_entry (me, entry);
 922     }
 923 
 924     g_queue_free (ino->subdir);
 925     ino->subdir = NULL;
 926 
 927     CALL (free_inode) (me, ino);
 928     g_free (ino->linkname);
 929     if ((me->flags & VFSF_USETMP) != 0 && ino->localname != NULL)
 930     {
 931         unlink (ino->localname);
 932         g_free (ino->localname);
 933     }
 934     ino->super->ino_usage--;
 935     g_free (ino);
 936 }
 937 
 938 /* --------------------------------------------------------------------------------------------- */
 939 
 940 struct vfs_s_entry *
 941 vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 942 {
 943     struct vfs_s_entry *entry;
 944 
 945     entry = g_new0 (struct vfs_s_entry, 1);
 946 
 947     entry->name = g_strdup (name);
 948     entry->ino = inode;
 949     entry->ino->ent = entry;
 950     CALL (init_entry) (me, entry);
 951 
 952     return entry;
 953 }
 954 
 955 /* --------------------------------------------------------------------------------------------- */
 956 
 957 void
 958 vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
     /* [previous][next][first][last][top][bottom][index][help]  */
 959 {
 960     if (ent->dir != NULL)
 961         g_queue_remove (ent->dir->subdir, ent);
 962 
 963     MC_PTR_FREE (ent->name);
 964 
 965     if (ent->ino != NULL)
 966     {
 967         ent->ino->ent = NULL;
 968         vfs_s_free_inode (me, ent->ino);
 969     }
 970 
 971     g_free (ent);
 972 }
 973 
 974 /* --------------------------------------------------------------------------------------------- */
 975 
 976 void
 977 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]  */
 978 {
 979     (void) me;
 980 
 981     ent->dir = dir;
 982 
 983     ent->ino->st.st_nlink++;
 984     g_queue_push_tail (dir->subdir, ent);
 985 }
 986 
 987 /* --------------------------------------------------------------------------------------------- */
 988 
 989 int
 990 vfs_s_entry_compare (const void *a, const void *b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 991 {
 992     const struct vfs_s_entry *e = (const struct vfs_s_entry *) a;
 993     const char *name = (const char *) b;
 994 
 995     return strcmp (e->name, name);
 996 }
 997 
 998 /* --------------------------------------------------------------------------------------------- */
 999 
1000 struct stat *
1001 vfs_s_default_stat (struct vfs_class *me, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1002 {
1003     static struct stat st;
1004     mode_t myumask;
1005 
1006     (void) me;
1007 
1008     myumask = umask (022);
1009     umask (myumask);
1010     mode &= ~myumask;
1011 
1012     st.st_mode = mode;
1013     st.st_ino = 0;
1014     st.st_dev = 0;
1015 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1016     st.st_rdev = 0;
1017 #endif
1018     st.st_uid = getuid ();
1019     st.st_gid = getgid ();
1020 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1021     st.st_blksize = 512;
1022 #endif
1023     st.st_size = 0;
1024 
1025     vfs_zero_stat_times (&st);
1026 
1027     vfs_adjust_stat (&st);
1028 
1029     return &st;
1030 }
1031 
1032 /* --------------------------------------------------------------------------------------------- */
1033 /**
1034  * Calculate number of st_blocks using st_size and st_blksize.
1035  * In according to stat(2), st_blocks is the size in 512-byte units.
1036  *
1037  * @param s stat info
1038  */
1039 
1040 void
1041 vfs_adjust_stat (struct stat *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
1042 {
1043 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
1044     if (s->st_size == 0)
1045         s->st_blocks = 0;
1046     else
1047     {
1048 #    ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1049         blkcnt_t ioblocks;
1050         blksize_t ioblock_size;
1051 
1052         // 1. Calculate how many IO blocks are occupied
1053         ioblocks = 1 + (s->st_size - 1) / s->st_blksize;
1054         // 2. Calculate size of st_blksize in 512-byte units
1055         ioblock_size = 1 + (s->st_blksize - 1) / 512;
1056         // 3. Calculate number of blocks
1057         s->st_blocks = ioblocks * ioblock_size;
1058 #    else
1059         // Let IO block size is 512 bytes
1060         s->st_blocks = 1 + (s->st_size - 1) / 512;
1061 #    endif
1062     }
1063 #endif
1064 }
1065 
1066 /* --------------------------------------------------------------------------------------------- */
1067 
1068 struct vfs_s_entry *
1069 vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent,
     /* [previous][next][first][last][top][bottom][index][help]  */
1070                       mode_t mode)
1071 {
1072     struct vfs_s_inode *inode;
1073     struct stat *st;
1074 
1075     st = vfs_s_default_stat (me, mode);
1076     inode = vfs_s_new_inode (me, parent->super, st);
1077 
1078     return vfs_s_new_entry (me, name, inode);
1079 }
1080 
1081 /* --------------------------------------------------------------------------------------------- */
1082 
1083 struct vfs_s_inode *
1084 vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super, const char *path,
     /* [previous][next][first][last][top][bottom][index][help]  */
1085                   int follow, int flags)
1086 {
1087     struct vfs_s_entry *ent;
1088 
1089     if (((me->flags & VFSF_REMOTE) == 0) && (*path == '\0'))
1090         return super->root;
1091 
1092     ent = VFS_SUBCLASS (me)->find_entry (me, super->root, path, follow, flags);
1093     return (ent != NULL ? ent->ino : NULL);
1094 }
1095 
1096 /* --------------------------------------------------------------------------------------------- */
1097 /* Ook, these were functions around directory entries / inodes */
1098 /* -------------------------------- superblock games -------------------------- */
1099 /**
1100  * get superlock object by vpath
1101  *
1102  * @param vpath path
1103  * @return superlock object or NULL if not found
1104  */
1105 
1106 struct vfs_s_super *
1107 vfs_get_super_by_vpath (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1108 {
1109     GList *iter;
1110     void *cookie = NULL;
1111     const vfs_path_element_t *path_element;
1112     struct vfs_s_subclass *subclass;
1113     struct vfs_s_super *super = NULL;
1114     vfs_path_t *vpath_archive;
1115 
1116     path_element = vfs_path_get_by_index (vpath, -1);
1117     subclass = VFS_SUBCLASS (path_element->class);
1118 
1119     vpath_archive = vfs_path_clone (vpath);
1120     vfs_path_remove_element_by_index (vpath_archive, -1);
1121 
1122     if (subclass->archive_check != NULL)
1123     {
1124         cookie = subclass->archive_check (vpath_archive);
1125         if (cookie == NULL)
1126             goto ret;
1127     }
1128 
1129     if (subclass->archive_same == NULL)
1130         goto ret;
1131 
1132     for (iter = subclass->supers; iter != NULL; iter = g_list_next (iter))
1133     {
1134         int i;
1135 
1136         super = VFS_SUPER (iter->data);
1137 
1138         // 0 == other, 1 == same, return it, 2 == other but stop scanning
1139         i = subclass->archive_same (path_element, super, vpath_archive, cookie);
1140         if (i == 1)
1141             goto ret;
1142         if (i != 0)
1143             break;
1144 
1145         super = NULL;
1146     }
1147 
1148 ret:
1149     vfs_path_free (vpath_archive, TRUE);
1150     return super;
1151 }
1152 
1153 /* --------------------------------------------------------------------------------------------- */
1154 /**
1155  * get path from last VFS-element and create corresponding superblock
1156  *
1157  * @param vpath source path object
1158  * @param archive pointer to object for store newly created superblock
1159  * @param flags flags
1160  *
1161  * @return path from last VFS-element
1162  */
1163 const char *
1164 vfs_s_get_path (const vfs_path_t *vpath, struct vfs_s_super **archive, int flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
1165 {
1166     const char *retval = "";
1167     int result = -1;
1168     struct vfs_s_super *super;
1169     const vfs_path_element_t *path_element;
1170     struct vfs_s_subclass *subclass;
1171 
1172     path_element = vfs_path_get_by_index (vpath, -1);
1173 
1174     if (path_element->path != NULL)
1175         retval = path_element->path;
1176 
1177     super = vfs_get_super_by_vpath (vpath);
1178     if (super != NULL)
1179         goto return_success;
1180 
1181     if ((flags & FL_NO_OPEN) != 0)
1182     {
1183         path_element->class->verrno = EIO;
1184         return NULL;
1185     }
1186 
1187     subclass = VFS_SUBCLASS (path_element->class);
1188 
1189     super = subclass->new_archive != NULL ? subclass->new_archive (path_element->class)
1190                                           : vfs_s_new_super (path_element->class);
1191 
1192     if (subclass->open_archive != NULL)
1193     {
1194         vfs_path_t *vpath_archive;
1195 
1196         vpath_archive = vfs_path_clone (vpath);
1197         vfs_path_remove_element_by_index (vpath_archive, -1);
1198 
1199         result = subclass->open_archive (super, vpath_archive, path_element);
1200         vfs_path_free (vpath_archive, TRUE);
1201     }
1202     if (result == -1)
1203     {
1204         vfs_s_free_super (path_element->class, super);
1205         path_element->class->verrno = EIO;
1206         return NULL;
1207     }
1208     if (super->name == NULL)
1209         vfs_die ("You have to fill name\n");
1210     if (super->root == NULL)
1211         vfs_die ("You have to fill root inode\n");
1212 
1213     vfs_s_insert_super (path_element->class, super);
1214     vfs_stamp_create (path_element->class, super);
1215 
1216 return_success:
1217     *archive = super;
1218     return retval;
1219 }
1220 
1221 /* --------------------------------------------------------------------------------------------- */
1222 
1223 void
1224 vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
1225 {
1226     if (!super->want_stale)
1227     {
1228         vfs_s_free_inode (me, super->root);
1229         super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
1230     }
1231 }
1232 
1233 /* --------------------------------------------------------------------------------------------- */
1234 
1235 char *
1236 vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
1237 {
1238     if (ino->ent == NULL)
1239         ERRNOR (EAGAIN, NULL);
1240 
1241     if ((me->flags & VFSF_USETMP) == 0)
1242     {
1243         // archives
1244         char *path;
1245 
1246         path = g_strdup (ino->ent->name);
1247 
1248         while (TRUE)
1249         {
1250             char *newpath;
1251 
1252             ino = ino->ent->dir;
1253             if (ino == ino->super->root)
1254                 break;
1255 
1256             newpath = g_strconcat (ino->ent->name, PATH_SEP_STR, path, (char *) NULL);
1257             g_free (path);
1258             path = newpath;
1259         }
1260         return path;
1261     }
1262 
1263     // remote systems
1264     if (ino->ent->dir == NULL || ino->ent->dir->ent == NULL)
1265         return g_strdup (ino->ent->name);
1266 
1267     return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, ino->ent->name, (char *) NULL);
1268 }
1269 
1270 /* --------------------------------------------------------------------------------------------- */
1271 
1272 void
1273 vfs_s_init_fh (vfs_file_handler_t *fh, struct vfs_s_inode *ino, gboolean changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
1274 {
1275     fh->ino = ino;
1276     fh->handle = -1;
1277     fh->changed = changed;
1278     fh->linear = LS_NOT_LINEAR;
1279 }
1280 
1281 /* --------------------------------------------------------------------------------------------- */
1282 /* --------------------------- stat and friends ---------------------------- */
1283 
1284 void *
1285 vfs_s_open (const vfs_path_t *vpath, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1286 {
1287     gboolean was_changed = FALSE;
1288     vfs_file_handler_t *fh;
1289     struct vfs_s_super *super;
1290     const char *q;
1291     struct vfs_s_inode *ino;
1292     struct vfs_class *me;
1293     struct vfs_s_subclass *s;
1294 
1295     q = vfs_s_get_path (vpath, &super, 0);
1296     if (q == NULL)
1297         return NULL;
1298 
1299     me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
1300 
1301     ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
1302     if (ino != NULL && (flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
1303     {
1304         me->verrno = EEXIST;
1305         return NULL;
1306     }
1307 
1308     s = VFS_SUBCLASS (me);
1309 
1310     if (ino == NULL)
1311     {
1312         char *name;
1313         struct vfs_s_entry *ent;
1314         struct vfs_s_inode *dir;
1315 
1316         // If the filesystem is read-only, disable file creation
1317         if ((flags & O_CREAT) == 0 || me->write == NULL)
1318             return NULL;
1319 
1320         name = g_path_get_dirname (q);
1321         dir = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_DIR);
1322         g_free (name);
1323         if (dir == NULL)
1324             return NULL;
1325 
1326         name = g_path_get_basename (q);
1327         ent = vfs_s_generate_entry (me, name, dir, 0755);
1328         ino = ent->ino;
1329         vfs_s_insert_entry (me, dir, ent);
1330         if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0)
1331         {
1332             int tmp_handle;
1333             vfs_path_t *tmp_vpath;
1334 
1335             tmp_handle = vfs_mkstemps (&tmp_vpath, me->name, name);
1336             ino->localname = vfs_path_free (tmp_vpath, FALSE);
1337             if (tmp_handle == -1)
1338             {
1339                 g_free (name);
1340                 return NULL;
1341             }
1342 
1343             close (tmp_handle);
1344         }
1345 
1346         g_free (name);
1347         was_changed = TRUE;
1348     }
1349 
1350     if (S_ISDIR (ino->st.st_mode))
1351     {
1352         me->verrno = EISDIR;
1353         return NULL;
1354     }
1355 
1356     fh = s->fh_new != NULL ? s->fh_new (ino, was_changed) : vfs_s_new_fh (ino, was_changed);
1357 
1358     if (IS_LINEAR (flags))
1359     {
1360         if (s->linear_start != NULL)
1361         {
1362             vfs_print_message ("%s", _ ("Starting linear transfer..."));
1363             fh->linear = LS_LINEAR_PREOPEN;
1364         }
1365     }
1366     else
1367     {
1368         if (s->fh_open != NULL && s->fh_open (me, fh, flags, mode) != 0)
1369         {
1370             vfs_s_free_fh (s, fh);
1371             return NULL;
1372         }
1373     }
1374 
1375     if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0 && fh->ino->localname != NULL)
1376     {
1377         fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
1378         if (fh->handle == -1)
1379         {
1380             vfs_s_free_fh (s, fh);
1381             me->verrno = errno;
1382             return NULL;
1383         }
1384     }
1385 
1386     // i.e. we had no open files and now we have one
1387     vfs_rmstamp (me, (vfsid) super);
1388     super->fd_usage++;
1389     fh->ino->st.st_nlink++;
1390     return fh;
1391 }
1392 
1393 /* --------------------------------------------------------------------------------------------- */
1394 
1395 int
1396 vfs_s_stat (const vfs_path_t *vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1397 {
1398     return vfs_s_internal_stat (vpath, buf, FL_FOLLOW);
1399 }
1400 
1401 /* --------------------------------------------------------------------------------------------- */
1402 
1403 int
1404 vfs_s_lstat (const vfs_path_t *vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1405 {
1406     return vfs_s_internal_stat (vpath, buf, FL_NONE);
1407 }
1408 
1409 /* --------------------------------------------------------------------------------------------- */
1410 
1411 int
1412 vfs_s_fstat (void *fh, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1413 {
1414     *buf = VFS_FILE_HANDLER (fh)->ino->st;
1415     return 0;
1416 }
1417 
1418 /* --------------------------------------------------------------------------------------------- */
1419 
1420 int
1421 vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
1422 {
1423     // If you want reget, you'll have to open file with O_LINEAR
1424     off_t total = 0;
1425     char buffer[BUF_8K];
1426     int handle;
1427     ssize_t n;
1428     off_t stat_size = ino->st.st_size;
1429     vfs_file_handler_t *fh = NULL;
1430     vfs_path_t *tmp_vpath;
1431     struct vfs_s_subclass *s = VFS_SUBCLASS (me);
1432 
1433     if ((me->flags & VFSF_USETMP) == 0)
1434         return (-1);
1435 
1436     handle = vfs_mkstemps (&tmp_vpath, me->name, ino->ent->name);
1437     ino->localname = vfs_path_free (tmp_vpath, FALSE);
1438     if (handle == -1)
1439     {
1440         me->verrno = errno;
1441         goto error_4;
1442     }
1443 
1444     fh = s->fh_new != NULL ? s->fh_new (ino, FALSE) : vfs_s_new_fh (ino, FALSE);
1445 
1446     if (s->linear_start (me, fh, 0) == 0)
1447         goto error_3;
1448 
1449     // Clear the interrupt status
1450     tty_got_interrupt ();
1451     tty_enable_interrupt_key ();
1452 
1453     while ((n = s->linear_read (me, fh, buffer, sizeof (buffer))) != 0)
1454     {
1455         int t;
1456 
1457         if (n < 0)
1458             goto error_1;
1459 
1460         total += n;
1461         vfs_s_print_stats (me->name, _ ("Getting file"), ino->ent->name, total, stat_size);
1462 
1463         if (tty_got_interrupt ())
1464             goto error_1;
1465 
1466         t = write (handle, buffer, n);
1467         if (t != n)
1468         {
1469             if (t == -1)
1470                 me->verrno = errno;
1471             goto error_1;
1472         }
1473     }
1474     s->linear_close (me, fh);
1475     close (handle);
1476 
1477     tty_disable_interrupt_key ();
1478     vfs_s_free_fh (s, fh);
1479     return 0;
1480 
1481 error_1:
1482     s->linear_close (me, fh);
1483 error_3:
1484     tty_disable_interrupt_key ();
1485     close (handle);
1486     unlink (ino->localname);
1487 error_4:
1488     MC_PTR_FREE (ino->localname);
1489     if (fh != NULL)
1490         vfs_s_free_fh (s, fh);
1491     return (-1);
1492 }
1493 
1494 /* --------------------------------------------------------------------------------------------- */
1495 /* ----------------------------- Stamping support -------------------------- */
1496 
1497 /* Initialize one of our subclasses - fill common functions */
1498 void
1499 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]  */
1500 {
1501     memset (vclass, 0, sizeof (struct vfs_class));
1502 
1503     vclass->name = name;
1504     vclass->flags = flags;
1505     vclass->prefix = prefix;
1506 
1507     vclass->fill_names = vfs_s_fill_names;
1508     vclass->open = vfs_s_open;
1509     vclass->close = vfs_s_close;
1510     vclass->read = vfs_s_read;
1511     if ((vclass->flags & VFSF_READONLY) == 0)
1512         vclass->write = vfs_s_write;
1513     vclass->opendir = vfs_s_opendir;
1514     vclass->readdir = vfs_s_readdir;
1515     vclass->closedir = vfs_s_closedir;
1516     vclass->stat = vfs_s_stat;
1517     vclass->lstat = vfs_s_lstat;
1518     vclass->fstat = vfs_s_fstat;
1519     vclass->readlink = vfs_s_readlink;
1520     vclass->chdir = vfs_s_chdir;
1521     vclass->ferrno = vfs_s_ferrno;
1522     vclass->lseek = vfs_s_lseek;
1523     vclass->getid = vfs_s_getid;
1524     vclass->nothingisopen = vfs_s_nothingisopen;
1525     vclass->free = vfs_s_free;
1526     vclass->setctl = vfs_s_setctl;
1527     if ((vclass->flags & VFSF_USETMP) != 0)
1528     {
1529         vclass->getlocalcopy = vfs_s_getlocalcopy;
1530         vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
1531     }
1532 }
1533 
1534 /* --------------------------------------------------------------------------------------------- */
1535 
1536 void
1537 vfs_init_subclass (struct vfs_s_subclass *sub, const char *name, vfs_flags_t flags,
     /* [previous][next][first][last][top][bottom][index][help]  */
1538                    const char *prefix)
1539 {
1540     struct vfs_class *vclass = VFS_CLASS (sub);
1541     size_t len;
1542     char *start;
1543 
1544     vfs_init_class (vclass, name, flags, prefix);
1545 
1546     len = sizeof (struct vfs_s_subclass) - sizeof (struct vfs_class);
1547     start = (char *) sub + sizeof (struct vfs_class);
1548     memset (start, 0, len);
1549 
1550     if ((vclass->flags & VFSF_USETMP) != 0)
1551         sub->find_entry = vfs_s_find_entry_linear;
1552     else if ((vclass->flags & VFSF_REMOTE) != 0)
1553         sub->find_entry = vfs_s_find_entry_linear;
1554     else
1555         sub->find_entry = vfs_s_find_entry_tree;
1556     sub->dir_uptodate = vfs_s_dir_uptodate;
1557 }
1558 
1559 /* --------------------------------------------------------------------------------------------- */
1560 /** Find VFS id for given directory name */
1561 
1562 vfsid
1563 vfs_getid (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1564 {
1565     const struct vfs_class *me;
1566 
1567     me = vfs_path_get_last_path_vfs (vpath);
1568     if (me == NULL || me->getid == NULL)
1569         return NULL;
1570 
1571     return me->getid (vpath);
1572 }
1573 
1574 /* --------------------------------------------------------------------------------------------- */
1575 /* ----------- Utility functions for networked filesystems  -------------- */
1576 
1577 #ifdef ENABLE_VFS_NET
1578 int
1579 vfs_s_select_on_two (int fd1, int fd2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1580 {
1581     struct timeval time_out = {
1582         .tv_sec = 1,
1583         .tv_usec = 0,
1584     };
1585     fd_set set;
1586     int maxfd;
1587     int v;
1588 
1589     maxfd = MAX (fd1, fd2) + 1;
1590 
1591     FD_ZERO (&set);
1592     FD_SET (fd1, &set);
1593     FD_SET (fd2, &set);
1594 
1595     v = select (maxfd, &set, 0, 0, &time_out);
1596     if (v <= 0)
1597         return v;
1598     if (FD_ISSET (fd1, &set))
1599         return 1;
1600     if (FD_ISSET (fd2, &set))
1601         return 2;
1602     return (-1);
1603 }
1604 
1605 /* --------------------------------------------------------------------------------------------- */
1606 
1607 int
1608 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]  */
1609 {
1610     FILE *logfile = me->logfile;
1611     int i;
1612     char c;
1613 
1614     for (i = 0; i < buf_len - 1; i++, buf++)
1615     {
1616         if (read (sock, buf, sizeof (char)) <= 0)
1617             return 0;
1618 
1619         if (logfile != NULL)
1620         {
1621             size_t ret1;
1622             int ret2;
1623 
1624             ret1 = fwrite (buf, 1, 1, logfile);
1625             ret2 = fflush (logfile);
1626             (void) ret1;
1627             (void) ret2;
1628         }
1629 
1630         if (*buf == term)
1631         {
1632             *buf = '\0';
1633             return 1;
1634         }
1635     }
1636 
1637     // Line is too long - terminate buffer and discard the rest of line
1638     *buf = '\0';
1639     while (read (sock, &c, sizeof (c)) > 0)
1640     {
1641         if (logfile != NULL)
1642         {
1643             size_t ret1;
1644             int ret2;
1645 
1646             ret1 = fwrite (&c, 1, 1, logfile);
1647             ret2 = fflush (logfile);
1648             (void) ret1;
1649             (void) ret2;
1650         }
1651         if (c == '\n')
1652             return 1;
1653     }
1654     return 0;
1655 }
1656 
1657 /* --------------------------------------------------------------------------------------------- */
1658 
1659 int
1660 vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
1661 {
1662     int i;
1663     int res = 0;
1664 
1665     (void) me;
1666 
1667     tty_enable_interrupt_key ();
1668 
1669     for (i = 0; i < size - 1; i++)
1670     {
1671         ssize_t n;
1672 
1673         n = read (fd, &buffer[i], 1);
1674         if (n == -1 && errno == EINTR)
1675         {
1676             buffer[i] = '\0';
1677             res = EINTR;
1678             goto ret;
1679         }
1680         if (n == 0)
1681         {
1682             buffer[i] = '\0';
1683             goto ret;
1684         }
1685         if (buffer[i] == '\n')
1686         {
1687             buffer[i] = '\0';
1688             res = 1;
1689             goto ret;
1690         }
1691     }
1692 
1693     buffer[size - 1] = '\0';
1694 
1695 ret:
1696     tty_disable_interrupt_key ();
1697 
1698     return res;
1699 }
1700 #endif
1701 
1702 /* --------------------------------------------------------------------------------------------- */
1703 /**
1704  * Normalize filenames start position
1705  */
1706 
1707 void
1708 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]  */
1709 {
1710     GList *iter;
1711 
1712     for (iter = g_queue_peek_head_link (root_inode->subdir); iter != NULL;
1713          iter = g_list_next (iter))
1714     {
1715         struct vfs_s_entry *entry = VFS_ENTRY (iter->data);
1716 
1717         if ((size_t) entry->leading_spaces > final_num_spaces)
1718         {
1719             char *source_name, *spacer;
1720 
1721             source_name = entry->name;
1722             spacer = g_strnfill ((size_t) entry->leading_spaces - final_num_spaces, ' ');
1723             entry->name = g_strconcat (spacer, source_name, (char *) NULL);
1724             g_free (spacer);
1725             g_free (source_name);
1726         }
1727 
1728         entry->leading_spaces = -1;
1729     }
1730 }
1731 
1732 /* --------------------------------------------------------------------------------------------- */

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