2008-04-09 Marco Ciampa <ciampix@libero.it>
[midnight-commander.git] / vfs / sfs.c
blobf4989ca300fc32988ed90093c32a65931aa93449
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.
21 * This defines whole class of filesystems which contain single file
22 * inside. It is somehow similar to extfs, except that extfs makes
23 * whole virtual trees and we do only single virtual files.
25 * If you want to gunzip something, you should open it with #ugz
26 * suffix, DON'T try to gunzip it yourself.
28 * Namespace: exports vfs_sfs_ops */
30 #include <config.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <string.h>
37 #include "../src/global.h"
38 #include "../src/tty.h" /* enable/disable interrupt key */
39 #include "../src/wtools.h" /* message() */
40 #include "../src/main.h" /* print_vfs_message */
41 #include "utilvfs.h"
42 #include "vfs.h"
43 #include "vfs-impl.h"
44 #include "gc.h" /* vfs_stamp_create */
45 #include "local.h"
46 #include "../src/execute.h" /* EXECUTE_AS_SHELL */
48 struct cachedfile {
49 char *name, *cache;
50 struct cachedfile *next;
53 static struct cachedfile *head;
54 static struct vfs_class vfs_sfs_ops;
56 #define MAXFS 32
57 static int sfs_no = 0;
58 static char *sfs_prefix[ MAXFS ];
59 static char *sfs_command[ MAXFS ];
60 static int sfs_flags[ MAXFS ];
61 #define F_1 1
62 #define F_2 2
63 #define F_NOLOCALCOPY 4
64 #define F_FULLMATCH 8
66 static int
67 sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
69 char *inpath, *op;
70 int w;
71 char pad[10240];
72 char *s, *t = pad;
73 int was_percent = 0;
74 char *pname; /* name of parent archive */
75 char *pqname; /* name of parent archive, quoted */
77 pname = g_strdup (name);
78 vfs_split (pname, &inpath, &op);
79 if ((w = (*me->which) (me, op)) == -1)
80 vfs_die ("This cannot happen... Hopefully.\n");
82 if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) {
83 g_free (pname);
84 return -1;
87 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
88 if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
89 s = mc_getlocalcopy (pname);
90 if (!s) {
91 g_free (pname);
92 return -1;
94 pqname = name_quote (s, 0);
95 g_free (s);
96 } else {
97 pqname = name_quote (pname, 0);
99 g_free (pname);
101 #define COPY_CHAR \
102 if ((size_t) (t-pad) > sizeof(pad)) { \
103 g_free (pqname); \
104 return -1; \
106 else \
107 *t++ = *s;
109 #define COPY_STRING(a) \
110 if ((t-pad)+strlen(a)>sizeof(pad)) { \
111 g_free (pqname); \
112 return -1; \
113 } else { \
114 strcpy (t, a); \
115 t+= strlen(a); \
118 for (s = sfs_command[w]; *s; s++) {
119 if (was_percent) {
121 const char *ptr = NULL;
122 was_percent = 0;
124 switch (*s) {
125 case '1':
126 ptr = pqname;
127 break;
128 case '2':
129 ptr = op + strlen (sfs_prefix[w]);
130 break;
131 case '3':
132 ptr = cache;
133 break;
134 case '%':
135 COPY_CHAR;
136 continue;
138 COPY_STRING (ptr);
139 } else {
140 if (*s == '%')
141 was_percent = 1;
142 else
143 COPY_CHAR;
147 g_free (pqname);
148 open_error_pipe ();
149 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
150 close_error_pipe (1, NULL);
151 return -1;
154 close_error_pipe (0, NULL);
155 return 0; /* OK */
158 static const char *
159 sfs_redirect (struct vfs_class *me, const char *name)
161 struct cachedfile *cur = head;
162 char *cache;
163 int handle;
165 while (cur) {
166 if (!strcmp (name, cur->name)) {
167 vfs_stamp (&vfs_sfs_ops, cur);
168 return cur->cache;
170 cur = cur->next;
173 handle = vfs_mkstemps (&cache, "sfs", name);
175 if (handle == -1) {
176 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
179 close (handle);
181 if (!sfs_vfmake (me, name, cache)) {
182 cur = g_new (struct cachedfile, 1);
183 cur->name = g_strdup (name);
184 cur->cache = cache;
185 cur->next = head;
186 head = cur;
188 vfs_stamp_create (&vfs_sfs_ops, head);
190 return cache;
193 unlink (cache);
194 g_free (cache);
195 return "/I_MUST_NOT_EXIST";
198 static void *
199 sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
201 int *sfs_info;
202 int fd;
204 path = sfs_redirect (me, path);
205 fd = open (path, NO_LINEAR (flags), mode);
206 if (fd == -1)
207 return 0;
209 sfs_info = g_new (int, 1);
210 *sfs_info = fd;
212 return sfs_info;
215 static int sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
217 path = sfs_redirect (me, path);
218 return stat (path, buf);
221 static int sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
223 path = sfs_redirect (me, path);
224 #ifndef HAVE_STATLSTAT
225 return lstat (path, buf);
226 #else
227 return statlstat (path, buf);
228 #endif
231 static int sfs_chmod (struct vfs_class *me, const char *path, int mode)
233 path = sfs_redirect (me, path);
234 return chmod (path, mode);
237 static int sfs_chown (struct vfs_class *me, const char *path, int owner, int group)
239 path = sfs_redirect (me, path);
240 return chown (path, owner, group);
243 static int sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
245 path = sfs_redirect (me, path);
246 return utime (path, times);
249 static int
250 sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
252 path = sfs_redirect (me, path);
253 return readlink (path, buf, size);
256 static vfsid
257 sfs_getid (struct vfs_class *me, const char *path)
259 struct cachedfile *cur = head;
261 (void) me;
263 while (cur) {
264 if (!strcmp (path, cur->name))
265 break;
266 cur = cur->next;
269 return (vfsid) cur;
272 static void sfs_free (vfsid id)
274 struct cachedfile *which = (struct cachedfile *) id;
275 struct cachedfile *cur, *prev;
277 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
279 if (!cur)
280 vfs_die( "Free of thing which is unknown to me\n" );
281 unlink (cur->cache);
283 if (prev)
284 prev->next = cur->next;
285 else
286 head = cur->next;
288 g_free (cur->cache);
289 g_free (cur->name);
290 g_free (cur);
293 static void sfs_fill_names (struct vfs_class *me, fill_names_f func)
295 struct cachedfile *cur = head;
297 (void) me;
299 while (cur){
300 (*func)(cur->name);
301 cur = cur->next;
305 static int sfs_nothingisopen (vfsid id)
307 /* FIXME: Investigate whether have to guard this like in
308 the other VFSs (see fd_usage in extfs) -- Norbert */
309 (void) id;
310 return 1;
313 static char *
314 sfs_getlocalcopy (struct vfs_class *me, const char *path)
316 path = sfs_redirect (me, path);
317 return g_strdup (path);
320 static int
321 sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
322 const char *local, int has_changed)
324 (void) me;
325 (void) path;
326 (void) local;
327 (void) has_changed;
328 return 0;
331 static int sfs_init (struct vfs_class *me)
333 char *mc_sfsini;
334 FILE *cfg;
335 char key[256];
337 (void) me;
339 mc_sfsini = concat_dir_and_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
340 cfg = fopen (mc_sfsini, "r");
342 if (!cfg){
343 fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
344 g_free (mc_sfsini);
345 return 0;
347 g_free (mc_sfsini);
349 sfs_no = 0;
350 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg)) {
351 char *c, *semi = NULL, flags = 0;
353 if (*key == '#' || *key == '\n')
354 continue;
356 for (c = key; *c; c++)
357 if ((*c == ':') || (*c == '/')){
358 semi = c;
359 if (*c == '/'){
360 *c = 0;
361 flags |= F_FULLMATCH;
363 break;
366 if (!semi){
367 invalid_line:
368 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
369 "sfs.ini", key);
370 continue;
373 c = semi + 1;
374 while (*c && (*c != ' ') && (*c != '\t')) {
375 switch (*c) {
376 case '1': flags |= F_1; break;
377 case '2': flags |= F_2; break;
378 case 'R': flags |= F_NOLOCALCOPY; break;
379 default:
380 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
381 *c, "sfs.ini", key);
383 c++;
385 if (!*c)
386 goto invalid_line;
387 c++;
388 *(semi+1) = 0;
389 if ((semi = strchr (c, '\n')))
390 *semi = 0;
392 sfs_prefix [sfs_no] = g_strdup (key);
393 sfs_command [sfs_no] = g_strdup (c);
394 sfs_flags [sfs_no] = flags;
395 sfs_no++;
397 fclose (cfg);
398 return 1;
401 static void
402 sfs_done (struct vfs_class *me)
404 int i;
406 (void) me;
408 for (i = 0; i < sfs_no; i++){
409 g_free (sfs_prefix [i]);
410 g_free (sfs_command [i]);
411 sfs_prefix [i] = sfs_command [i] = NULL;
413 sfs_no = 0;
416 static int
417 sfs_which (struct vfs_class *me, const char *path)
419 int i;
421 (void) me;
423 for (i = 0; i < sfs_no; i++)
424 if (sfs_flags [i] & F_FULLMATCH) {
425 if (!strcmp (path, sfs_prefix [i]))
426 return i;
427 } else
428 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
429 return i;
431 return -1;
434 void
435 init_sfs (void)
437 vfs_sfs_ops.name = "sfs";
438 vfs_sfs_ops.init = sfs_init;
439 vfs_sfs_ops.done = sfs_done;
440 vfs_sfs_ops.fill_names = sfs_fill_names;
441 vfs_sfs_ops.which = sfs_which;
442 vfs_sfs_ops.open = sfs_open;
443 vfs_sfs_ops.close = local_close;
444 vfs_sfs_ops.read = local_read;
445 vfs_sfs_ops.stat = sfs_stat;
446 vfs_sfs_ops.lstat = sfs_lstat;
447 vfs_sfs_ops.fstat = local_fstat;
448 vfs_sfs_ops.chmod = sfs_chmod;
449 vfs_sfs_ops.chown = sfs_chown;
450 vfs_sfs_ops.utime = sfs_utime;
451 vfs_sfs_ops.readlink = sfs_readlink;
452 vfs_sfs_ops.ferrno = local_errno;
453 vfs_sfs_ops.lseek = local_lseek;
454 vfs_sfs_ops.getid = sfs_getid;
455 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
456 vfs_sfs_ops.free = sfs_free;
457 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
458 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
459 vfs_register_class (&vfs_sfs_ops);