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

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