sfs.c 8.9 KB

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