Changed interface of functions mc_getlocalcopy() and mc_ungetlocalcopy()
[midnight-commander.git] / src / vfs / sfs / sfs.c
blob2ebd487b602b12da0b4333f8c5b40cc548ebd73d
1 /*
2 Single File fileSystem
4 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
5 2011
6 The Free Software Foundation, Inc.
8 This file is part of the Midnight Commander.
10 The Midnight Commander is free software: you can redistribute it
11 and/or modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation, either version 3 of the License,
13 or (at your option) any later version.
15 The Midnight Commander is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /**
25 * \file
26 * \brief Source: Single File fileSystem
28 * This defines whole class of filesystems which contain single file
29 * inside. It is somehow similar to extfs, except that extfs makes
30 * whole virtual trees and we do only single virtual files.
32 * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
33 * suffix, DON'T try to gunzip it yourself.
35 * Namespace: exports vfs_sfs_ops
38 #include <config.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <fcntl.h>
46 #include "lib/global.h"
47 #include "lib/util.h"
48 #include "lib/widget.h" /* D_ERROR, D_NORMAL */
50 #include "src/execute.h" /* EXECUTE_AS_SHELL */
52 #include "lib/vfs/vfs.h"
53 #include "lib/vfs/utilvfs.h"
54 #include "src/vfs/local/local.h"
55 #include "lib/vfs/gc.h" /* vfs_stamp_create */
57 #include "sfs.h"
59 /*** global variables ****************************************************************************/
61 /*** file scope macro definitions ****************************************************************/
63 #define MAXFS 32
65 #define F_1 1
66 #define F_2 2
67 #define F_NOLOCALCOPY 4
68 #define F_FULLMATCH 8
70 #define COPY_CHAR \
71 if ((size_t) (t - pad) > sizeof(pad)) \
72 { \
73 g_free (pqname); \
74 return -1; \
75 } \
76 else \
77 *t++ = *s_iter;
79 #define COPY_STRING(a) \
80 if ((t - pad) + strlen(a) > sizeof(pad)) \
81 { \
82 g_free (pqname); \
83 return -1; \
84 } \
85 else \
86 { \
87 strcpy (t, a); \
88 t += strlen (a); \
91 /*** file scope type declarations ****************************************************************/
93 typedef struct cachedfile
95 char *name;
96 char *cache;
97 } cachedfile;
99 /*** file scope variables ************************************************************************/
101 static GSList *head;
102 static struct vfs_class vfs_sfs_ops;
104 static int sfs_no = 0;
105 static char *sfs_prefix[MAXFS];
106 static char *sfs_command[MAXFS];
107 static int sfs_flags[MAXFS];
109 /*** file scope functions ************************************************************************/
111 static int
112 cachedfile_compare (const void *a, const void *b)
114 const cachedfile *cf = (const cachedfile *) a;
115 const char *name = (const char *) b;
117 return strcmp (name, cf->name);
120 /* --------------------------------------------------------------------------------------------- */
122 static int
123 sfs_vfmake (const vfs_path_t * vpath, vfs_path_t * cache_vpath)
125 int w;
126 char pad[10240];
127 char *s_iter, *t = pad;
128 int was_percent = 0;
129 vfs_path_t *pname, *s; /* name of parent archive */
130 char *pqname; /* name of parent archive, quoted */
131 vfs_path_element_t *path_element;
133 path_element = vfs_path_get_by_index (vpath, -1);
134 pname = vfs_path_clone (vpath);
135 vfs_path_remove_element_by_index (pname, -1);
137 w = (*path_element->class->which) (path_element->class, path_element->vfs_prefix);
138 if (w == -1)
139 vfs_die ("This cannot happen... Hopefully.\n");
141 if ((sfs_flags[w] & F_1) == 0 && strcmp (vfs_path_get_last_path_str (pname), PATH_SEP_STR) != 0)
143 vfs_path_free (pname);
144 return -1;
147 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
148 if ((sfs_flags[w] & F_NOLOCALCOPY) == 0)
150 s = mc_getlocalcopy (pname);
151 if (s == NULL)
153 vfs_path_free (pname);
154 return -1;
156 pqname = name_quote (vfs_path_get_last_path_str (s), 0);
157 vfs_path_free (s);
159 else
161 char *pname_str;
163 pname_str = vfs_path_to_str (pname);
164 pqname = name_quote (pname_str, 0);
165 g_free (pname_str);
167 vfs_path_free (pname);
170 for (s_iter = sfs_command[w]; *s_iter != '\0'; s_iter++)
172 if (was_percent)
174 const char *ptr = NULL;
176 was_percent = 0;
178 switch (*s_iter)
180 case '1':
181 ptr = pqname;
182 break;
183 case '2':
184 ptr = path_element->path;
185 break;
186 case '3':
188 vfs_path_element_t *tmp_path_element;
190 tmp_path_element = vfs_path_get_by_index (cache_vpath, -1);
191 ptr = tmp_path_element->path;
192 break;
194 case '%':
195 COPY_CHAR;
196 continue;
198 COPY_STRING (ptr);
200 else
202 if (*s_iter == '%')
203 was_percent = 1;
204 else
205 COPY_CHAR;
209 g_free (pqname);
210 open_error_pipe ();
211 if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad))
213 close_error_pipe (D_ERROR, NULL);
214 return -1;
217 close_error_pipe (D_NORMAL, NULL);
218 return 0; /* OK */
221 /* --------------------------------------------------------------------------------------------- */
223 static const char *
224 sfs_redirect (const vfs_path_t * vpath)
226 GSList *cur;
227 cachedfile *cf;
228 vfs_path_t *cache_vpath;
229 int handle;
230 vfs_path_element_t *path_element;
231 char *path = vfs_path_to_str (vpath);
233 path_element = vfs_path_get_by_index (vpath, -1);
234 cur = g_slist_find_custom (head, path, cachedfile_compare);
235 g_free (path);
237 if (cur != NULL)
239 cf = (cachedfile *) cur->data;
240 vfs_stamp (&vfs_sfs_ops, cf);
241 return cf->cache;
244 handle = vfs_mkstemps (&cache_vpath, "sfs", path_element->path);
246 if (handle == -1)
247 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
249 close (handle);
251 if (sfs_vfmake (vpath, cache_vpath) == 0)
253 cf = g_new (cachedfile, 1);
254 cf->name = vfs_path_to_str (vpath);
255 cf->cache = vfs_path_to_str (cache_vpath);
256 head = g_slist_prepend (head, cf);
257 vfs_path_free (cache_vpath);
259 vfs_stamp_create (&vfs_sfs_ops, (cachedfile *) head->data);
260 return cf->cache;
263 mc_unlink (cache_vpath);
264 vfs_path_free (cache_vpath);
265 return "/I_MUST_NOT_EXIST";
268 /* --------------------------------------------------------------------------------------------- */
270 static void *
271 sfs_open (const vfs_path_t * vpath /*struct vfs_class *me, const char *path */ , int flags,
272 mode_t mode)
274 int *sfs_info;
275 int fd;
277 fd = open (sfs_redirect (vpath), NO_LINEAR (flags), mode);
278 if (fd == -1)
279 return 0;
281 sfs_info = g_new (int, 1);
282 *sfs_info = fd;
284 return sfs_info;
287 /* --------------------------------------------------------------------------------------------- */
289 static int
290 sfs_stat (const vfs_path_t * vpath, struct stat *buf)
292 return stat (sfs_redirect (vpath), buf);
295 /* --------------------------------------------------------------------------------------------- */
297 static int
298 sfs_lstat (const vfs_path_t * vpath, struct stat *buf)
300 #ifndef HAVE_STATLSTAT
301 return lstat (sfs_redirect (vpath), buf);
302 #else
303 return statlstat (sfs_redirect (vpath), buf);
304 #endif
307 /* --------------------------------------------------------------------------------------------- */
309 static int
310 sfs_chmod (const vfs_path_t * vpath, mode_t mode)
312 return chmod (sfs_redirect (vpath), mode);
315 /* --------------------------------------------------------------------------------------------- */
317 static int
318 sfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
320 return chown (sfs_redirect (vpath), owner, group);
323 /* --------------------------------------------------------------------------------------------- */
325 static int
326 sfs_utime (const vfs_path_t * vpath, struct utimbuf *times)
328 return utime (sfs_redirect (vpath), times);
331 /* --------------------------------------------------------------------------------------------- */
333 static int
334 sfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
336 return readlink (sfs_redirect (vpath), buf, size);
339 /* --------------------------------------------------------------------------------------------- */
341 static vfsid
342 sfs_getid (const vfs_path_t * vpath)
344 GSList *cur;
345 char *path = vfs_path_to_str (vpath);
347 cur = g_slist_find_custom (head, path, cachedfile_compare);
348 g_free (path);
350 return (vfsid) (cur != NULL ? cur->data : NULL);
353 /* --------------------------------------------------------------------------------------------- */
355 static void
356 sfs_free (vfsid id)
358 struct cachedfile *which;
359 GSList *cur;
361 which = (struct cachedfile *) id;
362 cur = g_slist_find (head, which);
363 if (cur == NULL)
364 vfs_die ("Free of thing which is unknown to me\n");
366 which = (struct cachedfile *) cur->data;
367 unlink (which->cache);
368 g_free (which->cache);
369 g_free (which->name);
370 g_free (which);
372 head = g_slist_delete_link (head, cur);
375 /* --------------------------------------------------------------------------------------------- */
377 static void
378 sfs_fill_names (struct vfs_class *me, fill_names_f func)
380 GSList *cur;
382 (void) me;
384 for (cur = head; cur != NULL; cur = g_slist_next (cur))
385 func (((cachedfile *) cur->data)->name);
388 /* --------------------------------------------------------------------------------------------- */
390 static int
391 sfs_nothingisopen (vfsid id)
393 /* FIXME: Investigate whether have to guard this like in
394 the other VFSs (see fd_usage in extfs) -- Norbert */
395 (void) id;
396 return 1;
399 /* --------------------------------------------------------------------------------------------- */
401 static vfs_path_t *
402 sfs_getlocalcopy (const vfs_path_t * vpath)
404 return vfs_path_from_str (sfs_redirect (vpath));
407 /* --------------------------------------------------------------------------------------------- */
409 static int
410 sfs_ungetlocalcopy (const vfs_path_t * vpath, const vfs_path_t * local, gboolean has_changed)
412 (void) vpath;
413 (void) local;
414 (void) has_changed;
415 return 0;
418 /* --------------------------------------------------------------------------------------------- */
420 static int
421 sfs_init (struct vfs_class *me)
423 char *mc_sfsini;
424 FILE *cfg;
425 char key[256];
427 (void) me;
429 mc_sfsini = g_build_filename (mc_global.sysconfig_dir, "sfs.ini", (char *) NULL);
430 cfg = fopen (mc_sfsini, "r");
432 if (cfg == NULL)
434 fprintf (stderr, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini);
435 g_free (mc_sfsini);
436 return 0;
438 g_free (mc_sfsini);
440 sfs_no = 0;
441 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg))
443 char *c, *semi = NULL, flags = 0;
445 if (*key == '#' || *key == '\n')
446 continue;
448 for (c = key; *c; c++)
449 if ((*c == ':') || (*c == '/'))
451 semi = c;
452 if (*c == '/')
454 *c = 0;
455 flags |= F_FULLMATCH;
457 break;
460 if (!semi)
462 invalid_line:
463 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
464 continue;
467 c = semi + 1;
468 while (*c && (*c != ' ') && (*c != '\t'))
470 switch (*c)
472 case '1':
473 flags |= F_1;
474 break;
475 case '2':
476 flags |= F_2;
477 break;
478 case 'R':
479 flags |= F_NOLOCALCOPY;
480 break;
481 default:
482 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
484 c++;
486 if (!*c)
487 goto invalid_line;
489 c++;
490 *(semi + 1) = 0;
491 semi = strchr (c, '\n');
492 if (semi != NULL)
493 *semi = 0;
495 sfs_prefix[sfs_no] = g_strdup (key);
496 sfs_command[sfs_no] = g_strdup (c);
497 sfs_flags[sfs_no] = flags;
498 sfs_no++;
500 fclose (cfg);
501 return 1;
504 /* --------------------------------------------------------------------------------------------- */
506 static void
507 sfs_done (struct vfs_class *me)
509 int i;
511 (void) me;
513 for (i = 0; i < sfs_no; i++)
515 g_free (sfs_prefix[i]);
516 g_free (sfs_command[i]);
517 sfs_prefix[i] = sfs_command[i] = NULL;
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 /* --------------------------------------------------------------------------------------------- */