Following prototypes of functions was changed in VFS-module API:
[midnight-commander.git] / src / vfs / sfs / sfs.c
blob1b1b83c860dfc4f14aefd3ed4c005dc250dd67f5
1 /*
2 * Single File fileSystem
4 * Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
5 * Free Software Foundation, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /**
23 * \file
24 * \brief Source: Single File fileSystem
26 * This defines whole class of filesystems which contain single file
27 * inside. It is somehow similar to extfs, except that extfs makes
28 * whole virtual trees and we do only single virtual files.
30 * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
31 * suffix, DON'T try to gunzip it yourself.
33 * Namespace: exports vfs_sfs_ops
36 #include <config.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <fcntl.h>
44 #include "lib/global.h"
45 #include "lib/util.h"
46 #include "lib/widget.h" /* D_ERROR, D_NORMAL */
48 #include "src/execute.h" /* EXECUTE_AS_SHELL */
50 #include "lib/vfs/vfs.h"
51 #include "lib/vfs/utilvfs.h"
52 #include "src/vfs/local/local.h"
53 #include "lib/vfs/gc.h" /* vfs_stamp_create */
55 #include "sfs.h"
57 /*** global variables ****************************************************************************/
59 /*** file scope macro definitions ****************************************************************/
61 #define MAXFS 32
63 #define F_1 1
64 #define F_2 2
65 #define F_NOLOCALCOPY 4
66 #define F_FULLMATCH 8
68 #define COPY_CHAR \
69 if ((size_t) (t - pad) > sizeof(pad)) \
70 { \
71 g_free (pqname); \
72 return -1; \
73 } \
74 else \
75 *t++ = *s;
77 #define COPY_STRING(a) \
78 if ((t - pad) + strlen(a) > sizeof(pad)) \
79 { \
80 g_free (pqname); \
81 return -1; \
82 } \
83 else \
84 { \
85 strcpy (t, a); \
86 t += strlen (a); \
89 /*** file scope type declarations ****************************************************************/
91 typedef struct cachedfile
93 char *name;
94 char *cache;
95 } cachedfile;
97 /*** file scope variables ************************************************************************/
99 static GSList *head;
100 static struct vfs_class vfs_sfs_ops;
102 static int sfs_no = 0;
103 static char *sfs_prefix[MAXFS];
104 static char *sfs_command[MAXFS];
105 static int sfs_flags[MAXFS];
107 /*** file scope functions ************************************************************************/
109 static int
110 cachedfile_compare (const void *a, const void *b)
112 const cachedfile *cf = (const cachedfile *) a;
113 const char *name = (const char *) b;
115 return strcmp (name, cf->name);
118 /* --------------------------------------------------------------------------------------------- */
120 static int
121 sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
123 char *inpath, *op;
124 int w;
125 char pad[10240];
126 char *s, *t = pad;
127 int was_percent = 0;
128 char *pname; /* name of parent archive */
129 char *pqname; /* name of parent archive, quoted */
131 pname = g_strdup (name);
132 vfs_split (pname, &inpath, &op);
133 w = (*me->which) (me, op);
134 if (w == -1)
135 vfs_die ("This cannot happen... Hopefully.\n");
137 if (!(sfs_flags[w] & F_1) && strcmp (pname, "/"))
139 g_free (pname);
140 return -1;
143 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
144 if (!(sfs_flags[w] & F_NOLOCALCOPY))
146 s = mc_getlocalcopy (pname);
147 if (!s)
149 g_free (pname);
150 return -1;
152 pqname = name_quote (s, 0);
153 g_free (s);
155 else
157 pqname = name_quote (pname, 0);
159 g_free (pname);
162 for (s = sfs_command[w]; *s; s++)
164 if (was_percent)
167 const char *ptr = NULL;
168 was_percent = 0;
170 switch (*s)
172 case '1':
173 ptr = pqname;
174 break;
175 case '2':
176 ptr = op + strlen (sfs_prefix[w]);
177 break;
178 case '3':
179 ptr = cache;
180 break;
181 case '%':
182 COPY_CHAR;
183 continue;
185 COPY_STRING (ptr);
187 else
189 if (*s == '%')
190 was_percent = 1;
191 else
192 COPY_CHAR;
196 g_free (pqname);
197 open_error_pipe ();
198 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad))
200 close_error_pipe (D_ERROR, NULL);
201 return -1;
204 close_error_pipe (D_NORMAL, NULL);
205 return 0; /* OK */
208 /* --------------------------------------------------------------------------------------------- */
210 static const char *
211 sfs_redirect (struct vfs_class *me, const char *name)
213 GSList *cur;
214 cachedfile *cf;
215 char *cache;
216 int handle;
218 cur = g_slist_find_custom (head, name, cachedfile_compare);
219 if (cur != NULL)
221 cf = (cachedfile *) cur->data;
222 vfs_stamp (&vfs_sfs_ops, cf);
223 return cf->cache;
226 handle = vfs_mkstemps (&cache, "sfs", name);
228 if (handle == -1)
229 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
231 close (handle);
233 if (sfs_vfmake (me, name, cache) == 0)
235 cf = g_new (cachedfile, 1);
236 cf->name = g_strdup (name);
237 cf->cache = cache;
238 head = g_slist_prepend (head, cf);
240 vfs_stamp_create (&vfs_sfs_ops, (cachedfile *) head->data);
241 return cache;
244 unlink (cache);
245 g_free (cache);
246 return "/I_MUST_NOT_EXIST";
249 /* --------------------------------------------------------------------------------------------- */
251 static void *
252 sfs_open (const vfs_path_t * vpath /*struct vfs_class *me, const char *path */ , int flags,
253 mode_t mode)
255 int *sfs_info;
256 int fd;
257 const char *path;
258 vfs_path_element_t *path_element;
260 path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
261 path = sfs_redirect (path_element->class, vpath->unparsed);
262 fd = open (path, NO_LINEAR (flags), mode);
263 if (fd == -1)
264 return 0;
266 sfs_info = g_new (int, 1);
267 *sfs_info = fd;
269 return sfs_info;
272 /* --------------------------------------------------------------------------------------------- */
274 static int
275 sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
277 path = sfs_redirect (me, path);
278 return stat (path, buf);
281 /* --------------------------------------------------------------------------------------------- */
283 static int
284 sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
286 path = sfs_redirect (me, path);
287 #ifndef HAVE_STATLSTAT
288 return lstat (path, buf);
289 #else
290 return statlstat (path, buf);
291 #endif
294 /* --------------------------------------------------------------------------------------------- */
296 static int
297 sfs_chmod (struct vfs_class *me, const char *path, int mode)
299 path = sfs_redirect (me, path);
300 return chmod (path, mode);
303 /* --------------------------------------------------------------------------------------------- */
305 static int
306 sfs_chown (struct vfs_class *me, const char *path, uid_t owner, gid_t group)
308 path = sfs_redirect (me, path);
309 return chown (path, owner, group);
312 /* --------------------------------------------------------------------------------------------- */
314 static int
315 sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
317 path = sfs_redirect (me, path);
318 return utime (path, times);
321 /* --------------------------------------------------------------------------------------------- */
323 static int
324 sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
326 path = sfs_redirect (me, path);
327 return readlink (path, buf, size);
330 /* --------------------------------------------------------------------------------------------- */
332 static vfsid
333 sfs_getid (struct vfs_class *me, const char *path)
335 GSList *cur;
337 (void) me;
339 cur = g_slist_find_custom (head, path, cachedfile_compare);
341 return (vfsid) (cur != NULL ? cur->data : NULL);
344 /* --------------------------------------------------------------------------------------------- */
346 static void
347 sfs_free (vfsid id)
349 struct cachedfile *which;
350 GSList *cur;
352 which = (struct cachedfile *) id;
353 cur = g_slist_find (head, which);
354 if (cur == NULL)
355 vfs_die ("Free of thing which is unknown to me\n");
357 which = (struct cachedfile *) cur->data;
358 unlink (which->cache);
359 g_free (which->cache);
360 g_free (which->name);
361 g_free (which);
363 head = g_slist_delete_link (head, cur);
366 /* --------------------------------------------------------------------------------------------- */
368 static void
369 sfs_fill_names (struct vfs_class *me, fill_names_f func)
371 GSList *cur;
373 (void) me;
375 for (cur = head; cur != NULL; cur = g_slist_next (cur))
376 func (((cachedfile *) cur->data)->name);
379 /* --------------------------------------------------------------------------------------------- */
381 static int
382 sfs_nothingisopen (vfsid id)
384 /* FIXME: Investigate whether have to guard this like in
385 the other VFSs (see fd_usage in extfs) -- Norbert */
386 (void) id;
387 return 1;
390 /* --------------------------------------------------------------------------------------------- */
392 static char *
393 sfs_getlocalcopy (const vfs_path_t * vpath)
395 vfs_path_element_t *path_element;
396 const char *path;
398 path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
399 path = sfs_redirect (path_element->class, vpath->unparsed);
400 return g_strdup (path);
403 /* --------------------------------------------------------------------------------------------- */
405 static int
406 sfs_ungetlocalcopy (const vfs_path_t * vpath, const char *local, int has_changed)
408 (void) vpath;
409 (void) local;
410 (void) has_changed;
411 return 0;
414 /* --------------------------------------------------------------------------------------------- */
416 static int
417 sfs_init (struct vfs_class *me)
419 char *mc_sfsini;
420 FILE *cfg;
421 char key[256];
423 (void) me;
425 mc_sfsini = g_build_filename (mc_global.sysconfig_dir, "sfs.ini", (char *) NULL);
426 cfg = fopen (mc_sfsini, "r");
428 if (cfg == NULL)
430 fprintf (stderr, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini);
431 g_free (mc_sfsini);
432 return 0;
434 g_free (mc_sfsini);
436 sfs_no = 0;
437 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg))
439 char *c, *semi = NULL, flags = 0;
441 if (*key == '#' || *key == '\n')
442 continue;
444 for (c = key; *c; c++)
445 if ((*c == ':') || (*c == '/'))
447 semi = c;
448 if (*c == '/')
450 *c = 0;
451 flags |= F_FULLMATCH;
453 break;
456 if (!semi)
458 invalid_line:
459 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
460 continue;
463 c = semi + 1;
464 while (*c && (*c != ' ') && (*c != '\t'))
466 switch (*c)
468 case '1':
469 flags |= F_1;
470 break;
471 case '2':
472 flags |= F_2;
473 break;
474 case 'R':
475 flags |= F_NOLOCALCOPY;
476 break;
477 default:
478 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
480 c++;
482 if (!*c)
483 goto invalid_line;
485 c++;
486 *(semi + 1) = 0;
487 semi = strchr (c, '\n');
488 if (semi != NULL)
489 *semi = 0;
491 sfs_prefix[sfs_no] = g_strdup (key);
492 sfs_command[sfs_no] = g_strdup (c);
493 sfs_flags[sfs_no] = flags;
494 sfs_no++;
496 fclose (cfg);
497 return 1;
500 /* --------------------------------------------------------------------------------------------- */
502 static void
503 sfs_done (struct vfs_class *me)
505 int i;
507 (void) me;
509 for (i = 0; i < sfs_no; i++)
511 g_free (sfs_prefix[i]);
512 g_free (sfs_command[i]);
513 sfs_prefix[i] = sfs_command[i] = NULL;
515 sfs_no = 0;
518 /* --------------------------------------------------------------------------------------------- */
520 static int
521 sfs_which (struct vfs_class *me, const char *path)
523 int i;
525 (void) me;
527 for (i = 0; i < sfs_no; i++)
528 if (sfs_flags[i] & F_FULLMATCH)
530 if (!strcmp (path, sfs_prefix[i]))
531 return i;
533 else if (!strncmp (path, sfs_prefix[i], strlen (sfs_prefix[i])))
534 return i;
536 return -1;
539 /* --------------------------------------------------------------------------------------------- */
540 /*** public functions ****************************************************************************/
541 /* --------------------------------------------------------------------------------------------- */
543 void
544 init_sfs (void)
546 vfs_sfs_ops.name = "sfs";
547 vfs_sfs_ops.init = sfs_init;
548 vfs_sfs_ops.done = sfs_done;
549 vfs_sfs_ops.fill_names = sfs_fill_names;
550 vfs_sfs_ops.which = sfs_which;
551 vfs_sfs_ops.open = sfs_open;
552 vfs_sfs_ops.close = local_close;
553 vfs_sfs_ops.read = local_read;
554 vfs_sfs_ops.stat = sfs_stat;
555 vfs_sfs_ops.lstat = sfs_lstat;
556 vfs_sfs_ops.fstat = local_fstat;
557 vfs_sfs_ops.chmod = sfs_chmod;
558 vfs_sfs_ops.chown = sfs_chown;
559 vfs_sfs_ops.utime = sfs_utime;
560 vfs_sfs_ops.readlink = sfs_readlink;
561 vfs_sfs_ops.ferrno = local_errno;
562 vfs_sfs_ops.lseek = local_lseek;
563 vfs_sfs_ops.getid = sfs_getid;
564 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
565 vfs_sfs_ops.free = sfs_free;
566 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
567 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
568 vfs_register_class (&vfs_sfs_ops);
571 /* --------------------------------------------------------------------------------------------- */