update
[midnight-commander.git] / vfs / sfs.c
blobdda26fdc4db01538b7d8fe466a38bca2d296ab52
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, shell (FIXME) */
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>
21 #include <fcntl.h>
23 #include "utilvfs.h"
25 #include "vfs.h"
26 #include "local.h"
28 /* This is needed, or libvfs.so will lack symbol shell. Should look up who requires it */
29 char *shell = "/bin/sh";
31 struct cachedfile {
32 char *name, *cache;
33 uid_t uid;
34 struct cachedfile *next;
37 static struct cachedfile *head;
39 #define MAXFS 32
40 static int sfs_no = 0;
41 static char *sfs_prefix[ MAXFS ];
42 static char *sfs_command[ MAXFS ];
43 static int sfs_flags[ MAXFS ];
44 #define F_1 1
45 #define F_2 2
46 #define F_NOLOCALCOPY 4
47 #define F_FULLMATCH 8
49 static int uptodate (char *name, char *cache)
51 return 1;
54 static int vfmake (vfs *me, char *name, char *cache)
56 char *inpath, *op;
57 int w;
58 char pad [10240];
59 char *s, *t = pad;
60 int was_percent = 0;
62 vfs_split (name, &inpath, &op);
63 if ((w = (*me->which) (me, op)) == -1)
64 vfs_die ("This cannot happen... Hopefully.\n");
66 if ((sfs_flags[w] & F_1) || (!strcmp (name, "/"))) ; else return -1;
67 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
68 if (!(sfs_flags[w] & F_NOLOCALCOPY))
69 name = mc_getlocalcopy (name);
70 else
71 name = g_strdup (name);
72 s = sfs_command[w];
73 #define COPY_CHAR if (t-pad>10200) return -1; else *t++ = *s;
74 #define COPY_STRING(a) if ((t-pad)+strlen(a)>10200) return -1; else { strcpy (t, a); t+= strlen(a); }
75 while (*s) {
76 if (was_percent) {
77 switch (*s) {
78 case '1': COPY_STRING (name); break;
79 case '2': COPY_STRING (op + strlen (sfs_prefix[w])); break;
80 case '3': COPY_STRING (cache); break;
81 case '%': COPY_CHAR; break;
83 was_percent = 0;
84 } else {
85 if (*s == '%')
86 was_percent = 1;
87 else
88 COPY_CHAR;
90 s++;
92 g_free (name);
94 if (my_system (EXECUTE_AS_SHELL | EXECUTE_SETUID | EXECUTE_WAIT, "/bin/sh", pad)) {
95 return -1;
98 return 0; /* OK */
101 static char *
102 redirect (vfs *me, char *name)
104 struct cachedfile *cur = head;
105 uid_t uid = vfs_uid;
106 char *cache, *xname;
107 int handle;
109 while (cur){
110 if ((!strcmp (name, cur->name)) &&
111 (uid == cur->uid) &&
112 (uptodate (cur->name, cur->cache)))
113 /* FIXME: when not uptodate, we might want to kill cache
114 * file immediately, not to wait until timeout. */ {
115 vfs_stamp (&vfs_sfs_ops, cur);
116 return cur->cache;
118 cur = cur->next;
121 cache = tempnam (NULL, "sfs");
122 handle = open (cache, O_RDWR | O_CREAT | O_EXCL, 0600);
123 if (handle == -1)
124 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
126 close (handle);
128 xname = g_strdup (name);
129 if (!vfmake (me, name, cache)){
130 cur = g_new (struct cachedfile, 1);
131 cur->name = xname;
132 cur->cache = cache;
133 cur->uid = uid;
134 cur->next = head;
135 head = cur;
137 vfs_add_noncurrent_stamps (&vfs_sfs_ops, (vfsid) head, NULL);
138 vfs_rm_parents (NULL);
140 return cache;
141 } else {
142 g_free(xname);
144 return "/I_MUST_NOT_EXIST";
147 static void *
148 sfs_open (vfs *me, char *path, int flags, int mode)
150 int *sfs_info;
151 int fd;
153 path = redirect (me, path);
154 fd = open (path, flags, mode);
155 if (fd == -1)
156 return 0;
158 sfs_info = g_new (int, 1);
159 *sfs_info = fd;
161 return sfs_info;
164 static int sfs_stat (vfs *me, char *path, struct stat *buf)
166 path = redirect (me, path);
167 return stat (path, buf);
170 static int sfs_lstat (vfs *me, char *path, struct stat *buf)
172 path = redirect (me, path);
173 #ifndef HAVE_STATLSTAT
174 return lstat (path,buf);
175 #else
176 return statlstat (path, buf);
177 #endif
180 static int sfs_chmod (vfs *me, char *path, int mode)
182 path = redirect (me, path);
183 return chmod (path, mode);
186 static int sfs_chown (vfs *me, char *path, int owner, int group)
188 path = redirect (me, path);
189 return chown (path, owner, group);
192 static int sfs_utime (vfs *me, char *path, struct utimbuf *times)
194 path = redirect (me, path);
195 return utime (path, times);
198 static int sfs_readlink (vfs *me, char *path, char *buf, int size)
200 path = redirect (me, path);
201 return readlink (path, buf, size);
204 static vfsid sfs_getid (vfs *me, char *path, struct vfs_stamping **parent)
205 { /* FIXME: what should I do? */
206 vfs *v;
207 vfsid id;
208 struct vfs_stamping *par;
209 struct cachedfile *cur = head;
211 while (cur) {
212 if ((!strcmp( path, cur->name )) &&
213 (vfs_uid == cur->uid))
214 break;
215 cur = cur->next;
217 if (!cur)
218 vfs_die( "sfs_getid of noncached thingie?" );
220 *parent = NULL;
223 char *path2 = g_strdup (path);
224 v = vfs_split (path2, NULL, NULL);
225 id = (*v->getid) (v, path2, &par);
226 g_free (path2);
229 if (id != (vfsid)-1) {
230 *parent = g_new (struct vfs_stamping, 1);
231 (*parent)->v = v;
232 (*parent)->id = id;
233 (*parent)->parent = par;
234 (*parent)->next = NULL;
236 return (vfsid) cur;
239 static void sfs_free (vfsid id)
241 struct cachedfile *which = (struct cachedfile *) id;
242 struct cachedfile *cur, *prev;
244 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
246 if (!cur)
247 vfs_die( "Free of thing which is unknown to me\n" );
248 unlink (cur->cache);
250 if (prev)
251 prev->next = cur->next;
252 else
253 head = cur->next;
256 static void sfs_fill_names (vfs *me, void (*func)(char *))
258 struct cachedfile *cur = head;
260 while (cur){
261 (*func)(cur->name);
262 cur = cur->next;
266 static int sfs_nothingisopen (vfsid id)
268 /* FIXME: Investigate whether have to guard this like in
269 the other VFSs (see fd_usage in extfs) -- Norbert */
270 return 1;
273 static char *sfs_getlocalcopy (vfs *me, char *path)
275 path = redirect (me, path);
276 return g_strdup (path);
279 static void sfs_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
283 static int sfs_init (vfs *me)
285 FILE *cfg = fopen (LIBDIR "extfs/sfs.ini", "r");
287 if (!cfg){
288 fprintf (stderr, "Warning: " LIBDIR "extfs/sfs.ini not found\n");
289 return 0;
292 sfs_no = 0;
293 while (sfs_no < MAXFS){
294 char key[256];
295 char *c, *semi = NULL, flags = 0;
296 int i;
298 if (!fgets (key, 250, cfg))
299 break;
301 if (*key == '#')
302 continue;
304 for (i = 0; i < strlen (key); i++)
305 if ((key[i]==':') || (key[i]=='/')){
306 semi = key+i;
307 if (key [i] == '/'){
308 key [i] = 0;
309 flags |= F_FULLMATCH;
311 break;
314 if (!semi){
315 fprintf (stderr, "Warning: Invalid line %s in sfs.ini.\n", key);
316 continue;
319 c = semi + 1;
320 while ((*c != ' ') && (*c != 9)) {
321 switch (*c) {
322 case '1': flags |= F_1; break;
323 case '2': flags |= F_2; break;
324 case 'R': flags |= F_NOLOCALCOPY; break;
325 default:
326 fprintf (stderr, "Warning: Invalid flag %c in sfs.ini line %s.\n", *c, key);
328 c++;
330 c++;
331 *(semi+1) = 0;
332 if ((semi = strchr (c, '\n')))
333 *semi = 0;
335 sfs_prefix [sfs_no] = g_strdup (key);
336 sfs_command [sfs_no] = g_strdup (c);
337 sfs_flags [sfs_no] = flags;
338 sfs_no++;
340 fclose (cfg);
341 return 1;
344 static void
345 sfs_done (vfs *me)
347 int i;
349 for (i = 0; i < sfs_no; i++){
350 g_free (sfs_prefix [i]);
351 g_free (sfs_command [i]);
352 sfs_prefix [i] = sfs_command [i] = NULL;
354 sfs_no = 0;
357 static int
358 sfs_which (vfs *me, char *path)
360 int i;
362 for (i = 0; i < sfs_no; i++)
363 if (sfs_flags [i] & F_FULLMATCH) {
364 if (!strcmp (path, sfs_prefix [i]))
365 return i;
366 } else
367 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
368 return i;
371 return -1;
374 vfs vfs_sfs_ops = {
375 NULL, /* This is place of next pointer */
376 "Signle file filesystems",
377 F_EXEC, /* flags */
378 NULL, /* prefix */
379 NULL, /* data */
380 0, /* errno */
381 sfs_init,
382 sfs_done,
383 sfs_fill_names,
384 sfs_which,
386 sfs_open,
387 local_close,
388 local_read,
389 NULL,
391 NULL,
392 NULL,
393 NULL,
394 NULL,
395 NULL,
397 sfs_stat,
398 sfs_lstat,
399 local_fstat,
401 sfs_chmod,
402 sfs_chown,
403 sfs_utime,
405 sfs_readlink,
406 NULL,
407 NULL,
408 NULL,
410 NULL,
411 NULL,
412 local_errno,
413 local_lseek,
414 NULL,
416 sfs_getid,
417 sfs_nothingisopen,
418 sfs_free,
420 sfs_getlocalcopy,
421 sfs_ungetlocalcopy,
423 NULL,
424 NULL,
425 NULL,
426 NULL
428 #ifdef HAVE_MMAP
429 ,local_mmap,
430 local_munmap
431 #endif