root/src/vfs/sfs/sfs.c

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

DEFINITIONS

This source file includes following definitions.
  1. cachedfile_compare
  2. sfs_vfmake
  3. sfs_redirect
  4. sfs_open
  5. sfs_stat
  6. sfs_lstat
  7. sfs_chmod
  8. sfs_chown
  9. sfs_utime
  10. sfs_readlink
  11. sfs_getid
  12. sfs_free
  13. sfs_fill_names
  14. sfs_nothingisopen
  15. sfs_getlocalcopy
  16. sfs_ungetlocalcopy
  17. sfs_init
  18. sfs_done
  19. sfs_which
  20. vfs_init_sfs

   1 /*
   2    Single File fileSystem
   3 
   4    Copyright (C) 1998-2024
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2013
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 /**
  27  * \file
  28  * \brief Source: Single File fileSystem
  29  *
  30  * This defines whole class of filesystems which contain single file
  31  * inside. It is somehow similar to extfs, except that extfs makes
  32  * whole virtual trees and we do only single virtual files.
  33  *
  34  * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
  35  * suffix, DON'T try to gunzip it yourself.
  36  *
  37  * Namespace: exports vfs_sfs_ops
  38  */
  39 
  40 #include <config.h>
  41 #include <sys/types.h>
  42 #include <unistd.h>
  43 #include <stdio.h>
  44 #include <string.h>
  45 
  46 #include "lib/global.h"
  47 #include "lib/util.h"
  48 #include "lib/widget.h"         /* D_ERROR, D_NORMAL */
  49 
  50 #include "lib/vfs/vfs.h"
  51 #include "lib/vfs/utilvfs.h"
  52 #include "lib/vfs/xdirentry.h"
  53 #include "src/vfs/local/local.h"
  54 #include "lib/vfs/gc.h"         /* vfs_stamp_create */
  55 
  56 #include "sfs.h"
  57 
  58 /*** global variables ****************************************************************************/
  59 
  60 /*** file scope macro definitions ****************************************************************/
  61 
  62 #define MAXFS 32
  63 
  64 typedef enum
  65 {
  66     F_NONE = 0x0,
  67     F_1 = 0x1,
  68     F_2 = 0x2,
  69     F_NOLOCALCOPY = 0x4,
  70     F_FULLMATCH = 0x8
  71 } sfs_flags_t;
  72 
  73 #define COPY_CHAR \
  74     if ((size_t) (t - pad) > sizeof (pad)) \
  75     { \
  76         g_free (pqname); \
  77         return (-1); \
  78     } \
  79     else \
  80         *t++ = *s_iter;
  81 
  82 #define COPY_STRING(a) \
  83     if ((t - pad) + strlen (a) > sizeof (pad)) \
  84     { \
  85         g_free (pqname); \
  86         return (-1); \
  87     } \
  88     else \
  89     { \
  90         strcpy (t, a); \
  91         t += strlen (a); \
  92     }
  93 
  94 /*** file scope type declarations ****************************************************************/
  95 
  96 typedef struct cachedfile
  97 {
  98     char *name;
  99     char *cache;
 100 } cachedfile;
 101 
 102 /*** forward declarations (file scope functions) *************************************************/
 103 
 104 /*** file scope variables ************************************************************************/
 105 
 106 static GSList *head = NULL;
 107 
 108 static struct vfs_s_subclass sfs_subclass;
 109 static struct vfs_class *vfs_sfs_ops = VFS_CLASS (&sfs_subclass);
 110 
 111 static int sfs_no = 0;
 112 static struct
 113 {
 114     char *prefix;
 115     char *command;
 116     sfs_flags_t flags;
 117 } sfs_info[MAXFS];
 118 
 119 /* --------------------------------------------------------------------------------------------- */
 120 /*** file scope functions ************************************************************************/
 121 /* --------------------------------------------------------------------------------------------- */
 122 
 123 static int
 124 cachedfile_compare (const void *a, const void *b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 125 {
 126     const cachedfile *cf = (const cachedfile *) a;
 127     const char *name = (const char *) b;
 128 
 129     return strcmp (name, cf->name);
 130 }
 131 
 132 /* --------------------------------------------------------------------------------------------- */
 133 
 134 static int
 135 sfs_vfmake (const vfs_path_t *vpath, vfs_path_t *cache_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 136 {
 137     int w;
 138     char pad[10240];
 139     char *s_iter, *t = pad;
 140     gboolean was_percent = FALSE;
 141     vfs_path_t *pname;          /* name of parent archive */
 142     char *pqname;               /* name of parent archive, quoted */
 143     const vfs_path_element_t *path_element;
 144     mc_pipe_t *pip;
 145     GError *error = NULL;
 146 
 147     path_element = vfs_path_get_by_index (vpath, -1);
 148     pname = vfs_path_clone (vpath);
 149     vfs_path_remove_element_by_index (pname, -1);
 150 
 151     w = path_element->class->which (path_element->class, path_element->vfs_prefix);
 152     if (w == -1)
 153         vfs_die ("This cannot happen... Hopefully.\n");
 154 
 155     if ((sfs_info[w].flags & F_1) == 0
 156         && strcmp (vfs_path_get_last_path_str (pname), PATH_SEP_STR) != 0)
 157     {
 158         vfs_path_free (pname, TRUE);
 159         return (-1);
 160     }
 161 
 162     /*    if ((sfs_info[w].flags & F_2) || (!inpath) || (!*inpath)); else return -1; */
 163     if ((sfs_info[w].flags & F_NOLOCALCOPY) != 0)
 164         pqname = name_quote (vfs_path_as_str (pname), FALSE);
 165     else
 166     {
 167         vfs_path_t *s;
 168 
 169         s = mc_getlocalcopy (pname);
 170         if (s == NULL)
 171         {
 172             vfs_path_free (pname, TRUE);
 173             return (-1);
 174         }
 175 
 176         pqname = name_quote (vfs_path_get_last_path_str (s), FALSE);
 177         vfs_path_free (s, TRUE);
 178     }
 179 
 180     vfs_path_free (pname, TRUE);
 181 
 182     for (s_iter = sfs_info[w].command; *s_iter != '\0'; s_iter++)
 183     {
 184         if (was_percent)
 185         {
 186             const char *ptr = NULL;
 187 
 188             was_percent = FALSE;
 189 
 190             switch (*s_iter)
 191             {
 192             case '1':
 193                 ptr = pqname;
 194                 break;
 195             case '2':
 196                 ptr = path_element->path;
 197                 break;
 198             case '3':
 199                 ptr = vfs_path_get_last_path_str (cache_vpath);
 200                 break;
 201             case '%':
 202                 COPY_CHAR;
 203                 continue;
 204             default:
 205                 break;
 206             }
 207 
 208             if (ptr != NULL)
 209             {
 210                 COPY_STRING (ptr);
 211             }
 212         }
 213         else if (*s_iter == '%')
 214             was_percent = TRUE;
 215         else
 216         {
 217             COPY_CHAR;
 218         }
 219     }
 220 
 221     g_free (pqname);
 222 
 223     /* don't read stdout */
 224     pip = mc_popen (pad, FALSE, TRUE, &error);
 225     if (pip == NULL)
 226     {
 227         message (D_ERROR, MSG_ERROR, _("SFS virtual file system:\n%s"), error->message);
 228         g_error_free (error);
 229         return (-1);
 230     }
 231 
 232     pip->err.null_term = TRUE;
 233 
 234     mc_pread (pip, &error);
 235     if (error != NULL)
 236     {
 237         message (D_ERROR, MSG_ERROR, _("SFS virtual file system:\n%s"), error->message);
 238         g_error_free (error);
 239         mc_pclose (pip, NULL);
 240         return (-1);
 241     }
 242 
 243     if (pip->err.len > 0)
 244         message (D_ERROR, MSG_ERROR, _("SFS virtual file system:\n%s"), pip->err.buf);
 245 
 246     mc_pclose (pip, NULL);
 247     return 0;                   /* OK */
 248 }
 249 
 250 /* --------------------------------------------------------------------------------------------- */
 251 
 252 static const char *
 253 sfs_redirect (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 254 {
 255     GSList *cur;
 256     cachedfile *cf;
 257     vfs_path_t *cache_vpath;
 258     int handle;
 259 
 260     cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
 261 
 262     if (cur != NULL)
 263     {
 264         cf = (cachedfile *) cur->data;
 265         vfs_stamp (vfs_sfs_ops, cf);
 266         return cf->cache;
 267     }
 268 
 269     handle = vfs_mkstemps (&cache_vpath, "sfs", vfs_path_get_last_path_str (vpath));
 270 
 271     if (handle == -1)
 272         return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
 273 
 274     close (handle);
 275 
 276     if (sfs_vfmake (vpath, cache_vpath) == 0)
 277     {
 278         cf = g_new (cachedfile, 1);
 279         cf->name = g_strdup (vfs_path_as_str (vpath));
 280         cf->cache = vfs_path_free (cache_vpath, FALSE);
 281         head = g_slist_prepend (head, cf);
 282 
 283         vfs_stamp_create (vfs_sfs_ops, (cachedfile *) head->data);
 284         return cf->cache;
 285     }
 286 
 287     mc_unlink (cache_vpath);
 288     vfs_path_free (cache_vpath, TRUE);
 289     return "/I_MUST_NOT_EXIST";
 290 }
 291 
 292 /* --------------------------------------------------------------------------------------------- */
 293 
 294 static void *
 295 sfs_open (const vfs_path_t *vpath /*struct vfs_class *me, const char *path */ , int flags,
     /* [previous][next][first][last][top][bottom][index][help]  */
 296           mode_t mode)
 297 {
 298     int *info;
 299     int fd;
 300 
 301     fd = open (sfs_redirect (vpath), NO_LINEAR (flags), mode);
 302     if (fd == -1)
 303         return NULL;
 304 
 305     info = g_new (int, 1);
 306     *info = fd;
 307 
 308     return info;
 309 }
 310 
 311 /* --------------------------------------------------------------------------------------------- */
 312 
 313 static int
 314 sfs_stat (const vfs_path_t *vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 315 {
 316     return stat (sfs_redirect (vpath), buf);
 317 }
 318 
 319 /* --------------------------------------------------------------------------------------------- */
 320 
 321 static int
 322 sfs_lstat (const vfs_path_t *vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 323 {
 324 #ifndef HAVE_STATLSTAT
 325     return lstat (sfs_redirect (vpath), buf);
 326 #else
 327     return statlstat (sfs_redirect (vpath), buf);
 328 #endif
 329 }
 330 
 331 /* --------------------------------------------------------------------------------------------- */
 332 
 333 static int
 334 sfs_chmod (const vfs_path_t *vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 335 {
 336     return chmod (sfs_redirect (vpath), mode);
 337 }
 338 
 339 /* --------------------------------------------------------------------------------------------- */
 340 
 341 static int
 342 sfs_chown (const vfs_path_t *vpath, uid_t owner, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help]  */
 343 {
 344     return chown (sfs_redirect (vpath), owner, group);
 345 }
 346 
 347 /* --------------------------------------------------------------------------------------------- */
 348 
 349 static int
 350 sfs_utime (const vfs_path_t *vpath, mc_timesbuf_t *times)
     /* [previous][next][first][last][top][bottom][index][help]  */
 351 {
 352     return vfs_utime (sfs_redirect (vpath), times);
 353 }
 354 
 355 /* --------------------------------------------------------------------------------------------- */
 356 
 357 static int
 358 sfs_readlink (const vfs_path_t *vpath, char *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 359 {
 360     return readlink (sfs_redirect (vpath), buf, size);
 361 }
 362 
 363 /* --------------------------------------------------------------------------------------------- */
 364 
 365 static vfsid
 366 sfs_getid (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 367 {
 368     GSList *cur;
 369 
 370     cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
 371 
 372     return (vfsid) (cur != NULL ? cur->data : NULL);
 373 }
 374 
 375 /* --------------------------------------------------------------------------------------------- */
 376 
 377 static void
 378 sfs_free (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 379 {
 380     struct cachedfile *which;
 381     GSList *cur;
 382 
 383     which = (struct cachedfile *) id;
 384     cur = g_slist_find (head, which);
 385     if (cur == NULL)
 386         vfs_die ("Free of thing which is unknown to me\n");
 387 
 388     which = (struct cachedfile *) cur->data;
 389     unlink (which->cache);
 390     g_free (which->cache);
 391     g_free (which->name);
 392     g_free (which);
 393 
 394     head = g_slist_delete_link (head, cur);
 395 }
 396 
 397 /* --------------------------------------------------------------------------------------------- */
 398 
 399 static void
 400 sfs_fill_names (struct vfs_class *me, fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
 401 {
 402     GSList *cur;
 403 
 404     (void) me;
 405 
 406     for (cur = head; cur != NULL; cur = g_slist_next (cur))
 407         func (((cachedfile *) cur->data)->name);
 408 }
 409 
 410 /* --------------------------------------------------------------------------------------------- */
 411 
 412 static gboolean
 413 sfs_nothingisopen (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 414 {
 415     /* FIXME: Investigate whether have to guard this like in
 416        the other VFSs (see fd_usage in extfs) -- Norbert */
 417     (void) id;
 418     return TRUE;
 419 }
 420 
 421 /* --------------------------------------------------------------------------------------------- */
 422 
 423 static vfs_path_t *
 424 sfs_getlocalcopy (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 425 {
 426     return vfs_path_from_str (sfs_redirect (vpath));
 427 }
 428 
 429 /* --------------------------------------------------------------------------------------------- */
 430 
 431 static int
 432 sfs_ungetlocalcopy (const vfs_path_t *vpath, const vfs_path_t *local, gboolean has_changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
 433 {
 434     (void) vpath;
 435     (void) local;
 436     (void) has_changed;
 437     return 0;
 438 }
 439 
 440 /* --------------------------------------------------------------------------------------------- */
 441 
 442 static int
 443 sfs_init (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 444 {
 445     char *mc_sfsini;
 446     FILE *cfg;
 447     char key[256];
 448 
 449     (void) me;
 450 
 451     mc_sfsini = g_build_filename (mc_global.sysconfig_dir, "sfs.ini", (char *) NULL);
 452     cfg = fopen (mc_sfsini, "r");
 453 
 454     if (cfg == NULL)
 455     {
 456         fprintf (stderr, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini);
 457         g_free (mc_sfsini);
 458         return 0;
 459     }
 460     g_free (mc_sfsini);
 461 
 462     sfs_no = 0;
 463     while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg) != NULL)
 464     {
 465         char *c, *semi = NULL;
 466         sfs_flags_t flags = F_NONE;
 467 
 468         if (*key == '#' || *key == '\n')
 469             continue;
 470 
 471         for (c = key; *c != '\0'; c++)
 472             if (*c == ':' || IS_PATH_SEP (*c))
 473             {
 474                 semi = c;
 475                 if (IS_PATH_SEP (*c))
 476                 {
 477                     *c = '\0';
 478                     flags |= F_FULLMATCH;
 479                 }
 480                 break;
 481             }
 482 
 483         if (semi == NULL)
 484         {
 485           invalid_line:
 486             fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
 487             continue;
 488         }
 489 
 490         for (c = semi + 1; *c != '\0' && !whitespace (*c); c++)
 491             switch (*c)
 492             {
 493             case '1':
 494                 flags |= F_1;
 495                 break;
 496             case '2':
 497                 flags |= F_2;
 498                 break;
 499             case 'R':
 500                 flags |= F_NOLOCALCOPY;
 501                 break;
 502             default:
 503                 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
 504             }
 505 
 506         if (*c == '\0')
 507             goto invalid_line;
 508 
 509         c++;
 510         *(semi + 1) = '\0';
 511         semi = strchr (c, '\n');
 512         if (semi != NULL)
 513             *semi = '\0';
 514 
 515         sfs_info[sfs_no].prefix = g_strdup (key);
 516         sfs_info[sfs_no].command = g_strdup (c);
 517         sfs_info[sfs_no].flags = flags;
 518         sfs_no++;
 519     }
 520     fclose (cfg);
 521 
 522     return 1;
 523 }
 524 
 525 /* --------------------------------------------------------------------------------------------- */
 526 
 527 static void
 528 sfs_done (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 529 {
 530     int i;
 531 
 532     (void) me;
 533 
 534     for (i = 0; i < sfs_no; i++)
 535     {
 536         MC_PTR_FREE (sfs_info[i].prefix);
 537         MC_PTR_FREE (sfs_info[i].command);
 538     }
 539     sfs_no = 0;
 540 }
 541 
 542 /* --------------------------------------------------------------------------------------------- */
 543 
 544 static int
 545 sfs_which (struct vfs_class *me, const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 546 {
 547     int i;
 548 
 549     (void) me;
 550 
 551     for (i = 0; i < sfs_no; i++)
 552         if ((sfs_info[i].flags & F_FULLMATCH) != 0)
 553         {
 554             if (strcmp (path, sfs_info[i].prefix) == 0)
 555                 return i;
 556         }
 557         else if (strncmp (path, sfs_info[i].prefix, strlen (sfs_info[i].prefix)) == 0)
 558             return i;
 559 
 560     return (-1);
 561 }
 562 
 563 /* --------------------------------------------------------------------------------------------- */
 564 /*** public functions ****************************************************************************/
 565 /* --------------------------------------------------------------------------------------------- */
 566 
 567 void
 568 vfs_init_sfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 569 {
 570     /* NULLize vfs_s_subclass members */
 571     memset (&sfs_subclass, 0, sizeof (sfs_subclass));
 572 
 573     vfs_init_class (vfs_sfs_ops, "sfs", VFSF_UNKNOWN, NULL);
 574     vfs_sfs_ops->init = sfs_init;
 575     vfs_sfs_ops->done = sfs_done;
 576     vfs_sfs_ops->fill_names = sfs_fill_names;
 577     vfs_sfs_ops->which = sfs_which;
 578     vfs_sfs_ops->open = sfs_open;
 579     vfs_sfs_ops->close = local_close;
 580     vfs_sfs_ops->read = local_read;
 581     vfs_sfs_ops->stat = sfs_stat;
 582     vfs_sfs_ops->lstat = sfs_lstat;
 583     vfs_sfs_ops->fstat = local_fstat;
 584     vfs_sfs_ops->chmod = sfs_chmod;
 585     vfs_sfs_ops->chown = sfs_chown;
 586     vfs_sfs_ops->utime = sfs_utime;
 587     vfs_sfs_ops->readlink = sfs_readlink;
 588     vfs_sfs_ops->ferrno = local_errno;
 589     vfs_sfs_ops->lseek = local_lseek;
 590     vfs_sfs_ops->getid = sfs_getid;
 591     vfs_sfs_ops->nothingisopen = sfs_nothingisopen;
 592     vfs_sfs_ops->free = sfs_free;
 593     vfs_sfs_ops->getlocalcopy = sfs_getlocalcopy;
 594     vfs_sfs_ops->ungetlocalcopy = sfs_ungetlocalcopy;
 595     vfs_register_class (vfs_sfs_ops);
 596 }
 597 
 598 /* --------------------------------------------------------------------------------------------- */

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