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

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