Merge commit 'origin/mc-4.6'
[midnight-commander.git] / vfs / sfs.c
blob34fee616cd9a1a2f028b7d206a1778167672b7ee
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 <mhl/string.h>
39 #include "../src/global.h"
40 #include "../src/tty.h" /* enable/disable interrupt key */
41 #include "../src/wtools.h" /* message() */
42 #include "../src/main.h" /* print_vfs_message */
43 #include "utilvfs.h"
44 #include "vfs.h"
45 #include "vfs-impl.h"
46 #include "gc.h" /* vfs_stamp_create */
47 #include "local.h"
48 #include "../src/execute.h" /* EXECUTE_AS_SHELL */
50 struct cachedfile {
51 char *name, *cache;
52 struct cachedfile *next;
55 static struct cachedfile *head;
56 static struct vfs_class vfs_sfs_ops;
58 #define MAXFS 32
59 static int sfs_no = 0;
60 static char *sfs_prefix[ MAXFS ];
61 static char *sfs_command[ MAXFS ];
62 static int sfs_flags[ MAXFS ];
63 #define F_1 1
64 #define F_2 2
65 #define F_NOLOCALCOPY 4
66 #define F_FULLMATCH 8
68 static int
69 sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
71 char *inpath, *op;
72 int w;
73 char pad[10240];
74 char *s, *t = pad;
75 int was_percent = 0;
76 char *pname; /* name of parent archive */
77 char *pqname; /* name of parent archive, quoted */
79 pname = g_strdup (name);
80 vfs_split (pname, &inpath, &op);
81 if ((w = (*me->which) (me, op)) == -1)
82 vfs_die ("This cannot happen... Hopefully.\n");
84 if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) {
85 g_free (pname);
86 return -1;
89 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
90 if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
91 s = mc_getlocalcopy (pname);
92 if (!s) {
93 g_free (pname);
94 return -1;
96 pqname = name_quote (s, 0);
97 g_free (s);
98 } else {
99 pqname = name_quote (pname, 0);
101 g_free (pname);
103 #define COPY_CHAR \
104 if ((size_t) (t-pad) > sizeof(pad)) { \
105 g_free (pqname); \
106 return -1; \
108 else \
109 *t++ = *s;
111 #define COPY_STRING(a) \
112 if ((t-pad)+strlen(a)>sizeof(pad)) { \
113 g_free (pqname); \
114 return -1; \
115 } else { \
116 strcpy (t, a); \
117 t+= strlen(a); \
120 for (s = sfs_command[w]; *s; s++) {
121 if (was_percent) {
123 const char *ptr = NULL;
124 was_percent = 0;
126 switch (*s) {
127 case '1':
128 ptr = pqname;
129 break;
130 case '2':
131 ptr = op + strlen (sfs_prefix[w]);
132 break;
133 case '3':
134 ptr = cache;
135 break;
136 case '%':
137 COPY_CHAR;
138 continue;
140 COPY_STRING (ptr);
141 } else {
142 if (*s == '%')
143 was_percent = 1;
144 else
145 COPY_CHAR;
149 g_free (pqname);
150 open_error_pipe ();
151 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
152 close_error_pipe (D_ERROR, NULL);
153 return -1;
156 close_error_pipe (D_NORMAL, NULL);
157 return 0; /* OK */
160 static const char *
161 sfs_redirect (struct vfs_class *me, const char *name)
163 struct cachedfile *cur = head;
164 char *cache;
165 int handle;
167 while (cur) {
168 if (!strcmp (name, cur->name)) {
169 vfs_stamp (&vfs_sfs_ops, cur);
170 return cur->cache;
172 cur = cur->next;
175 handle = vfs_mkstemps (&cache, "sfs", name);
177 if (handle == -1) {
178 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
181 close (handle);
183 if (!sfs_vfmake (me, name, cache)) {
184 cur = g_new (struct cachedfile, 1);
185 cur->name = g_strdup (name);
186 cur->cache = cache;
187 cur->next = head;
188 head = cur;
190 vfs_stamp_create (&vfs_sfs_ops, head);
192 return cache;
195 unlink (cache);
196 g_free (cache);
197 return "/I_MUST_NOT_EXIST";
200 static void *
201 sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
203 int *sfs_info;
204 int fd;
206 path = sfs_redirect (me, path);
207 fd = open (path, NO_LINEAR (flags), mode);
208 if (fd == -1)
209 return 0;
211 sfs_info = g_new (int, 1);
212 *sfs_info = fd;
214 return sfs_info;
217 static int sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
219 path = sfs_redirect (me, path);
220 return stat (path, buf);
223 static int sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
225 path = sfs_redirect (me, path);
226 #ifndef HAVE_STATLSTAT
227 return lstat (path, buf);
228 #else
229 return statlstat (path, buf);
230 #endif
233 static int sfs_chmod (struct vfs_class *me, const char *path, int mode)
235 path = sfs_redirect (me, path);
236 return chmod (path, mode);
239 static int sfs_chown (struct vfs_class *me, const char *path, int owner, int group)
241 path = sfs_redirect (me, path);
242 return chown (path, owner, group);
245 static int sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
247 path = sfs_redirect (me, path);
248 return utime (path, times);
251 static int
252 sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
254 path = sfs_redirect (me, path);
255 return readlink (path, buf, size);
258 static vfsid
259 sfs_getid (struct vfs_class *me, const char *path)
261 struct cachedfile *cur = head;
263 (void) me;
265 while (cur) {
266 if (!strcmp (path, cur->name))
267 break;
268 cur = cur->next;
271 return (vfsid) cur;
274 static void sfs_free (vfsid id)
276 struct cachedfile *which = (struct cachedfile *) id;
277 struct cachedfile *cur, *prev;
279 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
281 if (!cur)
282 vfs_die( "Free of thing which is unknown to me\n" );
283 unlink (cur->cache);
285 if (prev)
286 prev->next = cur->next;
287 else
288 head = cur->next;
290 g_free (cur->cache);
291 g_free (cur->name);
292 g_free (cur);
295 static void sfs_fill_names (struct vfs_class *me, fill_names_f func)
297 struct cachedfile *cur = head;
299 (void) me;
301 while (cur){
302 (*func)(cur->name);
303 cur = cur->next;
307 static int sfs_nothingisopen (vfsid id)
309 /* FIXME: Investigate whether have to guard this like in
310 the other VFSs (see fd_usage in extfs) -- Norbert */
311 (void) id;
312 return 1;
315 static char *
316 sfs_getlocalcopy (struct vfs_class *me, const char *path)
318 path = sfs_redirect (me, path);
319 return g_strdup (path);
322 static int
323 sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
324 const char *local, int has_changed)
326 (void) me;
327 (void) path;
328 (void) local;
329 (void) has_changed;
330 return 0;
333 static int sfs_init (struct vfs_class *me)
335 char *mc_sfsini;
336 FILE *cfg;
337 char key[256];
339 (void) me;
341 mc_sfsini = mhl_str_dir_plus_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
342 cfg = fopen (mc_sfsini, "r");
344 if (!cfg){
345 fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
346 g_free (mc_sfsini);
347 return 0;
349 g_free (mc_sfsini);
351 sfs_no = 0;
352 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg)) {
353 char *c, *semi = NULL, flags = 0;
355 if (*key == '#' || *key == '\n')
356 continue;
358 for (c = key; *c; c++)
359 if ((*c == ':') || (*c == '/')){
360 semi = c;
361 if (*c == '/'){
362 *c = 0;
363 flags |= F_FULLMATCH;
365 break;
368 if (!semi){
369 invalid_line:
370 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
371 "sfs.ini", key);
372 continue;
375 c = semi + 1;
376 while (*c && (*c != ' ') && (*c != '\t')) {
377 switch (*c) {
378 case '1': flags |= F_1; break;
379 case '2': flags |= F_2; break;
380 case 'R': flags |= F_NOLOCALCOPY; break;
381 default:
382 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
383 *c, "sfs.ini", key);
385 c++;
387 if (!*c)
388 goto invalid_line;
389 c++;
390 *(semi+1) = 0;
391 if ((semi = strchr (c, '\n')))
392 *semi = 0;
394 sfs_prefix [sfs_no] = g_strdup (key);
395 sfs_command [sfs_no] = g_strdup (c);
396 sfs_flags [sfs_no] = flags;
397 sfs_no++;
399 fclose (cfg);
400 return 1;
403 static void
404 sfs_done (struct vfs_class *me)
406 int i;
408 (void) me;
410 for (i = 0; i < sfs_no; i++){
411 g_free (sfs_prefix [i]);
412 g_free (sfs_command [i]);
413 sfs_prefix [i] = sfs_command [i] = NULL;
415 sfs_no = 0;
418 static int
419 sfs_which (struct vfs_class *me, const char *path)
421 int i;
423 (void) me;
425 for (i = 0; i < sfs_no; i++)
426 if (sfs_flags [i] & F_FULLMATCH) {
427 if (!strcmp (path, sfs_prefix [i]))
428 return i;
429 } else
430 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
431 return i;
433 return -1;
436 void
437 init_sfs (void)
439 vfs_sfs_ops.name = "sfs";
440 vfs_sfs_ops.init = sfs_init;
441 vfs_sfs_ops.done = sfs_done;
442 vfs_sfs_ops.fill_names = sfs_fill_names;
443 vfs_sfs_ops.which = sfs_which;
444 vfs_sfs_ops.open = sfs_open;
445 vfs_sfs_ops.close = local_close;
446 vfs_sfs_ops.read = local_read;
447 vfs_sfs_ops.stat = sfs_stat;
448 vfs_sfs_ops.lstat = sfs_lstat;
449 vfs_sfs_ops.fstat = local_fstat;
450 vfs_sfs_ops.chmod = sfs_chmod;
451 vfs_sfs_ops.chown = sfs_chown;
452 vfs_sfs_ops.utime = sfs_utime;
453 vfs_sfs_ops.readlink = sfs_readlink;
454 vfs_sfs_ops.ferrno = local_errno;
455 vfs_sfs_ops.lseek = local_lseek;
456 vfs_sfs_ops.getid = sfs_getid;
457 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
458 vfs_sfs_ops.free = sfs_free;
459 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
460 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
461 vfs_register_class (&vfs_sfs_ops);