sfs.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * Single File fileSystem
  3. *
  4. * Copyright 1998 Pavel Machek, distribute under GPL
  5. *
  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.
  9. *
  10. * If you want to gunzip something, you should open it with #ugz
  11. * suffix, DON'T try to gunzip it yourself.
  12. *
  13. * Namespace: exports vfs_sfs_ops */
  14. #include <config.h>
  15. #include <errno.h>
  16. #include <sys/types.h>
  17. #include <unistd.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include "utilvfs.h"
  21. #include "vfs.h"
  22. #include "local.h"
  23. #include "../src/execute.h" /* EXECUTE_AS_SHELL */
  24. struct cachedfile {
  25. char *name, *cache;
  26. struct cachedfile *next;
  27. };
  28. static struct cachedfile *head;
  29. static struct vfs_class vfs_sfs_ops;
  30. #define MAXFS 32
  31. static int sfs_no = 0;
  32. static char *sfs_prefix[ MAXFS ];
  33. static char *sfs_command[ MAXFS ];
  34. static int sfs_flags[ MAXFS ];
  35. #define F_1 1
  36. #define F_2 2
  37. #define F_NOLOCALCOPY 4
  38. #define F_FULLMATCH 8
  39. static int
  40. sfs_uptodate (char *name, char *cache)
  41. {
  42. return 1;
  43. }
  44. static int
  45. sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
  46. {
  47. char *inpath, *op;
  48. int w;
  49. char pad[10240];
  50. char *s, *t = pad;
  51. int was_percent = 0;
  52. vfs_split (name, &inpath, &op);
  53. if ((w = (*me->which) (me, op)) == -1)
  54. vfs_die ("This cannot happen... Hopefully.\n");
  55. if ((sfs_flags[w] & F_1) || (!strcmp (name, "/")));
  56. else
  57. return -1;
  58. /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
  59. if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
  60. s = mc_getlocalcopy (name);
  61. if (!s)
  62. return -1;
  63. name = name_quote (s, 0);
  64. g_free (s);
  65. } else
  66. name = name_quote (name, 0);
  67. #define COPY_CHAR if (t-pad>sizeof(pad)) { return -1; } else *t++ = *s;
  68. #define COPY_STRING(a) if ((t-pad)+strlen(a)>sizeof(pad)) { return -1; } else { strcpy (t, a); t+= strlen(a); }
  69. for (s = sfs_command[w]; *s; s++) {
  70. if (was_percent) {
  71. const char *ptr = NULL;
  72. was_percent = 0;
  73. switch (*s) {
  74. case '1':
  75. ptr = name;
  76. break;
  77. case '2':
  78. ptr = op + strlen (sfs_prefix[w]);
  79. break;
  80. case '3':
  81. ptr = cache;
  82. break;
  83. case '%':
  84. COPY_CHAR;
  85. continue;
  86. }
  87. COPY_STRING (ptr);
  88. } else {
  89. if (*s == '%')
  90. was_percent = 1;
  91. else
  92. COPY_CHAR;
  93. }
  94. }
  95. open_error_pipe ();
  96. if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
  97. close_error_pipe (1, NULL);
  98. return -1;
  99. }
  100. close_error_pipe (0, NULL);
  101. return 0; /* OK */
  102. }
  103. static char *
  104. sfs_redirect (struct vfs_class *me, const char *name)
  105. {
  106. struct cachedfile *cur = head;
  107. char *cache;
  108. int handle;
  109. while (cur) {
  110. if ((!strcmp (name, cur->name))
  111. && (sfs_uptodate (cur->name, cur->cache))) {
  112. vfs_stamp (&vfs_sfs_ops, cur);
  113. return cur->cache;
  114. }
  115. cur = cur->next;
  116. }
  117. handle = mc_mkstemps (&cache, "sfs", NULL);
  118. if (handle == -1) {
  119. return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
  120. }
  121. close (handle);
  122. if (!sfs_vfmake (me, name, cache)) {
  123. cur = g_new (struct cachedfile, 1);
  124. cur->name = g_strdup (name);
  125. cur->cache = cache;
  126. cur->next = head;
  127. head = cur;
  128. vfs_add_noncurrent_stamps (&vfs_sfs_ops, (vfsid) head, NULL);
  129. return cache;
  130. }
  131. unlink (cache);
  132. g_free (cache);
  133. return "/I_MUST_NOT_EXIST";
  134. }
  135. static void *
  136. sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
  137. {
  138. int *sfs_info;
  139. int fd;
  140. path = sfs_redirect (me, path);
  141. fd = open (path, NO_LINEAR (flags), mode);
  142. if (fd == -1)
  143. return 0;
  144. sfs_info = g_new (int, 1);
  145. *sfs_info = fd;
  146. return sfs_info;
  147. }
  148. static int sfs_stat (struct vfs_class *me, char *path, struct stat *buf)
  149. {
  150. path = sfs_redirect (me, path);
  151. return stat (path, buf);
  152. }
  153. static int sfs_lstat (struct vfs_class *me, char *path, struct stat *buf)
  154. {
  155. path = sfs_redirect (me, path);
  156. #ifndef HAVE_STATLSTAT
  157. return lstat (path, buf);
  158. #else
  159. return statlstat (path, buf);
  160. #endif
  161. }
  162. static int sfs_chmod (struct vfs_class *me, char *path, int mode)
  163. {
  164. path = sfs_redirect (me, path);
  165. return chmod (path, mode);
  166. }
  167. static int sfs_chown (struct vfs_class *me, char *path, int owner, int group)
  168. {
  169. path = sfs_redirect (me, path);
  170. return chown (path, owner, group);
  171. }
  172. static int sfs_utime (struct vfs_class *me, char *path, struct utimbuf *times)
  173. {
  174. path = sfs_redirect (me, path);
  175. return utime (path, times);
  176. }
  177. static int sfs_readlink (struct vfs_class *me, char *path, char *buf, int size)
  178. {
  179. path = sfs_redirect (me, path);
  180. return readlink (path, buf, size);
  181. }
  182. static vfsid
  183. sfs_getid (struct vfs_class *me, const char *path, struct vfs_stamping **parent)
  184. { /* FIXME: what should I do? */
  185. struct vfs_class *v;
  186. vfsid id;
  187. struct vfs_stamping *par;
  188. struct cachedfile *cur = head;
  189. while (cur) {
  190. if (!strcmp (path, cur->name))
  191. break;
  192. cur = cur->next;
  193. }
  194. *parent = NULL;
  195. if (!cur)
  196. return (vfsid) (-1);
  197. {
  198. char *path2 = g_strdup (path);
  199. /* Strip suffix which led to this being sfs */
  200. v = vfs_split (path2, NULL, NULL);
  201. /* ... and learn whoever was the parent system */
  202. v = vfs_split (path2, NULL, NULL);
  203. id = (*v->getid) (v, path2, &par);
  204. g_free (path2);
  205. }
  206. if (id != (vfsid) - 1) {
  207. *parent = g_new (struct vfs_stamping, 1);
  208. (*parent)->v = v;
  209. (*parent)->id = id;
  210. (*parent)->parent = par;
  211. (*parent)->next = NULL;
  212. }
  213. return (vfsid) cur;
  214. }
  215. static void sfs_free (vfsid id)
  216. {
  217. struct cachedfile *which = (struct cachedfile *) id;
  218. struct cachedfile *cur, *prev;
  219. for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
  220. ;
  221. if (!cur)
  222. vfs_die( "Free of thing which is unknown to me\n" );
  223. unlink (cur->cache);
  224. if (prev)
  225. prev->next = cur->next;
  226. else
  227. head = cur->next;
  228. g_free (cur->cache);
  229. g_free (cur->name);
  230. g_free (cur);
  231. }
  232. static void sfs_fill_names (struct vfs_class *me, void (*func)(char *))
  233. {
  234. struct cachedfile *cur = head;
  235. while (cur){
  236. (*func)(cur->name);
  237. cur = cur->next;
  238. }
  239. }
  240. static int sfs_nothingisopen (vfsid id)
  241. {
  242. /* FIXME: Investigate whether have to guard this like in
  243. the other VFSs (see fd_usage in extfs) -- Norbert */
  244. return 1;
  245. }
  246. static char *
  247. sfs_getlocalcopy (struct vfs_class *me, const char *path)
  248. {
  249. path = sfs_redirect (me, path);
  250. return g_strdup (path);
  251. }
  252. static int
  253. sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
  254. const char *local, int has_changed)
  255. {
  256. return 0;
  257. }
  258. static int sfs_init (struct vfs_class *me)
  259. {
  260. char *mc_sfsini;
  261. FILE *cfg;
  262. mc_sfsini = concat_dir_and_file (mc_home, "extfs" PATH_SEP_STR "sfs.ini");
  263. cfg = fopen (mc_sfsini, "r");
  264. if (!cfg){
  265. fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
  266. g_free (mc_sfsini);
  267. return 0;
  268. }
  269. g_free (mc_sfsini);
  270. sfs_no = 0;
  271. while (sfs_no < MAXFS){
  272. char key[256];
  273. char *c, *semi = NULL, flags = 0;
  274. if (!fgets (key, sizeof (key), cfg))
  275. break;
  276. if (*key == '#')
  277. continue;
  278. for (c = key; *c; c++)
  279. if ((*c == ':') || (*c == '/')){
  280. semi = c;
  281. if (*c == '/'){
  282. *c = 0;
  283. flags |= F_FULLMATCH;
  284. }
  285. break;
  286. }
  287. if (!semi){
  288. fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
  289. "sfs.ini", key);
  290. continue;
  291. }
  292. c = semi + 1;
  293. while ((*c != ' ') && (*c != '\t')) {
  294. switch (*c) {
  295. case '1': flags |= F_1; break;
  296. case '2': flags |= F_2; break;
  297. case 'R': flags |= F_NOLOCALCOPY; break;
  298. default:
  299. fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
  300. *c, "sfs.ini", key);
  301. }
  302. c++;
  303. }
  304. c++;
  305. *(semi+1) = 0;
  306. if ((semi = strchr (c, '\n')))
  307. *semi = 0;
  308. sfs_prefix [sfs_no] = g_strdup (key);
  309. sfs_command [sfs_no] = g_strdup (c);
  310. sfs_flags [sfs_no] = flags;
  311. sfs_no++;
  312. }
  313. fclose (cfg);
  314. return 1;
  315. }
  316. static void
  317. sfs_done (struct vfs_class *me)
  318. {
  319. int i;
  320. for (i = 0; i < sfs_no; i++){
  321. g_free (sfs_prefix [i]);
  322. g_free (sfs_command [i]);
  323. sfs_prefix [i] = sfs_command [i] = NULL;
  324. }
  325. sfs_no = 0;
  326. }
  327. static int
  328. sfs_which (struct vfs_class *me, char *path)
  329. {
  330. int i;
  331. for (i = 0; i < sfs_no; i++)
  332. if (sfs_flags [i] & F_FULLMATCH) {
  333. if (!strcmp (path, sfs_prefix [i]))
  334. return i;
  335. } else
  336. if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
  337. return i;
  338. return -1;
  339. }
  340. void
  341. init_sfs (void)
  342. {
  343. vfs_sfs_ops.name = "sfs";
  344. vfs_sfs_ops.init = sfs_init;
  345. vfs_sfs_ops.done = sfs_done;
  346. vfs_sfs_ops.fill_names = sfs_fill_names;
  347. vfs_sfs_ops.which = sfs_which;
  348. vfs_sfs_ops.open = sfs_open;
  349. vfs_sfs_ops.close = local_close;
  350. vfs_sfs_ops.read = local_read;
  351. vfs_sfs_ops.stat = sfs_stat;
  352. vfs_sfs_ops.lstat = sfs_lstat;
  353. vfs_sfs_ops.fstat = local_fstat;
  354. vfs_sfs_ops.chmod = sfs_chmod;
  355. vfs_sfs_ops.chown = sfs_chown;
  356. vfs_sfs_ops.utime = sfs_utime;
  357. vfs_sfs_ops.readlink = sfs_readlink;
  358. vfs_sfs_ops.ferrno = local_errno;
  359. vfs_sfs_ops.lseek = local_lseek;
  360. vfs_sfs_ops.getid = sfs_getid;
  361. vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
  362. vfs_sfs_ops.free = sfs_free;
  363. vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
  364. vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
  365. #ifdef HAVE_MMAP
  366. vfs_sfs_ops.mmap = local_mmap;
  367. vfs_sfs_ops.munmap = local_munmap;
  368. #endif
  369. vfs_register_class (&vfs_sfs_ops);
  370. }