123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- /*
- * Single File fileSystem
- *
- * Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- /**
- * \file
- * \brief Source: Single File fileSystem
- *
- * This defines whole class of filesystems which contain single file
- * inside. It is somehow similar to extfs, except that extfs makes
- * whole virtual trees and we do only single virtual files.
- *
- * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
- * suffix, DON'T try to gunzip it yourself.
- *
- * Namespace: exports vfs_sfs_ops
- */
- #include <config.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <string.h>
- #include <fcntl.h>
- #include "lib/global.h"
- #include "src/wtools.h" /* message() */
- #include "src/main.h" /* print_vfs_message */
- #include "src/execute.h" /* EXECUTE_AS_SHELL */
- #include "utilvfs.h"
- #include "vfs.h"
- #include "vfs-impl.h"
- #include "gc.h" /* vfs_stamp_create */
- #include "local.h"
- struct cachedfile {
- char *name, *cache;
- struct cachedfile *next;
- };
- static struct cachedfile *head;
- static struct vfs_class vfs_sfs_ops;
- #define MAXFS 32
- static int sfs_no = 0;
- static char *sfs_prefix[ MAXFS ];
- static char *sfs_command[ MAXFS ];
- static int sfs_flags[ MAXFS ];
- #define F_1 1
- #define F_2 2
- #define F_NOLOCALCOPY 4
- #define F_FULLMATCH 8
- static int
- sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
- {
- char *inpath, *op;
- int w;
- char pad[10240];
- char *s, *t = pad;
- int was_percent = 0;
- char *pname; /* name of parent archive */
- char *pqname; /* name of parent archive, quoted */
- pname = g_strdup (name);
- vfs_split (pname, &inpath, &op);
- w = (*me->which) (me, op);
- if (w == -1)
- vfs_die ("This cannot happen... Hopefully.\n");
- if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) {
- g_free (pname);
- return -1;
- }
- /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
- if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
- s = mc_getlocalcopy (pname);
- if (!s) {
- g_free (pname);
- return -1;
- }
- pqname = name_quote (s, 0);
- g_free (s);
- } else {
- pqname = name_quote (pname, 0);
- }
- g_free (pname);
- #define COPY_CHAR \
- if ((size_t) (t-pad) > sizeof(pad)) { \
- g_free (pqname); \
- return -1; \
- } \
- else \
- *t++ = *s;
- #define COPY_STRING(a) \
- if ((t-pad)+strlen(a)>sizeof(pad)) { \
- g_free (pqname); \
- return -1; \
- } else { \
- strcpy (t, a); \
- t+= strlen(a); \
- }
- for (s = sfs_command[w]; *s; s++) {
- if (was_percent) {
- const char *ptr = NULL;
- was_percent = 0;
- switch (*s) {
- case '1':
- ptr = pqname;
- break;
- case '2':
- ptr = op + strlen (sfs_prefix[w]);
- break;
- case '3':
- ptr = cache;
- break;
- case '%':
- COPY_CHAR;
- continue;
- }
- COPY_STRING (ptr);
- } else {
- if (*s == '%')
- was_percent = 1;
- else
- COPY_CHAR;
- }
- }
- g_free (pqname);
- open_error_pipe ();
- if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
- close_error_pipe (D_ERROR, NULL);
- return -1;
- }
- close_error_pipe (D_NORMAL, NULL);
- return 0; /* OK */
- }
- static const char *
- sfs_redirect (struct vfs_class *me, const char *name)
- {
- struct cachedfile *cur = head;
- char *cache;
- int handle;
- while (cur) {
- if (!strcmp (name, cur->name)) {
- vfs_stamp (&vfs_sfs_ops, cur);
- return cur->cache;
- }
- cur = cur->next;
- }
- handle = vfs_mkstemps (&cache, "sfs", name);
- if (handle == -1) {
- return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
- }
- close (handle);
- if (!sfs_vfmake (me, name, cache)) {
- cur = g_new (struct cachedfile, 1);
- cur->name = g_strdup (name);
- cur->cache = cache;
- cur->next = head;
- head = cur;
- vfs_stamp_create (&vfs_sfs_ops, head);
- return cache;
- }
- unlink (cache);
- g_free (cache);
- return "/I_MUST_NOT_EXIST";
- }
- static void *
- sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
- {
- int *sfs_info;
- int fd;
- path = sfs_redirect (me, path);
- fd = open (path, NO_LINEAR (flags), mode);
- if (fd == -1)
- return 0;
- sfs_info = g_new (int, 1);
- *sfs_info = fd;
- return sfs_info;
- }
- static int sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
- {
- path = sfs_redirect (me, path);
- return stat (path, buf);
- }
- static int sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
- {
- path = sfs_redirect (me, path);
- #ifndef HAVE_STATLSTAT
- return lstat (path, buf);
- #else
- return statlstat (path, buf);
- #endif
- }
- static int sfs_chmod (struct vfs_class *me, const char *path, int mode)
- {
- path = sfs_redirect (me, path);
- return chmod (path, mode);
- }
- static int sfs_chown (struct vfs_class *me, const char *path, int owner, int group)
- {
- path = sfs_redirect (me, path);
- return chown (path, owner, group);
- }
- static int sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
- {
- path = sfs_redirect (me, path);
- return utime (path, times);
- }
- static int
- sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
- {
- path = sfs_redirect (me, path);
- return readlink (path, buf, size);
- }
- static vfsid
- sfs_getid (struct vfs_class *me, const char *path)
- {
- struct cachedfile *cur = head;
- (void) me;
- while (cur) {
- if (!strcmp (path, cur->name))
- break;
- cur = cur->next;
- }
- return (vfsid) cur;
- }
- static void sfs_free (vfsid id)
- {
- struct cachedfile *which = (struct cachedfile *) id;
- struct cachedfile *cur, *prev;
- for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
- ;
- if (!cur)
- vfs_die( "Free of thing which is unknown to me\n" );
- unlink (cur->cache);
- if (prev)
- prev->next = cur->next;
- else
- head = cur->next;
- g_free (cur->cache);
- g_free (cur->name);
- g_free (cur);
- }
- static void sfs_fill_names (struct vfs_class *me, fill_names_f func)
- {
- struct cachedfile *cur = head;
- (void) me;
- while (cur){
- (*func)(cur->name);
- cur = cur->next;
- }
- }
- static int sfs_nothingisopen (vfsid id)
- {
- /* FIXME: Investigate whether have to guard this like in
- the other VFSs (see fd_usage in extfs) -- Norbert */
- (void) id;
- return 1;
- }
- static char *
- sfs_getlocalcopy (struct vfs_class *me, const char *path)
- {
- path = sfs_redirect (me, path);
- return g_strdup (path);
- }
- static int
- sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
- const char *local, int has_changed)
- {
- (void) me;
- (void) path;
- (void) local;
- (void) has_changed;
- return 0;
- }
- static int sfs_init (struct vfs_class *me)
- {
- char *mc_sfsini;
- FILE *cfg;
- char key[256];
- (void) me;
- mc_sfsini = g_build_filename (mc_home, "sfs.ini", (char *) NULL);
- cfg = fopen (mc_sfsini, "r");
- if (cfg == NULL) {
- fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
- g_free (mc_sfsini);
- return 0;
- }
- g_free (mc_sfsini);
- sfs_no = 0;
- while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg)) {
- char *c, *semi = NULL, flags = 0;
- if (*key == '#' || *key == '\n')
- continue;
- for (c = key; *c; c++)
- if ((*c == ':') || (*c == '/')){
- semi = c;
- if (*c == '/'){
- *c = 0;
- flags |= F_FULLMATCH;
- }
- break;
- }
- if (!semi){
- invalid_line:
- fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
- "sfs.ini", key);
- continue;
- }
- c = semi + 1;
- while (*c && (*c != ' ') && (*c != '\t')) {
- switch (*c) {
- case '1': flags |= F_1; break;
- case '2': flags |= F_2; break;
- case 'R': flags |= F_NOLOCALCOPY; break;
- default:
- fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
- *c, "sfs.ini", key);
- }
- c++;
- }
- if (!*c)
- goto invalid_line;
- c++;
- *(semi+1) = 0;
- semi = strchr (c, '\n');
- if (semi != NULL)
- *semi = 0;
- sfs_prefix [sfs_no] = g_strdup (key);
- sfs_command [sfs_no] = g_strdup (c);
- sfs_flags [sfs_no] = flags;
- sfs_no++;
- }
- fclose (cfg);
- return 1;
- }
- static void
- sfs_done (struct vfs_class *me)
- {
- int i;
- (void) me;
- for (i = 0; i < sfs_no; i++){
- g_free (sfs_prefix [i]);
- g_free (sfs_command [i]);
- sfs_prefix [i] = sfs_command [i] = NULL;
- }
- sfs_no = 0;
- }
- static int
- sfs_which (struct vfs_class *me, const char *path)
- {
- int i;
- (void) me;
- for (i = 0; i < sfs_no; i++)
- if (sfs_flags [i] & F_FULLMATCH) {
- if (!strcmp (path, sfs_prefix [i]))
- return i;
- } else
- if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
- return i;
- return -1;
- }
- void
- init_sfs (void)
- {
- vfs_sfs_ops.name = "sfs";
- vfs_sfs_ops.init = sfs_init;
- vfs_sfs_ops.done = sfs_done;
- vfs_sfs_ops.fill_names = sfs_fill_names;
- vfs_sfs_ops.which = sfs_which;
- vfs_sfs_ops.open = sfs_open;
- vfs_sfs_ops.close = local_close;
- vfs_sfs_ops.read = local_read;
- vfs_sfs_ops.stat = sfs_stat;
- vfs_sfs_ops.lstat = sfs_lstat;
- vfs_sfs_ops.fstat = local_fstat;
- vfs_sfs_ops.chmod = sfs_chmod;
- vfs_sfs_ops.chown = sfs_chown;
- vfs_sfs_ops.utime = sfs_utime;
- vfs_sfs_ops.readlink = sfs_readlink;
- vfs_sfs_ops.ferrno = local_errno;
- vfs_sfs_ops.lseek = local_lseek;
- vfs_sfs_ops.getid = sfs_getid;
- vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
- vfs_sfs_ops.free = sfs_free;
- vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
- vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
- vfs_register_class (&vfs_sfs_ops);
- }
|