2 * Single File fileSystem
4 * Copyright 1998 Pavel Machek, distribute under GPL
6 * This defines whole class of filesystems which contain single file
7 * inside. It is somehow similar to extfs, except that extfs makes
8 * whole virtual trees and we do only single virtual files.
10 * If you want to gunzip something, you should open it with #ugz
11 * suffix, DON'T try to gunzip it yourself.
13 * Namespace: exports vfs_sfs_ops */
17 #include <sys/types.h>
30 struct cachedfile
*next
;
33 static struct cachedfile
*head
;
36 static int sfs_no
= 0;
37 static char *sfs_prefix
[ MAXFS
];
38 static char *sfs_command
[ MAXFS
];
39 static int sfs_flags
[ MAXFS
];
42 #define F_NOLOCALCOPY 4
45 static int uptodate (char *name
, char *cache
)
50 static int vfmake (vfs
*me
, char *name
, char *cache
)
58 vfs_split (name
, &inpath
, &op
);
59 if ((w
= (*me
->which
) (me
, op
)) == -1)
60 vfs_die ("This cannot happen... Hopefully.\n");
62 if ((sfs_flags
[w
] & F_1
) || (!strcmp (name
, "/"))) ; else return -1;
63 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
64 if (!(sfs_flags
[w
] & F_NOLOCALCOPY
)) {
65 s
= mc_getlocalcopy (name
);
68 name
= name_quote (s
, 0);
71 name
= name_quote (name
, 0);
72 #define COPY_CHAR if (t-pad>sizeof(pad)) { g_free (name); return -1; } else *t++ = *s;
73 #define COPY_STRING(a) if ((t-pad)+strlen(a)>sizeof(pad)) { g_free (name); return -1; } else { strcpy (t, a); t+= strlen(a); }
74 for (s
= sfs_command
[w
]; *s
; s
++) {
81 case '1': ptr
= name
; break;
82 case '2': ptr
= op
+ strlen (sfs_prefix
[w
]); break;
83 case '3': ptr
= cache
; break;
84 case '%': COPY_CHAR
; continue;
96 if (my_system (EXECUTE_AS_SHELL
, "/bin/sh", pad
)) {
104 redirect (vfs
*me
, char *name
)
106 struct cachedfile
*cur
= head
;
112 if ((!strcmp (name
, cur
->name
)) &&
114 (uptodate (cur
->name
, cur
->cache
)))
115 /* FIXME: when not uptodate, we might want to kill cache
116 * file immediately, not to wait until timeout. */ {
117 vfs_stamp (&vfs_sfs_ops
, cur
);
123 handle
= mc_mkstemps (&cache
, "sfs", NULL
);
126 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
131 if (!vfmake (me
, name
, cache
)){
132 cur
= g_new (struct cachedfile
, 1);
133 cur
->name
= g_strdup (name
);
139 vfs_add_noncurrent_stamps (&vfs_sfs_ops
, (vfsid
) head
, NULL
);
140 vfs_rm_parents (NULL
);
147 return "/I_MUST_NOT_EXIST";
151 sfs_open (vfs
*me
, char *path
, int flags
, int mode
)
156 path
= redirect (me
, path
);
157 fd
= open (path
, NO_LINEAR(flags
), mode
);
161 sfs_info
= g_new (int, 1);
167 static int sfs_stat (vfs
*me
, char *path
, struct stat
*buf
)
169 path
= redirect (me
, path
);
170 return stat (path
, buf
);
173 static int sfs_lstat (vfs
*me
, char *path
, struct stat
*buf
)
175 path
= redirect (me
, path
);
176 #ifndef HAVE_STATLSTAT
177 return lstat (path
, buf
);
179 return statlstat (path
, buf
);
183 static int sfs_chmod (vfs
*me
, char *path
, int mode
)
185 path
= redirect (me
, path
);
186 return chmod (path
, mode
);
189 static int sfs_chown (vfs
*me
, char *path
, int owner
, int group
)
191 path
= redirect (me
, path
);
192 return chown (path
, owner
, group
);
195 static int sfs_utime (vfs
*me
, char *path
, struct utimbuf
*times
)
197 path
= redirect (me
, path
);
198 return utime (path
, times
);
201 static int sfs_readlink (vfs
*me
, char *path
, char *buf
, int size
)
203 path
= redirect (me
, path
);
204 return readlink (path
, buf
, size
);
207 static vfsid
sfs_getid (vfs
*me
, char *path
, struct vfs_stamping
**parent
)
208 { /* FIXME: what should I do? */
211 struct vfs_stamping
*par
;
212 struct cachedfile
*cur
= head
;
215 if ((!strcmp( path
, cur
->name
)) &&
216 (vfs_uid
== cur
->uid
))
227 char *path2
= g_strdup (path
);
228 v
= vfs_split (path2
, NULL
, NULL
); /* Strip suffix which led to this being sfs */
229 v
= vfs_split (path2
, NULL
, NULL
); /* ... and learn whoever was the parent system */
230 id
= (*v
->getid
) (v
, path2
, &par
);
234 if (id
!= (vfsid
)-1) {
235 *parent
= g_new (struct vfs_stamping
, 1);
238 (*parent
)->parent
= par
;
239 (*parent
)->next
= NULL
;
244 static void sfs_free (vfsid id
)
246 struct cachedfile
*which
= (struct cachedfile
*) id
;
247 struct cachedfile
*cur
, *prev
;
249 for (cur
= head
, prev
= 0; cur
&& cur
!= which
; prev
= cur
, cur
= cur
->next
)
252 vfs_die( "Free of thing which is unknown to me\n" );
256 prev
->next
= cur
->next
;
265 static void sfs_fill_names (vfs
*me
, void (*func
)(char *))
267 struct cachedfile
*cur
= head
;
275 static int sfs_nothingisopen (vfsid id
)
277 /* FIXME: Investigate whether have to guard this like in
278 the other VFSs (see fd_usage in extfs) -- Norbert */
282 static char *sfs_getlocalcopy (vfs
*me
, char *path
)
284 path
= redirect (me
, path
);
285 return g_strdup (path
);
288 static int sfs_ungetlocalcopy (vfs
*me
, char *path
, char *local
, int has_changed
)
294 static int sfs_init (vfs
*me
)
299 mc_sfsini
= concat_dir_and_file (mc_home
, "extfs" PATH_SEP_STR
"sfs.ini");
300 cfg
= fopen (mc_sfsini
, "r");
303 fprintf (stderr
, _("Warning: file %s not found\n"), mc_sfsini
);
310 while (sfs_no
< MAXFS
){
312 char *c
, *semi
= NULL
, flags
= 0;
314 if (!fgets (key
, sizeof (key
), cfg
))
320 for (c
= key
; *c
; c
++)
321 if ((*c
== ':') || (*c
== '/')){
325 flags
|= F_FULLMATCH
;
331 fprintf (stderr
, _("Warning: Invalid line in %s:\n%s\n"),
337 while ((*c
!= ' ') && (*c
!= '\t')) {
339 case '1': flags
|= F_1
; break;
340 case '2': flags
|= F_2
; break;
341 case 'R': flags
|= F_NOLOCALCOPY
; break;
343 fprintf (stderr
, _("Warning: Invalid flag %c in %s:\n%s\n"),
350 if ((semi
= strchr (c
, '\n')))
353 sfs_prefix
[sfs_no
] = g_strdup (key
);
354 sfs_command
[sfs_no
] = g_strdup (c
);
355 sfs_flags
[sfs_no
] = flags
;
367 for (i
= 0; i
< sfs_no
; i
++){
368 g_free (sfs_prefix
[i
]);
369 g_free (sfs_command
[i
]);
370 sfs_prefix
[i
] = sfs_command
[i
] = NULL
;
376 sfs_which (vfs
*me
, char *path
)
380 for (i
= 0; i
< sfs_no
; i
++)
381 if (sfs_flags
[i
] & F_FULLMATCH
) {
382 if (!strcmp (path
, sfs_prefix
[i
]))
385 if (!strncmp (path
, sfs_prefix
[i
], strlen (sfs_prefix
[i
])))
392 NULL
, /* This is place of next pointer */