Reverted the use of mhl_str_dup and use g_strdup instead.
[midnight-commander.git] / vfs / sfs.c
blob234dca03437f808da75b7c8c92b7ee67e01f5e93
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/memory.h>
38 #include <mhl/string.h>
40 #include "../src/global.h"
41 #include "../src/tty.h" /* enable/disable interrupt key */
42 #include "../src/wtools.h" /* message() */
43 #include "../src/main.h" /* print_vfs_message */
44 #include "utilvfs.h"
45 #include "vfs.h"
46 #include "vfs-impl.h"
47 #include "gc.h" /* vfs_stamp_create */
48 #include "local.h"
49 #include "../src/execute.h" /* EXECUTE_AS_SHELL */
51 struct cachedfile {
52 char *name, *cache;
53 struct cachedfile *next;
56 static struct cachedfile *head;
57 static struct vfs_class vfs_sfs_ops;
59 #define MAXFS 32
60 static int sfs_no = 0;
61 static char *sfs_prefix[ MAXFS ];
62 static char *sfs_command[ MAXFS ];
63 static int sfs_flags[ MAXFS ];
64 #define F_1 1
65 #define F_2 2
66 #define F_NOLOCALCOPY 4
67 #define F_FULLMATCH 8
69 static int
70 sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
72 char *inpath, *op;
73 int w;
74 char pad[10240];
75 char *s, *t = pad;
76 int was_percent = 0;
77 char *pname; /* name of parent archive */
78 char *pqname; /* name of parent archive, quoted */
80 pname = g_strdup (name);
81 vfs_split (pname, &inpath, &op);
82 if ((w = (*me->which) (me, op)) == -1)
83 vfs_die ("This cannot happen... Hopefully.\n");
85 if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) {
86 g_free (pname);
87 return -1;
90 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
91 if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
92 s = mc_getlocalcopy (pname);
93 if (!s) {
94 g_free (pname);
95 return -1;
97 pqname = name_quote (s, 0);
98 g_free (s);
99 } else {
100 pqname = name_quote (pname, 0);
102 g_free (pname);
104 #define COPY_CHAR \
105 if ((size_t) (t-pad) > sizeof(pad)) { \
106 g_free (pqname); \
107 return -1; \
109 else \
110 *t++ = *s;
112 #define COPY_STRING(a) \
113 if ((t-pad)+strlen(a)>sizeof(pad)) { \
114 g_free (pqname); \
115 return -1; \
116 } else { \
117 strcpy (t, a); \
118 t+= strlen(a); \
121 for (s = sfs_command[w]; *s; s++) {
122 if (was_percent) {
124 const char *ptr = NULL;
125 was_percent = 0;
127 switch (*s) {
128 case '1':
129 ptr = pqname;
130 break;
131 case '2':
132 ptr = op + strlen (sfs_prefix[w]);
133 break;
134 case '3':
135 ptr = cache;
136 break;
137 case '%':
138 COPY_CHAR;
139 continue;
141 COPY_STRING (ptr);
142 } else {
143 if (*s == '%')
144 was_percent = 1;
145 else
146 COPY_CHAR;
150 g_free (pqname);
151 open_error_pipe ();
152 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
153 close_error_pipe (D_ERROR, NULL);
154 return -1;
157 close_error_pipe (D_NORMAL, NULL);
158 return 0; /* OK */
161 static const char *
162 sfs_redirect (struct vfs_class *me, const char *name)
164 struct cachedfile *cur = head;
165 char *cache;
166 int handle;
168 while (cur) {
169 if (!strcmp (name, cur->name)) {
170 vfs_stamp (&vfs_sfs_ops, cur);
171 return cur->cache;
173 cur = cur->next;
176 handle = vfs_mkstemps (&cache, "sfs", name);
178 if (handle == -1) {
179 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
182 close (handle);
184 if (!sfs_vfmake (me, name, cache)) {
185 cur = g_new (struct cachedfile, 1);
186 cur->name = g_strdup (name);
187 cur->cache = cache;
188 cur->next = head;
189 head = cur;
191 vfs_stamp_create (&vfs_sfs_ops, head);
193 return cache;
196 unlink (cache);
197 g_free (cache);
198 return "/I_MUST_NOT_EXIST";
201 static void *
202 sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
204 int *sfs_info;
205 int fd;
207 path = sfs_redirect (me, path);
208 fd = open (path, NO_LINEAR (flags), mode);
209 if (fd == -1)
210 return 0;
212 sfs_info = g_new (int, 1);
213 *sfs_info = fd;
215 return sfs_info;
218 static int sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
220 path = sfs_redirect (me, path);
221 return stat (path, buf);
224 static int sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
226 path = sfs_redirect (me, path);
227 #ifndef HAVE_STATLSTAT
228 return lstat (path, buf);
229 #else
230 return statlstat (path, buf);
231 #endif
234 static int sfs_chmod (struct vfs_class *me, const char *path, int mode)
236 path = sfs_redirect (me, path);
237 return chmod (path, mode);
240 static int sfs_chown (struct vfs_class *me, const char *path, int owner, int group)
242 path = sfs_redirect (me, path);
243 return chown (path, owner, group);
246 static int sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
248 path = sfs_redirect (me, path);
249 return utime (path, times);
252 static int
253 sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
255 path = sfs_redirect (me, path);
256 return readlink (path, buf, size);
259 static vfsid
260 sfs_getid (struct vfs_class *me, const char *path)
262 struct cachedfile *cur = head;
264 (void) me;
266 while (cur) {
267 if (!strcmp (path, cur->name))
268 break;
269 cur = cur->next;
272 return (vfsid) cur;
275 static void sfs_free (vfsid id)
277 struct cachedfile *which = (struct cachedfile *) id;
278 struct cachedfile *cur, *prev;
280 for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
282 if (!cur)
283 vfs_die( "Free of thing which is unknown to me\n" );
284 unlink (cur->cache);
286 if (prev)
287 prev->next = cur->next;
288 else
289 head = cur->next;
291 g_free (cur->cache);
292 g_free (cur->name);
293 g_free (cur);
296 static void sfs_fill_names (struct vfs_class *me, fill_names_f func)
298 struct cachedfile *cur = head;
300 (void) me;
302 while (cur){
303 (*func)(cur->name);
304 cur = cur->next;
308 static int sfs_nothingisopen (vfsid id)
310 /* FIXME: Investigate whether have to guard this like in
311 the other VFSs (see fd_usage in extfs) -- Norbert */
312 (void) id;
313 return 1;
316 static char *
317 sfs_getlocalcopy (struct vfs_class *me, const char *path)
319 path = sfs_redirect (me, path);
320 return g_strdup (path);
323 static int
324 sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
325 const char *local, int has_changed)
327 (void) me;
328 (void) path;
329 (void) local;
330 (void) has_changed;
331 return 0;
334 static int sfs_init (struct vfs_class *me)
336 char *mc_sfsini;
337 FILE *cfg;
338 char key[256];
340 (void) me;
342 mc_sfsini = mhl_str_dir_plus_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
343 cfg = fopen (mc_sfsini, "r");
345 if (!cfg){
346 fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
347 g_free (mc_sfsini);
348 return 0;
350 g_free (mc_sfsini);
352 sfs_no = 0;
353 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg)) {
354 char *c, *semi = NULL, flags = 0;
356 if (*key == '#' || *key == '\n')
357 continue;
359 for (c = key; *c; c++)
360 if ((*c == ':') || (*c == '/')){
361 semi = c;
362 if (*c == '/'){
363 *c = 0;
364 flags |= F_FULLMATCH;
366 break;
369 if (!semi){
370 invalid_line:
371 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
372 "sfs.ini", key);
373 continue;
376 c = semi + 1;
377 while (*c && (*c != ' ') && (*c != '\t')) {
378 switch (*c) {
379 case '1': flags |= F_1; break;
380 case '2': flags |= F_2; break;
381 case 'R': flags |= F_NOLOCALCOPY; break;
382 default:
383 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
384 *c, "sfs.ini", key);
386 c++;
388 if (!*c)
389 goto invalid_line;
390 c++;
391 *(semi+1) = 0;
392 if ((semi = strchr (c, '\n')))
393 *semi = 0;
395 sfs_prefix [sfs_no] = g_strdup (key);
396 sfs_command [sfs_no] = g_strdup (c);
397 sfs_flags [sfs_no] = flags;
398 sfs_no++;
400 fclose (cfg);
401 return 1;
404 static void
405 sfs_done (struct vfs_class *me)
407 int i;
409 (void) me;
411 for (i = 0; i < sfs_no; i++){
412 g_free (sfs_prefix [i]);
413 g_free (sfs_command [i]);
414 sfs_prefix [i] = sfs_command [i] = NULL;
416 sfs_no = 0;
419 static int
420 sfs_which (struct vfs_class *me, const char *path)
422 int i;
424 (void) me;
426 for (i = 0; i < sfs_no; i++)
427 if (sfs_flags [i] & F_FULLMATCH) {
428 if (!strcmp (path, sfs_prefix [i]))
429 return i;
430 } else
431 if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
432 return i;
434 return -1;
437 void
438 init_sfs (void)
440 vfs_sfs_ops.name = "sfs";
441 vfs_sfs_ops.init = sfs_init;
442 vfs_sfs_ops.done = sfs_done;
443 vfs_sfs_ops.fill_names = sfs_fill_names;
444 vfs_sfs_ops.which = sfs_which;
445 vfs_sfs_ops.open = sfs_open;
446 vfs_sfs_ops.close = local_close;
447 vfs_sfs_ops.read = local_read;
448 vfs_sfs_ops.stat = sfs_stat;
449 vfs_sfs_ops.lstat = sfs_lstat;
450 vfs_sfs_ops.fstat = local_fstat;
451 vfs_sfs_ops.chmod = sfs_chmod;
452 vfs_sfs_ops.chown = sfs_chown;
453 vfs_sfs_ops.utime = sfs_utime;
454 vfs_sfs_ops.readlink = sfs_readlink;
455 vfs_sfs_ops.ferrno = local_errno;
456 vfs_sfs_ops.lseek = local_lseek;
457 vfs_sfs_ops.getid = sfs_getid;
458 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
459 vfs_sfs_ops.free = sfs_free;
460 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
461 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
462 vfs_register_class (&vfs_sfs_ops);