Ticket #2361: VFS URI reimplementation
[midnight-commander.git] / src / vfs / sfs / sfs.c
blob9055abe67729c96e8bfdc62ab33fe74e6391b2c6
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 (const vfs_path_t * vpath, char *cache)
123 int w;
124 char pad[10240];
125 char *s, *t = pad;
126 int was_percent = 0;
127 char *pname; /* name of parent archive */
128 char *pqname; /* name of parent archive, quoted */
129 vfs_path_element_t *path_element;
131 path_element = vfs_path_get_by_index (vpath, -1);
132 pname = vfs_path_to_str_elements_count (vpath, -1);
133 w = (*path_element->class->which) (path_element->class, path_element->vfs_prefix);
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 = path_element->path;
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 (const vfs_path_t * vpath)
213 GSList *cur;
214 cachedfile *cf;
215 char *cache;
216 int handle;
217 vfs_path_element_t *path_element;
218 char *path = vfs_path_to_str (vpath);
220 path_element = vfs_path_get_by_index (vpath, -1);
221 cur = g_slist_find_custom (head, path, cachedfile_compare);
222 g_free (path);
224 if (cur != NULL)
226 cf = (cachedfile *) cur->data;
227 vfs_stamp (&vfs_sfs_ops, cf);
228 return cf->cache;
231 handle = vfs_mkstemps (&cache, "sfs", path_element->path);
233 if (handle == -1)
234 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
236 close (handle);
238 if (sfs_vfmake (vpath, cache) == 0)
240 cf = g_new (cachedfile, 1);
241 cf->name = vfs_path_to_str (vpath);
242 cf->cache = cache;
243 head = g_slist_prepend (head, cf);
245 vfs_stamp_create (&vfs_sfs_ops, (cachedfile *) head->data);
246 return cache;
249 unlink (cache);
250 g_free (cache);
251 return "/I_MUST_NOT_EXIST";
254 /* --------------------------------------------------------------------------------------------- */
256 static void *
257 sfs_open (const vfs_path_t * vpath /*struct vfs_class *me, const char *path */ , int flags,
258 mode_t mode)
260 int *sfs_info;
261 int fd;
263 fd = open (sfs_redirect (vpath), NO_LINEAR (flags), mode);
264 if (fd == -1)
265 return 0;
267 sfs_info = g_new (int, 1);
268 *sfs_info = fd;
270 return sfs_info;
273 /* --------------------------------------------------------------------------------------------- */
275 static int
276 sfs_stat (const vfs_path_t * vpath, struct stat *buf)
278 return stat (sfs_redirect (vpath), buf);
281 /* --------------------------------------------------------------------------------------------- */
283 static int
284 sfs_lstat (const vfs_path_t * vpath, struct stat *buf)
286 #ifndef HAVE_STATLSTAT
287 return lstat (sfs_redirect (vpath), buf);
288 #else
289 return statlstat (sfs_redirect (vpath), buf);
290 #endif
293 /* --------------------------------------------------------------------------------------------- */
295 static int
296 sfs_chmod (const vfs_path_t * vpath, mode_t mode)
298 return chmod (sfs_redirect (vpath), mode);
301 /* --------------------------------------------------------------------------------------------- */
303 static int
304 sfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
306 return chown (sfs_redirect (vpath), owner, group);
309 /* --------------------------------------------------------------------------------------------- */
311 static int
312 sfs_utime (const vfs_path_t * vpath, struct utimbuf *times)
314 return utime (sfs_redirect (vpath), times);
317 /* --------------------------------------------------------------------------------------------- */
319 static int
320 sfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
322 return readlink (sfs_redirect (vpath), buf, size);
325 /* --------------------------------------------------------------------------------------------- */
327 static vfsid
328 sfs_getid (const vfs_path_t * vpath)
330 GSList *cur;
331 char *path = vfs_path_to_str (vpath);
333 cur = g_slist_find_custom (head, path, cachedfile_compare);
334 g_free (path);
336 return (vfsid) (cur != NULL ? cur->data : NULL);
339 /* --------------------------------------------------------------------------------------------- */
341 static void
342 sfs_free (vfsid id)
344 struct cachedfile *which;
345 GSList *cur;
347 which = (struct cachedfile *) id;
348 cur = g_slist_find (head, which);
349 if (cur == NULL)
350 vfs_die ("Free of thing which is unknown to me\n");
352 which = (struct cachedfile *) cur->data;
353 unlink (which->cache);
354 g_free (which->cache);
355 g_free (which->name);
356 g_free (which);
358 head = g_slist_delete_link (head, cur);
361 /* --------------------------------------------------------------------------------------------- */
363 static void
364 sfs_fill_names (struct vfs_class *me, fill_names_f func)
366 GSList *cur;
368 (void) me;
370 for (cur = head; cur != NULL; cur = g_slist_next (cur))
371 func (((cachedfile *) cur->data)->name);
374 /* --------------------------------------------------------------------------------------------- */
376 static int
377 sfs_nothingisopen (vfsid id)
379 /* FIXME: Investigate whether have to guard this like in
380 the other VFSs (see fd_usage in extfs) -- Norbert */
381 (void) id;
382 return 1;
385 /* --------------------------------------------------------------------------------------------- */
387 static char *
388 sfs_getlocalcopy (const vfs_path_t * vpath)
390 return g_strdup (sfs_redirect (vpath));
393 /* --------------------------------------------------------------------------------------------- */
395 static int
396 sfs_ungetlocalcopy (const vfs_path_t * vpath, const char *local, int has_changed)
398 (void) vpath;
399 (void) local;
400 (void) has_changed;
401 return 0;
404 /* --------------------------------------------------------------------------------------------- */
406 static int
407 sfs_init (struct vfs_class *me)
409 char *mc_sfsini;
410 FILE *cfg;
411 char key[256];
413 (void) me;
415 mc_sfsini = g_build_filename (mc_global.sysconfig_dir, "sfs.ini", (char *) NULL);
416 cfg = fopen (mc_sfsini, "r");
418 if (cfg == NULL)
420 fprintf (stderr, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini);
421 g_free (mc_sfsini);
422 return 0;
424 g_free (mc_sfsini);
426 sfs_no = 0;
427 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg))
429 char *c, *semi = NULL, flags = 0;
431 if (*key == '#' || *key == '\n')
432 continue;
434 for (c = key; *c; c++)
435 if ((*c == ':') || (*c == '/'))
437 semi = c;
438 if (*c == '/')
440 *c = 0;
441 flags |= F_FULLMATCH;
443 break;
446 if (!semi)
448 invalid_line:
449 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
450 continue;
453 c = semi + 1;
454 while (*c && (*c != ' ') && (*c != '\t'))
456 switch (*c)
458 case '1':
459 flags |= F_1;
460 break;
461 case '2':
462 flags |= F_2;
463 break;
464 case 'R':
465 flags |= F_NOLOCALCOPY;
466 break;
467 default:
468 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
470 c++;
472 if (!*c)
473 goto invalid_line;
475 c++;
476 *(semi + 1) = 0;
477 semi = strchr (c, '\n');
478 if (semi != NULL)
479 *semi = 0;
481 sfs_prefix[sfs_no] = g_strdup (key);
482 sfs_command[sfs_no] = g_strdup (c);
483 sfs_flags[sfs_no] = flags;
484 sfs_no++;
486 fclose (cfg);
487 return 1;
490 /* --------------------------------------------------------------------------------------------- */
492 static void
493 sfs_done (struct vfs_class *me)
495 int i;
497 (void) me;
499 for (i = 0; i < sfs_no; i++)
501 g_free (sfs_prefix[i]);
502 g_free (sfs_command[i]);
503 sfs_prefix[i] = sfs_command[i] = NULL;
505 sfs_no = 0;
508 /* --------------------------------------------------------------------------------------------- */
510 static int
511 sfs_which (struct vfs_class *me, const char *path)
513 int i;
515 (void) me;
517 for (i = 0; i < sfs_no; i++)
518 if (sfs_flags[i] & F_FULLMATCH)
520 if (!strcmp (path, sfs_prefix[i]))
521 return i;
523 else if (!strncmp (path, sfs_prefix[i], strlen (sfs_prefix[i])))
524 return i;
526 return -1;
529 /* --------------------------------------------------------------------------------------------- */
530 /*** public functions ****************************************************************************/
531 /* --------------------------------------------------------------------------------------------- */
533 void
534 init_sfs (void)
536 vfs_sfs_ops.name = "sfs";
537 vfs_sfs_ops.init = sfs_init;
538 vfs_sfs_ops.done = sfs_done;
539 vfs_sfs_ops.fill_names = sfs_fill_names;
540 vfs_sfs_ops.which = sfs_which;
541 vfs_sfs_ops.open = sfs_open;
542 vfs_sfs_ops.close = local_close;
543 vfs_sfs_ops.read = local_read;
544 vfs_sfs_ops.stat = sfs_stat;
545 vfs_sfs_ops.lstat = sfs_lstat;
546 vfs_sfs_ops.fstat = local_fstat;
547 vfs_sfs_ops.chmod = sfs_chmod;
548 vfs_sfs_ops.chown = sfs_chown;
549 vfs_sfs_ops.utime = sfs_utime;
550 vfs_sfs_ops.readlink = sfs_readlink;
551 vfs_sfs_ops.ferrno = local_errno;
552 vfs_sfs_ops.lseek = local_lseek;
553 vfs_sfs_ops.getid = sfs_getid;
554 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
555 vfs_sfs_ops.free = sfs_free;
556 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
557 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
558 vfs_register_class (&vfs_sfs_ops);
561 /* --------------------------------------------------------------------------------------------- */