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

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