Merge branch '1810_edit_save_mode'
[kaloumi3.git] / vfs / sfs.c
blob1e5ed19734444107d24c9f1d2dc7e5254b90dfb6
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 #ugz
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 "../src/global.h"
46 #include "../src/wtools.h" /* message() */
47 #include "../src/main.h" /* print_vfs_message */
48 #include "../src/execute.h" /* EXECUTE_AS_SHELL */
50 #include "utilvfs.h"
51 #include "vfs.h"
52 #include "vfs-impl.h"
53 #include "gc.h" /* vfs_stamp_create */
54 #include "local.h"
56 struct cachedfile {
57 char *name, *cache;
58 struct cachedfile *next;
61 static struct cachedfile *head;
62 static struct vfs_class vfs_sfs_ops;
64 #define MAXFS 32
65 static int sfs_no = 0;
66 static char *sfs_prefix[ MAXFS ];
67 static char *sfs_command[ MAXFS ];
68 static int sfs_flags[ MAXFS ];
69 #define F_1 1
70 #define F_2 2
71 #define F_NOLOCALCOPY 4
72 #define F_FULLMATCH 8
74 static int
75 sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
77 char *inpath, *op;
78 int w;
79 char pad[10240];
80 char *s, *t = pad;
81 int was_percent = 0;
82 char *pname; /* name of parent archive */
83 char *pqname; /* name of parent archive, quoted */
85 pname = g_strdup (name);
86 vfs_split (pname, &inpath, &op);
87 if ((w = (*me->which) (me, op)) == -1)
88 vfs_die ("This cannot happen... Hopefully.\n");
90 if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) {
91 g_free (pname);
92 return -1;
95 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
96 if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
97 s = mc_getlocalcopy (pname);
98 if (!s) {
99 g_free (pname);
100 return -1;
102 pqname = name_quote (s, 0);
103 g_free (s);
104 } else {
105 pqname = name_quote (pname, 0);
107 g_free (pname);
109 #define COPY_CHAR \
110 if ((size_t) (t-pad) > sizeof(pad)) { \
111 g_free (pqname); \
112 return -1; \
114 else \
115 *t++ = *s;
117 #define COPY_STRING(a) \
118 if ((t-pad)+strlen(a)>sizeof(pad)) { \
119 g_free (pqname); \
120 return -1; \
121 } else { \
122 strcpy (t, a); \
123 t+= strlen(a); \
126 for (s = sfs_command[w]; *s; s++) {
127 if (was_percent) {
129 const char *ptr = NULL;
130 was_percent = 0;
132 switch (*s) {
133 case '1':
134 ptr = pqname;
135 break;
136 case '2':
137 ptr = op + strlen (sfs_prefix[w]);
138 break;
139 case '3':
140 ptr = cache;
141 break;
142 case '%':
143 COPY_CHAR;
144 continue;
146 COPY_STRING (ptr);
147 } else {
148 if (*s == '%')
149 was_percent = 1;
150 else
151 COPY_CHAR;
155 g_free (pqname);
156 open_error_pipe ();
157 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
158 close_error_pipe (D_ERROR, NULL);
159 return -1;
162 close_error_pipe (D_NORMAL, NULL);
163 return 0; /* OK */
166 static const char *
167 sfs_redirect (struct vfs_class *me, const char *name)
169 struct cachedfile *cur = head;
170 char *cache;
171 int handle;
173 while (cur) {
174 if (!strcmp (name, cur->name)) {
175 vfs_stamp (&vfs_sfs_ops, cur);
176 return cur->cache;
178 cur = cur->next;
181 handle = vfs_mkstemps (&cache, "sfs", name);
183 if (handle == -1) {
184 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
187 close (handle);
189 if (!sfs_vfmake (me, name, cache)) {
190 cur = g_new (struct cachedfile, 1);
191 cur->name = g_strdup (name);
192 cur->cache = cache;
193 cur->next = head;
194 head = cur;
196 vfs_stamp_create (&vfs_sfs_ops, head);
198 return cache;
201 unlink (cache);
202 g_free (cache);
203 return "/I_MUST_NOT_EXIST";
206 static void *
207 sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
209 int *sfs_info;
210 int fd;
212 path = sfs_redirect (me, path);
213 fd = open (path, NO_LINEAR (flags), mode);
214 if (fd == -1)
215 return 0;
217 sfs_info = g_new (int, 1);
218 *sfs_info = fd;
220 return sfs_info;
223 static int sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
225 path = sfs_redirect (me, path);
226 return stat (path, buf);
229 static int sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
231 path = sfs_redirect (me, path);
232 #ifndef HAVE_STATLSTAT
233 return lstat (path, buf);
234 #else
235 return statlstat (path, buf);
236 #endif
239 static int sfs_chmod (struct vfs_class *me, const char *path, int mode)
241 path = sfs_redirect (me, path);
242 return chmod (path, mode);
245 static int sfs_chown (struct vfs_class *me, const char *path, int owner, int group)
247 path = sfs_redirect (me, path);
248 return chown (path, owner, group);
251 static int sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
253 path = sfs_redirect (me, path);
254 return utime (path, times);
257 static int
258 sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
260 path = sfs_redirect (me, path);
261 return readlink (path, buf, size);
264 static vfsid
265 sfs_getid (struct vfs_class *me, const char *path)
267 struct cachedfile *cur = head;
269 (void) me;
271 while (cur) {
272 if (!strcmp (path, cur->name))
273 break;
274 cur = cur->next;
277 return (vfsid) cur;
280 static void sfs_free (vfsid id)
282 struct cachedfile *which = (struct cachedfile *) id;
283 struct cachedfile *cur, *prev;
285 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
287 if (!cur)
288 vfs_die( "Free of thing which is unknown to me\n" );
289 unlink (cur->cache);
291 if (prev)
292 prev->next = cur->next;
293 else
294 head = cur->next;
296 g_free (cur->cache);
297 g_free (cur->name);
298 g_free (cur);
301 static void sfs_fill_names (struct vfs_class *me, fill_names_f func)
303 struct cachedfile *cur = head;
305 (void) me;
307 while (cur){
308 (*func)(cur->name);
309 cur = cur->next;
313 static int sfs_nothingisopen (vfsid id)
315 /* FIXME: Investigate whether have to guard this like in
316 the other VFSs (see fd_usage in extfs) -- Norbert */
317 (void) id;
318 return 1;
321 static char *
322 sfs_getlocalcopy (struct vfs_class *me, const char *path)
324 path = sfs_redirect (me, path);
325 return g_strdup (path);
328 static int
329 sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
330 const char *local, int has_changed)
332 (void) me;
333 (void) path;
334 (void) local;
335 (void) has_changed;
336 return 0;
339 static int sfs_init (struct vfs_class *me)
341 char *mc_sfsini;
342 FILE *cfg;
343 char key[256];
345 (void) me;
347 mc_sfsini = concat_dir_and_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
348 cfg = fopen (mc_sfsini, "r");
350 if (!cfg){
351 fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
352 g_free (mc_sfsini);
353 return 0;
355 g_free (mc_sfsini);
357 sfs_no = 0;
358 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg)) {
359 char *c, *semi = NULL, flags = 0;
361 if (*key == '#' || *key == '\n')
362 continue;
364 for (c = key; *c; c++)
365 if ((*c == ':') || (*c == '/')){
366 semi = c;
367 if (*c == '/'){
368 *c = 0;
369 flags |= F_FULLMATCH;
371 break;
374 if (!semi){
375 invalid_line:
376 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
377 "sfs.ini", key);
378 continue;
381 c = semi + 1;
382 while (*c && (*c != ' ') && (*c != '\t')) {
383 switch (*c) {
384 case '1': flags |= F_1; break;
385 case '2': flags |= F_2; break;
386 case 'R': flags |= F_NOLOCALCOPY; break;
387 default:
388 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
389 *c, "sfs.ini", key);
391 c++;
393 if (!*c)
394 goto invalid_line;
395 c++;
396 *(semi+1) = 0;
397 if ((semi = strchr (c, '\n')))
398 *semi = 0;
400 sfs_prefix [sfs_no] = g_strdup (key);
401 sfs_command [sfs_no] = g_strdup (c);
402 sfs_flags [sfs_no] = flags;
403 sfs_no++;
405 fclose (cfg);
406 return 1;
409 static void
410 sfs_done (struct vfs_class *me)
412 int i;
414 (void) me;
416 for (i = 0; i < sfs_no; i++){
417 g_free (sfs_prefix [i]);
418 g_free (sfs_command [i]);
419 sfs_prefix [i] = sfs_command [i] = NULL;
421 sfs_no = 0;
424 static int
425 sfs_which (struct vfs_class *me, const char *path)
427 int i;
429 (void) me;
431 for (i = 0; i < sfs_no; i++)
432 if (sfs_flags [i] & F_FULLMATCH) {
433 if (!strcmp (path, sfs_prefix [i]))
434 return i;
435 } else
436 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
437 return i;
439 return -1;
442 void
443 init_sfs (void)
445 vfs_sfs_ops.name = "sfs";
446 vfs_sfs_ops.init = sfs_init;
447 vfs_sfs_ops.done = sfs_done;
448 vfs_sfs_ops.fill_names = sfs_fill_names;
449 vfs_sfs_ops.which = sfs_which;
450 vfs_sfs_ops.open = sfs_open;
451 vfs_sfs_ops.close = local_close;
452 vfs_sfs_ops.read = local_read;
453 vfs_sfs_ops.stat = sfs_stat;
454 vfs_sfs_ops.lstat = sfs_lstat;
455 vfs_sfs_ops.fstat = local_fstat;
456 vfs_sfs_ops.chmod = sfs_chmod;
457 vfs_sfs_ops.chown = sfs_chown;
458 vfs_sfs_ops.utime = sfs_utime;
459 vfs_sfs_ops.readlink = sfs_readlink;
460 vfs_sfs_ops.ferrno = local_errno;
461 vfs_sfs_ops.lseek = local_lseek;
462 vfs_sfs_ops.getid = sfs_getid;
463 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
464 vfs_sfs_ops.free = sfs_free;
465 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
466 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
467 vfs_register_class (&vfs_sfs_ops);