extfs: tester: fix indentation.
[midnight-commander.git] / src / vfs / sfs / sfs.c
blob3447482af1a7b0ed08f9d9b5b67dfe1498d89aa6
1 /*
2 Single File fileSystem
4 Copyright (C) 1998-2017
5 Free Software Foundation, Inc.
7 Written by:
8 Slava Zanko <slavazanko@gmail.com>, 2013
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /**
27 * \file
28 * \brief Source: Single File fileSystem
30 * This defines whole class of filesystems which contain single file
31 * inside. It is somehow similar to extfs, except that extfs makes
32 * whole virtual trees and we do only single virtual files.
34 * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
35 * suffix, DON'T try to gunzip it yourself.
37 * Namespace: exports vfs_sfs_ops
40 #include <config.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <string.h>
47 #include "lib/global.h"
48 #include "lib/util.h"
49 #include "lib/widget.h" /* D_ERROR, D_NORMAL */
51 #include "src/execute.h" /* EXECUTE_AS_SHELL */
53 #include "lib/vfs/vfs.h"
54 #include "lib/vfs/utilvfs.h"
55 #include "src/vfs/local/local.h"
56 #include "lib/vfs/gc.h" /* vfs_stamp_create */
58 #include "sfs.h"
60 /*** global variables ****************************************************************************/
62 /*** file scope macro definitions ****************************************************************/
64 #define MAXFS 32
66 #define F_1 1
67 #define F_2 2
68 #define F_NOLOCALCOPY 4
69 #define F_FULLMATCH 8
71 #define COPY_CHAR \
72 if ((size_t) (t - pad) > sizeof(pad)) \
73 { \
74 g_free (pqname); \
75 return -1; \
76 } \
77 else \
78 *t++ = *s_iter;
80 #define COPY_STRING(a) \
81 if ((t - pad) + strlen(a) > sizeof(pad)) \
82 { \
83 g_free (pqname); \
84 return -1; \
85 } \
86 else \
87 { \
88 strcpy (t, a); \
89 t += strlen (a); \
92 /*** file scope type declarations ****************************************************************/
94 typedef struct cachedfile
96 char *name;
97 char *cache;
98 } cachedfile;
100 /*** file scope variables ************************************************************************/
102 static GSList *head;
103 static struct vfs_class vfs_sfs_ops;
105 static int sfs_no = 0;
106 static char *sfs_prefix[MAXFS];
107 static char *sfs_command[MAXFS];
108 static int sfs_flags[MAXFS];
110 /*** file scope functions ************************************************************************/
112 static int
113 cachedfile_compare (const void *a, const void *b)
115 const cachedfile *cf = (const cachedfile *) a;
116 const char *name = (const char *) b;
118 return strcmp (name, cf->name);
121 /* --------------------------------------------------------------------------------------------- */
123 static int
124 sfs_vfmake (const vfs_path_t * vpath, vfs_path_t * cache_vpath)
126 int w;
127 char pad[10240];
128 char *s_iter, *t = pad;
129 int was_percent = 0;
130 vfs_path_t *pname; /* name of parent archive */
131 char *pqname; /* name of parent archive, quoted */
132 const vfs_path_element_t *path_element;
134 path_element = vfs_path_get_by_index (vpath, -1);
135 pname = vfs_path_clone (vpath);
136 vfs_path_remove_element_by_index (pname, -1);
138 w = (*path_element->class->which) (path_element->class, path_element->vfs_prefix);
139 if (w == -1)
140 vfs_die ("This cannot happen... Hopefully.\n");
142 if ((sfs_flags[w] & F_1) == 0 && strcmp (vfs_path_get_last_path_str (pname), PATH_SEP_STR) != 0)
144 vfs_path_free (pname);
145 return -1;
148 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
149 if ((sfs_flags[w] & F_NOLOCALCOPY) == 0)
151 vfs_path_t *s;
153 s = mc_getlocalcopy (pname);
154 if (s == NULL)
156 vfs_path_free (pname);
157 return -1;
159 pqname = name_quote (vfs_path_get_last_path_str (s), FALSE);
160 vfs_path_free (s);
162 else
163 pqname = name_quote (vfs_path_as_str (pname), FALSE);
165 vfs_path_free (pname);
168 for (s_iter = sfs_command[w]; *s_iter != '\0'; s_iter++)
170 if (was_percent)
172 const char *ptr = NULL;
174 was_percent = 0;
176 switch (*s_iter)
178 case '1':
179 ptr = pqname;
180 break;
181 case '2':
182 ptr = path_element->path;
183 break;
184 case '3':
185 ptr = vfs_path_get_by_index (cache_vpath, -1)->path;
186 break;
187 case '%':
188 COPY_CHAR;
189 continue;
190 default:
191 break;
193 if (ptr != NULL)
195 COPY_STRING (ptr);
198 else
200 if (*s_iter == '%')
201 was_percent = 1;
202 else
203 COPY_CHAR;
207 g_free (pqname);
208 open_error_pipe ();
209 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad))
211 close_error_pipe (D_ERROR, NULL);
212 return -1;
215 close_error_pipe (D_NORMAL, NULL);
216 return 0; /* OK */
219 /* --------------------------------------------------------------------------------------------- */
221 static const char *
222 sfs_redirect (const vfs_path_t * vpath)
224 GSList *cur;
225 cachedfile *cf;
226 vfs_path_t *cache_vpath;
227 int handle;
228 const vfs_path_element_t *path_element;
230 path_element = vfs_path_get_by_index (vpath, -1);
231 cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
233 if (cur != NULL)
235 cf = (cachedfile *) cur->data;
236 vfs_stamp (&vfs_sfs_ops, cf);
237 return cf->cache;
240 handle = vfs_mkstemps (&cache_vpath, "sfs", path_element->path);
242 if (handle == -1)
243 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
245 close (handle);
247 if (sfs_vfmake (vpath, cache_vpath) == 0)
249 cf = g_new (cachedfile, 1);
250 cf->name = g_strdup (vfs_path_as_str (vpath));
251 cf->cache = g_strdup (vfs_path_as_str (cache_vpath));
252 head = g_slist_prepend (head, cf);
253 vfs_path_free (cache_vpath);
255 vfs_stamp_create (&vfs_sfs_ops, (cachedfile *) head->data);
256 return cf->cache;
259 mc_unlink (cache_vpath);
260 vfs_path_free (cache_vpath);
261 return "/I_MUST_NOT_EXIST";
264 /* --------------------------------------------------------------------------------------------- */
266 static void *
267 sfs_open (const vfs_path_t * vpath /*struct vfs_class *me, const char *path */ , int flags,
268 mode_t mode)
270 int *sfs_info;
271 int fd;
273 fd = open (sfs_redirect (vpath), NO_LINEAR (flags), mode);
274 if (fd == -1)
275 return 0;
277 sfs_info = g_new (int, 1);
278 *sfs_info = fd;
280 return sfs_info;
283 /* --------------------------------------------------------------------------------------------- */
285 static int
286 sfs_stat (const vfs_path_t * vpath, struct stat *buf)
288 return stat (sfs_redirect (vpath), buf);
291 /* --------------------------------------------------------------------------------------------- */
293 static int
294 sfs_lstat (const vfs_path_t * vpath, struct stat *buf)
296 #ifndef HAVE_STATLSTAT
297 return lstat (sfs_redirect (vpath), buf);
298 #else
299 return statlstat (sfs_redirect (vpath), buf);
300 #endif
303 /* --------------------------------------------------------------------------------------------- */
305 static int
306 sfs_chmod (const vfs_path_t * vpath, mode_t mode)
308 return chmod (sfs_redirect (vpath), mode);
311 /* --------------------------------------------------------------------------------------------- */
313 static int
314 sfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
316 return chown (sfs_redirect (vpath), owner, group);
319 /* --------------------------------------------------------------------------------------------- */
321 static int
322 sfs_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
324 int ret;
326 #ifdef HAVE_UTIMENSAT
327 ret = utimensat (AT_FDCWD, sfs_redirect (vpath), *times, 0);
328 #else
329 ret = utime (sfs_redirect (vpath), times);
330 #endif
331 return ret;
334 /* --------------------------------------------------------------------------------------------- */
336 static int
337 sfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
339 return readlink (sfs_redirect (vpath), buf, size);
342 /* --------------------------------------------------------------------------------------------- */
344 static vfsid
345 sfs_getid (const vfs_path_t * vpath)
347 GSList *cur;
349 cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
351 return (vfsid) (cur != NULL ? cur->data : NULL);
354 /* --------------------------------------------------------------------------------------------- */
356 static void
357 sfs_free (vfsid id)
359 struct cachedfile *which;
360 GSList *cur;
362 which = (struct cachedfile *) id;
363 cur = g_slist_find (head, which);
364 if (cur == NULL)
365 vfs_die ("Free of thing which is unknown to me\n");
367 which = (struct cachedfile *) cur->data;
368 unlink (which->cache);
369 g_free (which->cache);
370 g_free (which->name);
371 g_free (which);
373 head = g_slist_delete_link (head, cur);
376 /* --------------------------------------------------------------------------------------------- */
378 static void
379 sfs_fill_names (struct vfs_class *me, fill_names_f func)
381 GSList *cur;
383 (void) me;
385 for (cur = head; cur != NULL; cur = g_slist_next (cur))
386 func (((cachedfile *) cur->data)->name);
389 /* --------------------------------------------------------------------------------------------- */
391 static int
392 sfs_nothingisopen (vfsid id)
394 /* FIXME: Investigate whether have to guard this like in
395 the other VFSs (see fd_usage in extfs) -- Norbert */
396 (void) id;
397 return 1;
400 /* --------------------------------------------------------------------------------------------- */
402 static vfs_path_t *
403 sfs_getlocalcopy (const vfs_path_t * vpath)
405 return vfs_path_from_str (sfs_redirect (vpath));
408 /* --------------------------------------------------------------------------------------------- */
410 static int
411 sfs_ungetlocalcopy (const vfs_path_t * vpath, const vfs_path_t * local, gboolean has_changed)
413 (void) vpath;
414 (void) local;
415 (void) has_changed;
416 return 0;
419 /* --------------------------------------------------------------------------------------------- */
421 static int
422 sfs_init (struct vfs_class *me)
424 char *mc_sfsini;
425 FILE *cfg;
426 char key[256];
428 (void) me;
430 mc_sfsini = g_build_filename (mc_global.sysconfig_dir, "sfs.ini", (char *) NULL);
431 cfg = fopen (mc_sfsini, "r");
433 if (cfg == NULL)
435 fprintf (stderr, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini);
436 g_free (mc_sfsini);
437 return 0;
439 g_free (mc_sfsini);
441 sfs_no = 0;
442 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg))
444 char *c, *semi = NULL, flags = 0;
446 if (*key == '#' || *key == '\n')
447 continue;
449 for (c = key; *c; c++)
450 if (*c == ':' || IS_PATH_SEP (*c))
452 semi = c;
453 if (IS_PATH_SEP (*c))
455 *c = '\0';
456 flags |= F_FULLMATCH;
458 break;
461 if (!semi)
463 invalid_line:
464 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
465 continue;
468 c = semi + 1;
469 while (*c != '\0' && !whitespace (*c))
471 switch (*c)
473 case '1':
474 flags |= F_1;
475 break;
476 case '2':
477 flags |= F_2;
478 break;
479 case 'R':
480 flags |= F_NOLOCALCOPY;
481 break;
482 default:
483 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
485 c++;
487 if (!*c)
488 goto invalid_line;
490 c++;
491 *(semi + 1) = 0;
492 semi = strchr (c, '\n');
493 if (semi != NULL)
494 *semi = 0;
496 sfs_prefix[sfs_no] = g_strdup (key);
497 sfs_command[sfs_no] = g_strdup (c);
498 sfs_flags[sfs_no] = flags;
499 sfs_no++;
501 fclose (cfg);
502 return 1;
505 /* --------------------------------------------------------------------------------------------- */
507 static void
508 sfs_done (struct vfs_class *me)
510 int i;
512 (void) me;
514 for (i = 0; i < sfs_no; i++)
516 MC_PTR_FREE (sfs_prefix[i]);
517 MC_PTR_FREE (sfs_command[i]);
519 sfs_no = 0;
522 /* --------------------------------------------------------------------------------------------- */
524 static int
525 sfs_which (struct vfs_class *me, const char *path)
527 int i;
529 (void) me;
531 for (i = 0; i < sfs_no; i++)
532 if (sfs_flags[i] & F_FULLMATCH)
534 if (!strcmp (path, sfs_prefix[i]))
535 return i;
537 else if (!strncmp (path, sfs_prefix[i], strlen (sfs_prefix[i])))
538 return i;
540 return -1;
543 /* --------------------------------------------------------------------------------------------- */
544 /*** public functions ****************************************************************************/
545 /* --------------------------------------------------------------------------------------------- */
547 void
548 init_sfs (void)
550 vfs_sfs_ops.name = "sfs";
551 vfs_sfs_ops.init = sfs_init;
552 vfs_sfs_ops.done = sfs_done;
553 vfs_sfs_ops.fill_names = sfs_fill_names;
554 vfs_sfs_ops.which = sfs_which;
555 vfs_sfs_ops.open = sfs_open;
556 vfs_sfs_ops.close = local_close;
557 vfs_sfs_ops.read = local_read;
558 vfs_sfs_ops.stat = sfs_stat;
559 vfs_sfs_ops.lstat = sfs_lstat;
560 vfs_sfs_ops.fstat = local_fstat;
561 vfs_sfs_ops.chmod = sfs_chmod;
562 vfs_sfs_ops.chown = sfs_chown;
563 vfs_sfs_ops.utime = sfs_utime;
564 vfs_sfs_ops.readlink = sfs_readlink;
565 vfs_sfs_ops.ferrno = local_errno;
566 vfs_sfs_ops.lseek = local_lseek;
567 vfs_sfs_ops.getid = sfs_getid;
568 vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
569 vfs_sfs_ops.free = sfs_free;
570 vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
571 vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
572 vfs_register_class (&vfs_sfs_ops);
575 /* --------------------------------------------------------------------------------------------- */