sfs.c 9.2 KB

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