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

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