small highlighting correction
[midnight-commander.git] / vfs / sfs.c
blobe8a599c37f9b97c11d1f6c30f1592422b7f32132
1 /*
2 * Single File fileSystem
4 * Copyright 1998 Pavel Machek, distribute under GPL
6 * $Id$
8 * This defines whole class of filesystems which contain single file
9 * inside. It is somehow similar to extfs, except that extfs makes
10 * whole virtual trees and we do only single virtual files.
12 * If you want to gunzip something, you should open it with #ugz
13 * suffix, DON'T try to gunzip it yourself.
15 * Namespace: exports vfs_sfs_ops */
17 #include <config.h>
18 #include <errno.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <string.h>
24 #include "utilvfs.h"
26 #include "vfs.h"
27 #include "local.h"
29 struct cachedfile {
30 char *name, *cache;
31 uid_t uid;
32 struct cachedfile *next;
35 static struct cachedfile *head;
37 #define MAXFS 32
38 static int sfs_no = 0;
39 static char *sfs_prefix[ MAXFS ];
40 static char *sfs_command[ MAXFS ];
41 static int sfs_flags[ MAXFS ];
42 #define F_1 1
43 #define F_2 2
44 #define F_NOLOCALCOPY 4
45 #define F_FULLMATCH 8
47 static int uptodate (char *name, char *cache)
49 return 1;
52 static int vfmake (vfs *me, char *name, char *cache)
54 char *inpath, *op;
55 int w;
56 char pad [10240];
57 char *s, *t = pad;
58 int was_percent = 0;
60 vfs_split (name, &inpath, &op);
61 if ((w = (*me->which) (me, op)) == -1)
62 vfs_die ("This cannot happen... Hopefully.\n");
64 if ((sfs_flags[w] & F_1) || (!strcmp (name, "/"))) ; else return -1;
65 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
66 if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
67 s = mc_getlocalcopy (name);
68 if (!s)
69 return -1;
70 name = name_quote (s, 0);
71 g_free (s);
72 } else
73 name = name_quote (name, 0);
74 #define COPY_CHAR if (t-pad>sizeof(pad)) { g_free (name); return -1; } else *t++ = *s;
75 #define COPY_STRING(a) if ((t-pad)+strlen(a)>sizeof(pad)) { g_free (name); return -1; } else { strcpy (t, a); t+= strlen(a); }
76 for (s = sfs_command[w]; *s; s++) {
77 if (was_percent) {
79 char *ptr = NULL;
80 was_percent = 0;
82 switch (*s) {
83 case '1': ptr = name; break;
84 case '2': ptr = op + strlen (sfs_prefix[w]); break;
85 case '3': ptr = cache; break;
86 case '%': COPY_CHAR; continue;
88 COPY_STRING (ptr);
89 } else {
90 if (*s == '%')
91 was_percent = 1;
92 else
93 COPY_CHAR;
96 g_free (name);
98 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
99 return -1;
102 return 0; /* OK */
105 static char *
106 redirect (vfs *me, char *name)
108 struct cachedfile *cur = head;
109 uid_t uid = vfs_uid;
110 char *cache;
111 int handle;
113 while (cur){
114 if ((!strcmp (name, cur->name)) &&
115 (uid == cur->uid) &&
116 (uptodate (cur->name, cur->cache)))
117 /* FIXME: when not uptodate, we might want to kill cache
118 * file immediately, not to wait until timeout. */ {
119 vfs_stamp (&vfs_sfs_ops, cur);
120 return cur->cache;
122 cur = cur->next;
125 handle = mc_mkstemps (&cache, "sfs", NULL);
127 if (handle == -1) {
128 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
131 close (handle);
133 if (!vfmake (me, name, cache)){
134 cur = g_new (struct cachedfile, 1);
135 cur->name = g_strdup (name);
136 cur->cache = cache;
137 cur->uid = uid;
138 cur->next = head;
139 head = cur;
141 vfs_add_noncurrent_stamps (&vfs_sfs_ops, (vfsid) head, NULL);
142 vfs_rm_parents (NULL);
144 return cache;
147 unlink (cache);
148 g_free (cache);
149 return "/I_MUST_NOT_EXIST";
152 static void *
153 sfs_open (vfs *me, char *path, int flags, int mode)
155 int *sfs_info;
156 int fd;
158 path = redirect (me, path);
159 fd = open (path, NO_LINEAR(flags), mode);
160 if (fd == -1)
161 return 0;
163 sfs_info = g_new (int, 1);
164 *sfs_info = fd;
166 return sfs_info;
169 static int sfs_stat (vfs *me, char *path, struct stat *buf)
171 path = redirect (me, path);
172 return stat (path, buf);
175 static int sfs_lstat (vfs *me, char *path, struct stat *buf)
177 path = redirect (me, path);
178 #ifndef HAVE_STATLSTAT
179 return lstat (path, buf);
180 #else
181 return statlstat (path, buf);
182 #endif
185 static int sfs_chmod (vfs *me, char *path, int mode)
187 path = redirect (me, path);
188 return chmod (path, mode);
191 static int sfs_chown (vfs *me, char *path, int owner, int group)
193 path = redirect (me, path);
194 return chown (path, owner, group);
197 static int sfs_utime (vfs *me, char *path, struct utimbuf *times)
199 path = redirect (me, path);
200 return utime (path, times);
203 static int sfs_readlink (vfs *me, char *path, char *buf, int size)
205 path = redirect (me, path);
206 return readlink (path, buf, size);
209 static vfsid sfs_getid (vfs *me, char *path, struct vfs_stamping **parent)
210 { /* FIXME: what should I do? */
211 vfs *v;
212 vfsid id;
213 struct vfs_stamping *par;
214 struct cachedfile *cur = head;
216 while (cur) {
217 if ((!strcmp( path, cur->name )) &&
218 (vfs_uid == cur->uid))
219 break;
220 cur = cur->next;
223 *parent = NULL;
225 if (!cur)
226 return (vfsid)(-1);
229 char *path2 = g_strdup (path);
230 v = vfs_split (path2, NULL, NULL); /* Strip suffix which led to this being sfs */
231 v = vfs_split (path2, NULL, NULL); /* ... and learn whoever was the parent system */
232 id = (*v->getid) (v, path2, &par);
233 g_free (path2);
236 if (id != (vfsid)-1) {
237 *parent = g_new (struct vfs_stamping, 1);
238 (*parent)->v = v;
239 (*parent)->id = id;
240 (*parent)->parent = par;
241 (*parent)->next = NULL;
243 return (vfsid) cur;
246 static void sfs_free (vfsid id)
248 struct cachedfile *which = (struct cachedfile *) id;
249 struct cachedfile *cur, *prev;
251 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
253 if (!cur)
254 vfs_die( "Free of thing which is unknown to me\n" );
255 unlink (cur->cache);
257 if (prev)
258 prev->next = cur->next;
259 else
260 head = cur->next;
262 g_free (cur->cache);
263 g_free (cur->name);
264 g_free (cur);
267 static void sfs_fill_names (vfs *me, void (*func)(char *))
269 struct cachedfile *cur = head;
271 while (cur){
272 (*func)(cur->name);
273 cur = cur->next;
277 static int sfs_nothingisopen (vfsid id)
279 /* FIXME: Investigate whether have to guard this like in
280 the other VFSs (see fd_usage in extfs) -- Norbert */
281 return 1;
284 static char *sfs_getlocalcopy (vfs *me, char *path)
286 path = redirect (me, path);
287 return g_strdup (path);
290 static int sfs_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
292 g_free(local);
293 return 0;
296 static int sfs_init (vfs *me)
298 char *mc_sfsini;
299 FILE *cfg;
301 mc_sfsini = concat_dir_and_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
302 cfg = fopen (mc_sfsini, "r");
304 if (!cfg){
305 fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
306 g_free (mc_sfsini);
307 return 0;
309 g_free (mc_sfsini);
311 sfs_no = 0;
312 while (sfs_no < MAXFS){
313 char key[256];
314 char *c, *semi = NULL, flags = 0;
316 if (!fgets (key, sizeof (key), cfg))
317 break;
319 if (*key == '#')
320 continue;
322 for (c = key; *c; c++)
323 if ((*c == ':') || (*c == '/')){
324 semi = c;
325 if (*c == '/'){
326 *c = 0;
327 flags |= F_FULLMATCH;
329 break;
332 if (!semi){
333 fprintf (stderr, _("Warning: Invalid line in sfs.ini:\n%s\n"), key);
334 continue;
337 c = semi + 1;
338 while ((*c != ' ') && (*c != '\t')) {
339 switch (*c) {
340 case '1': flags |= F_1; break;
341 case '2': flags |= F_2; break;
342 case 'R': flags |= F_NOLOCALCOPY; break;
343 default:
344 fprintf (stderr, _("Warning: Invalid flag %c in sfs.ini:\n%s\n"), *c, key);
346 c++;
348 c++;
349 *(semi+1) = 0;
350 if ((semi = strchr (c, '\n')))
351 *semi = 0;
353 sfs_prefix [sfs_no] = g_strdup (key);
354 sfs_command [sfs_no] = g_strdup (c);
355 sfs_flags [sfs_no] = flags;
356 sfs_no++;
358 fclose (cfg);
359 return 1;
362 static void
363 sfs_done (vfs *me)
365 int i;
367 for (i = 0; i < sfs_no; i++){
368 g_free (sfs_prefix [i]);
369 g_free (sfs_command [i]);
370 sfs_prefix [i] = sfs_command [i] = NULL;
372 sfs_no = 0;
375 static int
376 sfs_which (vfs *me, char *path)
378 int i;
380 for (i = 0; i < sfs_no; i++)
381 if (sfs_flags [i] & F_FULLMATCH) {
382 if (!strcmp (path, sfs_prefix [i]))
383 return i;
384 } else
385 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
386 return i;
388 return -1;
391 vfs vfs_sfs_ops = {
392 NULL, /* This is place of next pointer */
393 "sfs",
394 F_EXEC, /* flags */
395 NULL, /* prefix */
396 NULL, /* data */
397 0, /* errno */
398 sfs_init,
399 sfs_done,
400 sfs_fill_names,
401 sfs_which,
403 sfs_open,
404 local_close,
405 local_read,
406 NULL,
408 NULL,
409 NULL,
410 NULL,
411 NULL,
412 NULL,
414 sfs_stat,
415 sfs_lstat,
416 local_fstat,
418 sfs_chmod,
419 sfs_chown,
420 sfs_utime,
422 sfs_readlink,
423 NULL,
424 NULL,
425 NULL,
427 NULL,
428 NULL,
429 local_errno,
430 local_lseek,
431 NULL,
433 sfs_getid,
434 sfs_nothingisopen,
435 sfs_free,
437 sfs_getlocalcopy,
438 sfs_ungetlocalcopy,
440 NULL,
441 NULL,
442 NULL,
443 NULL
445 #ifdef HAVE_MMAP
446 ,local_mmap,
447 local_munmap
448 #endif