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.
24 * \brief Source: Single File fileSystem
26 * This defines whole class of filesystems which contain single file
27 * inside. It is somehow similar to extfs, except that extfs makes
28 * whole virtual trees and we do only single virtual files.
30 * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
31 * suffix, DON'T try to gunzip it yourself.
33 * Namespace: exports vfs_sfs_ops
38 #include <sys/types.h>
44 #include "lib/global.h"
46 #include "lib/widget.h" /* D_ERROR, D_NORMAL */
48 #include "src/execute.h" /* EXECUTE_AS_SHELL */
50 #include "lib/vfs/vfs.h"
51 #include "lib/vfs/utilvfs.h"
52 #include "src/vfs/local/local.h"
53 #include "lib/vfs/gc.h" /* vfs_stamp_create */
57 /*** global variables ****************************************************************************/
59 /*** file scope macro definitions ****************************************************************/
65 #define F_NOLOCALCOPY 4
69 if ((size_t) (t - pad) > sizeof(pad)) \
77 #define COPY_STRING(a) \
78 if ((t - pad) + strlen(a) > sizeof(pad)) \
89 /*** file scope type declarations ****************************************************************/
91 typedef struct cachedfile
97 /*** file scope variables ************************************************************************/
100 static struct vfs_class vfs_sfs_ops
;
102 static int sfs_no
= 0;
103 static char *sfs_prefix
[MAXFS
];
104 static char *sfs_command
[MAXFS
];
105 static int sfs_flags
[MAXFS
];
107 /*** file scope functions ************************************************************************/
110 cachedfile_compare (const void *a
, const void *b
)
112 const cachedfile
*cf
= (const cachedfile
*) a
;
113 const char *name
= (const char *) b
;
115 return strcmp (name
, cf
->name
);
118 /* --------------------------------------------------------------------------------------------- */
121 sfs_vfmake (struct vfs_class
*me
, const char *name
, char *cache
)
128 char *pname
; /* name of parent archive */
129 char *pqname
; /* name of parent archive, quoted */
131 pname
= g_strdup (name
);
132 vfs_split (pname
, &inpath
, &op
);
133 w
= (*me
->which
) (me
, op
);
135 vfs_die ("This cannot happen... Hopefully.\n");
137 if (!(sfs_flags
[w
] & F_1
) && strcmp (pname
, "/"))
143 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
144 if (!(sfs_flags
[w
] & F_NOLOCALCOPY
))
146 s
= mc_getlocalcopy (pname
);
152 pqname
= name_quote (s
, 0);
157 pqname
= name_quote (pname
, 0);
162 for (s
= sfs_command
[w
]; *s
; s
++)
167 const char *ptr
= NULL
;
176 ptr
= op
+ strlen (sfs_prefix
[w
]);
198 if (my_system (EXECUTE_AS_SHELL
, "/bin/sh", pad
))
200 close_error_pipe (D_ERROR
, NULL
);
204 close_error_pipe (D_NORMAL
, NULL
);
208 /* --------------------------------------------------------------------------------------------- */
211 sfs_redirect (struct vfs_class
*me
, const char *name
)
218 cur
= g_slist_find_custom (head
, name
, cachedfile_compare
);
221 cf
= (cachedfile
*) cur
->data
;
222 vfs_stamp (&vfs_sfs_ops
, cf
);
226 handle
= vfs_mkstemps (&cache
, "sfs", name
);
229 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
233 if (sfs_vfmake (me
, name
, cache
) == 0)
235 cf
= g_new (cachedfile
, 1);
236 cf
->name
= g_strdup (name
);
238 head
= g_slist_prepend (head
, cf
);
240 vfs_stamp_create (&vfs_sfs_ops
, (cachedfile
*) head
->data
);
246 return "/I_MUST_NOT_EXIST";
249 /* --------------------------------------------------------------------------------------------- */
252 sfs_open (const vfs_path_t
* vpath
/*struct vfs_class *me, const char *path */ , int flags
,
258 vfs_path_element_t
*path_element
;
260 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
261 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
262 fd
= open (path
, NO_LINEAR (flags
), mode
);
266 sfs_info
= g_new (int, 1);
272 /* --------------------------------------------------------------------------------------------- */
275 sfs_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
277 vfs_path_element_t
*path_element
;
280 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
281 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
282 return stat (path
, buf
);
285 /* --------------------------------------------------------------------------------------------- */
288 sfs_lstat (const vfs_path_t
* vpath
, struct stat
*buf
)
290 vfs_path_element_t
*path_element
;
293 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
294 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
295 #ifndef HAVE_STATLSTAT
296 return lstat (path
, buf
);
298 return statlstat (path
, buf
);
302 /* --------------------------------------------------------------------------------------------- */
305 sfs_chmod (const vfs_path_t
* vpath
, int mode
)
308 vfs_path_element_t
*path_element
;
310 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
312 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
313 return chmod (path
, mode
);
316 /* --------------------------------------------------------------------------------------------- */
319 sfs_chown (const vfs_path_t
* vpath
, uid_t owner
, gid_t group
)
322 vfs_path_element_t
*path_element
;
324 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
326 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
327 return chown (path
, owner
, group
);
330 /* --------------------------------------------------------------------------------------------- */
333 sfs_utime (const vfs_path_t
* vpath
, struct utimbuf
*times
)
336 vfs_path_element_t
*path_element
;
338 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
340 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
341 return utime (path
, times
);
344 /* --------------------------------------------------------------------------------------------- */
347 sfs_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
350 vfs_path_element_t
*path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
351 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
352 return readlink (path
, buf
, size
);
355 /* --------------------------------------------------------------------------------------------- */
358 sfs_getid (const vfs_path_t
* vpath
)
362 cur
= g_slist_find_custom (head
, vpath
->unparsed
, cachedfile_compare
);
364 return (vfsid
) (cur
!= NULL
? cur
->data
: NULL
);
367 /* --------------------------------------------------------------------------------------------- */
372 struct cachedfile
*which
;
375 which
= (struct cachedfile
*) id
;
376 cur
= g_slist_find (head
, which
);
378 vfs_die ("Free of thing which is unknown to me\n");
380 which
= (struct cachedfile
*) cur
->data
;
381 unlink (which
->cache
);
382 g_free (which
->cache
);
383 g_free (which
->name
);
386 head
= g_slist_delete_link (head
, cur
);
389 /* --------------------------------------------------------------------------------------------- */
392 sfs_fill_names (struct vfs_class
*me
, fill_names_f func
)
398 for (cur
= head
; cur
!= NULL
; cur
= g_slist_next (cur
))
399 func (((cachedfile
*) cur
->data
)->name
);
402 /* --------------------------------------------------------------------------------------------- */
405 sfs_nothingisopen (vfsid id
)
407 /* FIXME: Investigate whether have to guard this like in
408 the other VFSs (see fd_usage in extfs) -- Norbert */
413 /* --------------------------------------------------------------------------------------------- */
416 sfs_getlocalcopy (const vfs_path_t
* vpath
)
418 vfs_path_element_t
*path_element
;
421 path_element
= vfs_path_get_by_index (vpath
, vfs_path_length (vpath
) - 1);
422 path
= sfs_redirect (path_element
->class, vpath
->unparsed
);
423 return g_strdup (path
);
426 /* --------------------------------------------------------------------------------------------- */
429 sfs_ungetlocalcopy (const vfs_path_t
* vpath
, const char *local
, int has_changed
)
437 /* --------------------------------------------------------------------------------------------- */
440 sfs_init (struct vfs_class
*me
)
448 mc_sfsini
= g_build_filename (mc_global
.sysconfig_dir
, "sfs.ini", (char *) NULL
);
449 cfg
= fopen (mc_sfsini
, "r");
453 fprintf (stderr
, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini
);
460 while (sfs_no
< MAXFS
&& fgets (key
, sizeof (key
), cfg
))
462 char *c
, *semi
= NULL
, flags
= 0;
464 if (*key
== '#' || *key
== '\n')
467 for (c
= key
; *c
; c
++)
468 if ((*c
== ':') || (*c
== '/'))
474 flags
|= F_FULLMATCH
;
482 fprintf (stderr
, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key
);
487 while (*c
&& (*c
!= ' ') && (*c
!= '\t'))
498 flags
|= F_NOLOCALCOPY
;
501 fprintf (stderr
, _("Warning: Invalid flag %c in %s:\n%s\n"), *c
, "sfs.ini", key
);
510 semi
= strchr (c
, '\n');
514 sfs_prefix
[sfs_no
] = g_strdup (key
);
515 sfs_command
[sfs_no
] = g_strdup (c
);
516 sfs_flags
[sfs_no
] = flags
;
523 /* --------------------------------------------------------------------------------------------- */
526 sfs_done (struct vfs_class
*me
)
532 for (i
= 0; i
< sfs_no
; i
++)
534 g_free (sfs_prefix
[i
]);
535 g_free (sfs_command
[i
]);
536 sfs_prefix
[i
] = sfs_command
[i
] = NULL
;
541 /* --------------------------------------------------------------------------------------------- */
544 sfs_which (struct vfs_class
*me
, const char *path
)
550 for (i
= 0; i
< sfs_no
; i
++)
551 if (sfs_flags
[i
] & F_FULLMATCH
)
553 if (!strcmp (path
, sfs_prefix
[i
]))
556 else if (!strncmp (path
, sfs_prefix
[i
], strlen (sfs_prefix
[i
])))
562 /* --------------------------------------------------------------------------------------------- */
563 /*** public functions ****************************************************************************/
564 /* --------------------------------------------------------------------------------------------- */
569 vfs_sfs_ops
.name
= "sfs";
570 vfs_sfs_ops
.init
= sfs_init
;
571 vfs_sfs_ops
.done
= sfs_done
;
572 vfs_sfs_ops
.fill_names
= sfs_fill_names
;
573 vfs_sfs_ops
.which
= sfs_which
;
574 vfs_sfs_ops
.open
= sfs_open
;
575 vfs_sfs_ops
.close
= local_close
;
576 vfs_sfs_ops
.read
= local_read
;
577 vfs_sfs_ops
.stat
= sfs_stat
;
578 vfs_sfs_ops
.lstat
= sfs_lstat
;
579 vfs_sfs_ops
.fstat
= local_fstat
;
580 vfs_sfs_ops
.chmod
= sfs_chmod
;
581 vfs_sfs_ops
.chown
= sfs_chown
;
582 vfs_sfs_ops
.utime
= sfs_utime
;
583 vfs_sfs_ops
.readlink
= sfs_readlink
;
584 vfs_sfs_ops
.ferrno
= local_errno
;
585 vfs_sfs_ops
.lseek
= local_lseek
;
586 vfs_sfs_ops
.getid
= sfs_getid
;
587 vfs_sfs_ops
.nothingisopen
= sfs_nothingisopen
;
588 vfs_sfs_ops
.free
= sfs_free
;
589 vfs_sfs_ops
.getlocalcopy
= sfs_getlocalcopy
;
590 vfs_sfs_ops
.ungetlocalcopy
= sfs_ungetlocalcopy
;
591 vfs_register_class (&vfs_sfs_ops
);
594 /* --------------------------------------------------------------------------------------------- */