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 */
32 #include <sys/types.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 */
47 #include "gc.h" /* vfs_stamp_create */
49 #include "../src/execute.h" /* EXECUTE_AS_SHELL */
53 struct cachedfile
*next
;
56 static struct cachedfile
*head
;
57 static struct vfs_class vfs_sfs_ops
;
60 static int sfs_no
= 0;
61 static char *sfs_prefix
[ MAXFS
];
62 static char *sfs_command
[ MAXFS
];
63 static int sfs_flags
[ MAXFS
];
66 #define F_NOLOCALCOPY 4
70 sfs_vfmake (struct vfs_class
*me
, const char *name
, char *cache
)
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
, "/")) {
90 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
91 if (!(sfs_flags
[w
] & F_NOLOCALCOPY
)) {
92 s
= mc_getlocalcopy (pname
);
97 pqname
= name_quote (s
, 0);
100 pqname
= name_quote (pname
, 0);
105 if ((size_t) (t-pad) > sizeof(pad)) { \
112 #define COPY_STRING(a) \
113 if ((t-pad)+strlen(a)>sizeof(pad)) { \
121 for (s
= sfs_command
[w
]; *s
; s
++) {
124 const char *ptr
= NULL
;
132 ptr
= op
+ strlen (sfs_prefix
[w
]);
152 if (my_system (EXECUTE_AS_SHELL
, "/bin/sh", pad
)) {
153 close_error_pipe (D_ERROR
, NULL
);
157 close_error_pipe (D_NORMAL
, NULL
);
162 sfs_redirect (struct vfs_class
*me
, const char *name
)
164 struct cachedfile
*cur
= head
;
169 if (!strcmp (name
, cur
->name
)) {
170 vfs_stamp (&vfs_sfs_ops
, cur
);
176 handle
= vfs_mkstemps (&cache
, "sfs", name
);
179 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
184 if (!sfs_vfmake (me
, name
, cache
)) {
185 cur
= g_new (struct cachedfile
, 1);
186 cur
->name
= g_strdup (name
);
191 vfs_stamp_create (&vfs_sfs_ops
, head
);
198 return "/I_MUST_NOT_EXIST";
202 sfs_open (struct vfs_class
*me
, const char *path
, int flags
, int mode
)
207 path
= sfs_redirect (me
, path
);
208 fd
= open (path
, NO_LINEAR (flags
), mode
);
212 sfs_info
= g_new (int, 1);
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
);
230 return statlstat (path
, buf
);
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
);
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
);
260 sfs_getid (struct vfs_class
*me
, const char *path
)
262 struct cachedfile
*cur
= head
;
267 if (!strcmp (path
, cur
->name
))
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
)
283 vfs_die( "Free of thing which is unknown to me\n" );
287 prev
->next
= cur
->next
;
296 static void sfs_fill_names (struct vfs_class
*me
, fill_names_f func
)
298 struct cachedfile
*cur
= head
;
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 */
317 sfs_getlocalcopy (struct vfs_class
*me
, const char *path
)
319 path
= sfs_redirect (me
, path
);
320 return g_strdup (path
);
324 sfs_ungetlocalcopy (struct vfs_class
*me
, const char *path
,
325 const char *local
, int has_changed
)
334 static int sfs_init (struct vfs_class
*me
)
342 mc_sfsini
= mhl_str_dir_plus_file (mc_home
, "extfs" PATH_SEP_STR
"sfs.ini");
343 cfg
= fopen (mc_sfsini
, "r");
346 fprintf (stderr
, _("Warning: file %s not found\n"), mc_sfsini
);
353 while (sfs_no
< MAXFS
&& fgets (key
, sizeof (key
), cfg
)) {
354 char *c
, *semi
= NULL
, flags
= 0;
356 if (*key
== '#' || *key
== '\n')
359 for (c
= key
; *c
; c
++)
360 if ((*c
== ':') || (*c
== '/')){
364 flags
|= F_FULLMATCH
;
371 fprintf (stderr
, _("Warning: Invalid line in %s:\n%s\n"),
377 while (*c
&& (*c
!= ' ') && (*c
!= '\t')) {
379 case '1': flags
|= F_1
; break;
380 case '2': flags
|= F_2
; break;
381 case 'R': flags
|= F_NOLOCALCOPY
; break;
383 fprintf (stderr
, _("Warning: Invalid flag %c in %s:\n%s\n"),
392 if ((semi
= strchr (c
, '\n')))
395 sfs_prefix
[sfs_no
] = g_strdup (key
);
396 sfs_command
[sfs_no
] = g_strdup (c
);
397 sfs_flags
[sfs_no
] = flags
;
405 sfs_done (struct vfs_class
*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
;
420 sfs_which (struct vfs_class
*me
, const char *path
)
426 for (i
= 0; i
< sfs_no
; i
++)
427 if (sfs_flags
[i
] & F_FULLMATCH
) {
428 if (!strcmp (path
, sfs_prefix
[i
]))
431 if (!strncmp (path
, sfs_prefix
[i
], strlen (sfs_prefix
[i
])))
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
);