Updated italian translation.
[midnight-commander.git] / vfs / sfs.c
blobc584b2a9a81b046120ca2b63547217e38493112b
1 /*
2 * Single File fileSystem
4 * Copyright 1998 Pavel Machek, distribute under GPL
6 * This defines whole class of filesystems which contain single file
7 * inside. It is somehow similar to extfs, except that extfs makes
8 * whole virtual trees and we do only single virtual files.
10 * If you want to gunzip something, you should open it with #ugz
11 * suffix, DON'T try to gunzip it yourself.
13 * Namespace: exports vfs_sfs_ops */
15 #include <config.h>
16 #include <errno.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <string.h>
22 #include "utilvfs.h"
24 #include "vfs.h"
25 #include "local.h"
27 struct cachedfile {
28 char *name, *cache;
29 struct cachedfile *next;
32 static struct cachedfile *head;
34 #define MAXFS 32
35 static int sfs_no = 0;
36 static char *sfs_prefix[ MAXFS ];
37 static char *sfs_command[ MAXFS ];
38 static int sfs_flags[ MAXFS ];
39 #define F_1 1
40 #define F_2 2
41 #define F_NOLOCALCOPY 4
42 #define F_FULLMATCH 8
44 static int uptodate (char *name, char *cache)
46 return 1;
49 static int vfmake (vfs *me, char *name, char *cache)
51 char *inpath, *op;
52 int w;
53 char pad [10240];
54 char *s, *t = pad;
55 int was_percent = 0;
57 vfs_split (name, &inpath, &op);
58 if ((w = (*me->which) (me, op)) == -1)
59 vfs_die ("This cannot happen... Hopefully.\n");
61 if ((sfs_flags[w] & F_1) || (!strcmp (name, "/"))) ; else return -1;
62 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
63 if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
64 s = mc_getlocalcopy (name);
65 if (!s)
66 return -1;
67 name = name_quote (s, 0);
68 g_free (s);
69 } else
70 name = name_quote (name, 0);
71 #define COPY_CHAR if (t-pad>sizeof(pad)) { g_free (name); return -1; } else *t++ = *s;
72 #define COPY_STRING(a) if ((t-pad)+strlen(a)>sizeof(pad)) { g_free (name); return -1; } else { strcpy (t, a); t+= strlen(a); }
73 for (s = sfs_command[w]; *s; s++) {
74 if (was_percent) {
76 char *ptr = NULL;
77 was_percent = 0;
79 switch (*s) {
80 case '1': ptr = name; break;
81 case '2': ptr = op + strlen (sfs_prefix[w]); break;
82 case '3': ptr = cache; break;
83 case '%': COPY_CHAR; continue;
85 COPY_STRING (ptr);
86 } else {
87 if (*s == '%')
88 was_percent = 1;
89 else
90 COPY_CHAR;
93 g_free (name);
95 open_error_pipe ();
96 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
97 close_error_pipe (1, NULL);
98 return -1;
101 close_error_pipe (0, NULL);
102 return 0; /* OK */
105 static char *
106 redirect (vfs *me, char *name)
108 struct cachedfile *cur = head;
109 char *cache;
110 int handle;
112 while (cur) {
113 /* FIXME: when not uptodate, we might want to kill cache
114 * file immediately, not to wait until timeout. */
115 if ((!strcmp (name, cur->name))
116 && (uptodate (cur->name, cur->cache))) {
117 vfs_stamp (&vfs_sfs_ops, cur);
118 return cur->cache;
120 cur = cur->next;
123 handle = mc_mkstemps (&cache, "sfs", NULL);
125 if (handle == -1) {
126 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
129 close (handle);
131 if (!vfmake (me, name, cache)) {
132 cur = g_new (struct cachedfile, 1);
133 cur->name = g_strdup (name);
134 cur->cache = cache;
135 cur->next = head;
136 head = cur;
138 vfs_add_noncurrent_stamps (&vfs_sfs_ops, (vfsid) head, NULL);
139 vfs_rm_parents (NULL);
141 return cache;
144 unlink (cache);
145 g_free (cache);
146 return "/I_MUST_NOT_EXIST";
149 static void *
150 sfs_open (vfs *me, char *path, int flags, int mode)
152 int *sfs_info;
153 int fd;
155 path = redirect (me, path);
156 fd = open (path, NO_LINEAR(flags), mode);
157 if (fd == -1)
158 return 0;
160 sfs_info = g_new (int, 1);
161 *sfs_info = fd;
163 return sfs_info;
166 static int sfs_stat (vfs *me, char *path, struct stat *buf)
168 path = redirect (me, path);
169 return stat (path, buf);
172 static int sfs_lstat (vfs *me, char *path, struct stat *buf)
174 path = redirect (me, path);
175 #ifndef HAVE_STATLSTAT
176 return lstat (path, buf);
177 #else
178 return statlstat (path, buf);
179 #endif
182 static int sfs_chmod (vfs *me, char *path, int mode)
184 path = redirect (me, path);
185 return chmod (path, mode);
188 static int sfs_chown (vfs *me, char *path, int owner, int group)
190 path = redirect (me, path);
191 return chown (path, owner, group);
194 static int sfs_utime (vfs *me, char *path, struct utimbuf *times)
196 path = redirect (me, path);
197 return utime (path, times);
200 static int sfs_readlink (vfs *me, char *path, char *buf, int size)
202 path = redirect (me, path);
203 return readlink (path, buf, size);
206 static vfsid
207 sfs_getid (vfs *me, char *path, struct vfs_stamping **parent)
208 { /* FIXME: what should I do? */
209 vfs *v;
210 vfsid id;
211 struct vfs_stamping *par;
212 struct cachedfile *cur = head;
214 while (cur) {
215 if (!strcmp (path, cur->name))
216 break;
217 cur = cur->next;
220 *parent = NULL;
222 if (!cur)
223 return (vfsid) (-1);
226 char *path2 = g_strdup (path);
228 /* Strip suffix which led to this being sfs */
229 v = vfs_split (path2, NULL, NULL);
231 /* ... and learn whoever was the parent system */
232 v = vfs_split (path2, NULL, NULL);
234 id = (*v->getid) (v, path2, &par);
235 g_free (path2);
238 if (id != (vfsid) - 1) {
239 *parent = g_new (struct vfs_stamping, 1);
240 (*parent)->v = v;
241 (*parent)->id = id;
242 (*parent)->parent = par;
243 (*parent)->next = NULL;
245 return (vfsid) cur;
248 static void sfs_free (vfsid id)
250 struct cachedfile *which = (struct cachedfile *) id;
251 struct cachedfile *cur, *prev;
253 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
255 if (!cur)
256 vfs_die( "Free of thing which is unknown to me\n" );
257 unlink (cur->cache);
259 if (prev)
260 prev->next = cur->next;
261 else
262 head = cur->next;
264 g_free (cur->cache);
265 g_free (cur->name);
266 g_free (cur);
269 static void sfs_fill_names (vfs *me, void (*func)(char *))
271 struct cachedfile *cur = head;
273 while (cur){
274 (*func)(cur->name);
275 cur = cur->next;
279 static int sfs_nothingisopen (vfsid id)
281 /* FIXME: Investigate whether have to guard this like in
282 the other VFSs (see fd_usage in extfs) -- Norbert */
283 return 1;
286 static char *sfs_getlocalcopy (vfs *me, char *path)
288 path = redirect (me, path);
289 return g_strdup (path);
292 static int sfs_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
294 g_free(local);
295 return 0;
298 static int sfs_init (vfs *me)
300 char *mc_sfsini;
301 FILE *cfg;
303 mc_sfsini = concat_dir_and_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
304 cfg = fopen (mc_sfsini, "r");
306 if (!cfg){
307 fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
308 g_free (mc_sfsini);
309 return 0;
311 g_free (mc_sfsini);
313 sfs_no = 0;
314 while (sfs_no < MAXFS){
315 char key[256];
316 char *c, *semi = NULL, flags = 0;
318 if (!fgets (key, sizeof (key), cfg))
319 break;
321 if (*key == '#')
322 continue;
324 for (c = key; *c; c++)
325 if ((*c == ':') || (*c == '/')){
326 semi = c;
327 if (*c == '/'){
328 *c = 0;
329 flags |= F_FULLMATCH;
331 break;
334 if (!semi){
335 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
336 "sfs.ini", key);
337 continue;
340 c = semi + 1;
341 while ((*c != ' ') && (*c != '\t')) {
342 switch (*c) {
343 case '1': flags |= F_1; break;
344 case '2': flags |= F_2; break;
345 case 'R': flags |= F_NOLOCALCOPY; break;
346 default:
347 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
348 *c, "sfs.ini", key);
350 c++;
352 c++;
353 *(semi+1) = 0;
354 if ((semi = strchr (c, '\n')))
355 *semi = 0;
357 sfs_prefix [sfs_no] = g_strdup (key);
358 sfs_command [sfs_no] = g_strdup (c);
359 sfs_flags [sfs_no] = flags;
360 sfs_no++;
362 fclose (cfg);
363 return 1;
366 static void
367 sfs_done (vfs *me)
369 int i;
371 for (i = 0; i < sfs_no; i++){
372 g_free (sfs_prefix [i]);
373 g_free (sfs_command [i]);
374 sfs_prefix [i] = sfs_command [i] = NULL;
376 sfs_no = 0;
379 static int
380 sfs_which (vfs *me, char *path)
382 int i;
384 for (i = 0; i < sfs_no; i++)
385 if (sfs_flags [i] & F_FULLMATCH) {
386 if (!strcmp (path, sfs_prefix [i]))
387 return i;
388 } else
389 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
390 return i;
392 return -1;
395 vfs vfs_sfs_ops = {
396 NULL, /* This is place of next pointer */
397 "sfs",
398 F_EXEC, /* flags */
399 NULL, /* prefix */
400 NULL, /* data */
401 0, /* errno */
402 sfs_init,
403 sfs_done,
404 sfs_fill_names,
405 sfs_which,
407 sfs_open,
408 local_close,
409 local_read,
410 NULL,
412 NULL,
413 NULL,
414 NULL,
415 NULL,
416 NULL,
418 sfs_stat,
419 sfs_lstat,
420 local_fstat,
422 sfs_chmod,
423 sfs_chown,
424 sfs_utime,
426 sfs_readlink,
427 NULL,
428 NULL,
429 NULL,
431 NULL,
432 NULL,
433 local_errno,
434 local_lseek,
435 NULL,
437 sfs_getid,
438 sfs_nothingisopen,
439 sfs_free,
441 sfs_getlocalcopy,
442 sfs_ungetlocalcopy,
444 NULL,
445 NULL,
446 NULL,
447 NULL
449 #ifdef HAVE_MMAP
450 ,local_mmap,
451 local_munmap
452 #endif