2 * Single File fileSystem
4 * Copyright 1998 Pavel Machek, distribute under GPL
8 * This defines whole class of filesystems which contain single file
9 * inside. It is somehow similar to extfs, except that extfs makes
10 * whole virtual trees and we do only single virtual files.
12 * If you want to gunzip something, you should open it with #ugz
13 * suffix, DON'T try to gunzip it yourself.
15 * Namespace: exports vfs_sfs_ops */
19 #include <sys/types.h>
32 struct cachedfile
*next
;
35 static struct cachedfile
*head
;
38 static int sfs_no
= 0;
39 static char *sfs_prefix
[ MAXFS
];
40 static char *sfs_command
[ MAXFS
];
41 static int sfs_flags
[ MAXFS
];
44 #define F_NOLOCALCOPY 4
47 static int uptodate (char *name
, char *cache
)
52 static int vfmake (vfs
*me
, char *name
, char *cache
)
60 vfs_split (name
, &inpath
, &op
);
61 if ((w
= (*me
->which
) (me
, op
)) == -1)
62 vfs_die ("This cannot happen... Hopefully.\n");
64 if ((sfs_flags
[w
] & F_1
) || (!strcmp (name
, "/"))) ; else return -1;
65 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
66 if (!(sfs_flags
[w
] & F_NOLOCALCOPY
)) {
67 s
= mc_getlocalcopy (name
);
70 name
= name_quote (s
, 0);
73 name
= name_quote (name
, 0);
74 #define COPY_CHAR if (t-pad>sizeof(pad)) { g_free (name); return -1; } else *t++ = *s;
75 #define COPY_STRING(a) if ((t-pad)+strlen(a)>sizeof(pad)) { g_free (name); return -1; } else { strcpy (t, a); t+= strlen(a); }
76 for (s
= sfs_command
[w
]; *s
; s
++) {
83 case '1': ptr
= name
; break;
84 case '2': ptr
= op
+ strlen (sfs_prefix
[w
]); break;
85 case '3': ptr
= cache
; break;
86 case '%': COPY_CHAR
; continue;
98 if (my_system (EXECUTE_AS_SHELL
, "/bin/sh", pad
)) {
106 redirect (vfs
*me
, char *name
)
108 struct cachedfile
*cur
= head
;
114 if ((!strcmp (name
, cur
->name
)) &&
116 (uptodate (cur
->name
, cur
->cache
)))
117 /* FIXME: when not uptodate, we might want to kill cache
118 * file immediately, not to wait until timeout. */ {
119 vfs_stamp (&vfs_sfs_ops
, cur
);
125 handle
= mc_mkstemps (&cache
, "sfs", NULL
);
128 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
133 if (!vfmake (me
, name
, cache
)){
134 cur
= g_new (struct cachedfile
, 1);
135 cur
->name
= g_strdup (name
);
141 vfs_add_noncurrent_stamps (&vfs_sfs_ops
, (vfsid
) head
, NULL
);
142 vfs_rm_parents (NULL
);
149 return "/I_MUST_NOT_EXIST";
153 sfs_open (vfs
*me
, char *path
, int flags
, int mode
)
158 path
= redirect (me
, path
);
159 fd
= open (path
, NO_LINEAR(flags
), mode
);
163 sfs_info
= g_new (int, 1);
169 static int sfs_stat (vfs
*me
, char *path
, struct stat
*buf
)
171 path
= redirect (me
, path
);
172 return stat (path
, buf
);
175 static int sfs_lstat (vfs
*me
, char *path
, struct stat
*buf
)
177 path
= redirect (me
, path
);
178 #ifndef HAVE_STATLSTAT
179 return lstat (path
, buf
);
181 return statlstat (path
, buf
);
185 static int sfs_chmod (vfs
*me
, char *path
, int mode
)
187 path
= redirect (me
, path
);
188 return chmod (path
, mode
);
191 static int sfs_chown (vfs
*me
, char *path
, int owner
, int group
)
193 path
= redirect (me
, path
);
194 return chown (path
, owner
, group
);
197 static int sfs_utime (vfs
*me
, char *path
, struct utimbuf
*times
)
199 path
= redirect (me
, path
);
200 return utime (path
, times
);
203 static int sfs_readlink (vfs
*me
, char *path
, char *buf
, int size
)
205 path
= redirect (me
, path
);
206 return readlink (path
, buf
, size
);
209 static vfsid
sfs_getid (vfs
*me
, char *path
, struct vfs_stamping
**parent
)
210 { /* FIXME: what should I do? */
213 struct vfs_stamping
*par
;
214 struct cachedfile
*cur
= head
;
217 if ((!strcmp( path
, cur
->name
)) &&
218 (vfs_uid
== cur
->uid
))
229 char *path2
= g_strdup (path
);
230 v
= vfs_split (path2
, NULL
, NULL
); /* Strip suffix which led to this being sfs */
231 v
= vfs_split (path2
, NULL
, NULL
); /* ... and learn whoever was the parent system */
232 id
= (*v
->getid
) (v
, path2
, &par
);
236 if (id
!= (vfsid
)-1) {
237 *parent
= g_new (struct vfs_stamping
, 1);
240 (*parent
)->parent
= par
;
241 (*parent
)->next
= NULL
;
246 static void sfs_free (vfsid id
)
248 struct cachedfile
*which
= (struct cachedfile
*) id
;
249 struct cachedfile
*cur
, *prev
;
251 for (cur
= head
, prev
= 0; cur
&& cur
!= which
; prev
= cur
, cur
= cur
->next
)
254 vfs_die( "Free of thing which is unknown to me\n" );
258 prev
->next
= cur
->next
;
267 static void sfs_fill_names (vfs
*me
, void (*func
)(char *))
269 struct cachedfile
*cur
= head
;
277 static int sfs_nothingisopen (vfsid id
)
279 /* FIXME: Investigate whether have to guard this like in
280 the other VFSs (see fd_usage in extfs) -- Norbert */
284 static char *sfs_getlocalcopy (vfs
*me
, char *path
)
286 path
= redirect (me
, path
);
287 return g_strdup (path
);
290 static int sfs_ungetlocalcopy (vfs
*me
, char *path
, char *local
, int has_changed
)
296 static int sfs_init (vfs
*me
)
301 mc_sfsini
= concat_dir_and_file (mc_home
, "extfs" PATH_SEP_STR
"sfs.ini");
302 cfg
= fopen (mc_sfsini
, "r");
305 fprintf (stderr
, _("Warning: file %s not found\n"), mc_sfsini
);
312 while (sfs_no
< MAXFS
){
314 char *c
, *semi
= NULL
, flags
= 0;
316 if (!fgets (key
, sizeof (key
), cfg
))
322 for (c
= key
; *c
; c
++)
323 if ((*c
== ':') || (*c
== '/')){
327 flags
|= F_FULLMATCH
;
333 fprintf (stderr
, _("Warning: Invalid line in sfs.ini:\n%s\n"), key
);
338 while ((*c
!= ' ') && (*c
!= '\t')) {
340 case '1': flags
|= F_1
; break;
341 case '2': flags
|= F_2
; break;
342 case 'R': flags
|= F_NOLOCALCOPY
; break;
344 fprintf (stderr
, _("Warning: Invalid flag %c in sfs.ini:\n%s\n"), *c
, key
);
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 */