sfs.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. * Single File fileSystem
  3. *
  4. * Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
  5. * Free Software Foundation, Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. */
  21. /**
  22. * \file
  23. * \brief Source: Single File fileSystem
  24. *
  25. * This defines whole class of filesystems which contain single file
  26. * inside. It is somehow similar to extfs, except that extfs makes
  27. * whole virtual trees and we do only single virtual files.
  28. *
  29. * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
  30. * suffix, DON'T try to gunzip it yourself.
  31. *
  32. * Namespace: exports vfs_sfs_ops
  33. */
  34. #include <config.h>
  35. #include <errno.h>
  36. #include <sys/types.h>
  37. #include <unistd.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <fcntl.h>
  41. #include "lib/global.h"
  42. #include "src/wtools.h" /* message() */
  43. #include "src/main.h" /* print_vfs_message */
  44. #include "src/execute.h" /* EXECUTE_AS_SHELL */
  45. #include "utilvfs.h"
  46. #include "vfs.h"
  47. #include "vfs-impl.h"
  48. #include "gc.h" /* vfs_stamp_create */
  49. #include "local.h"
  50. struct cachedfile {
  51. char *name, *cache;
  52. struct cachedfile *next;
  53. };
  54. static struct cachedfile *head;
  55. static struct vfs_class vfs_sfs_ops;
  56. #define MAXFS 32
  57. static int sfs_no = 0;
  58. static char *sfs_prefix[ MAXFS ];
  59. static char *sfs_command[ MAXFS ];
  60. static int sfs_flags[ MAXFS ];
  61. #define F_1 1
  62. #define F_2 2
  63. #define F_NOLOCALCOPY 4
  64. #define F_FULLMATCH 8
  65. static int
  66. sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
  67. {
  68. char *inpath, *op;
  69. int w;
  70. char pad[10240];
  71. char *s, *t = pad;
  72. int was_percent = 0;
  73. char *pname; /* name of parent archive */
  74. char *pqname; /* name of parent archive, quoted */
  75. pname = g_strdup (name);
  76. vfs_split (pname, &inpath, &op);
  77. w = (*me->which) (me, op);
  78. if (w == -1)
  79. vfs_die ("This cannot happen... Hopefully.\n");
  80. if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) {
  81. g_free (pname);
  82. return -1;
  83. }
  84. /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
  85. if (!(sfs_flags[w] & F_NOLOCALCOPY)) {
  86. s = mc_getlocalcopy (pname);
  87. if (!s) {
  88. g_free (pname);
  89. return -1;
  90. }
  91. pqname = name_quote (s, 0);
  92. g_free (s);
  93. } else {
  94. pqname = name_quote (pname, 0);
  95. }
  96. g_free (pname);
  97. #define COPY_CHAR \
  98. if ((size_t) (t-pad) > sizeof(pad)) { \
  99. g_free (pqname); \
  100. return -1; \
  101. } \
  102. else \
  103. *t++ = *s;
  104. #define COPY_STRING(a) \
  105. if ((t-pad)+strlen(a)>sizeof(pad)) { \
  106. g_free (pqname); \
  107. return -1; \
  108. } else { \
  109. strcpy (t, a); \
  110. t+= strlen(a); \
  111. }
  112. for (s = sfs_command[w]; *s; s++) {
  113. if (was_percent) {
  114. const char *ptr = NULL;
  115. was_percent = 0;
  116. switch (*s) {
  117. case '1':
  118. ptr = pqname;
  119. break;
  120. case '2':
  121. ptr = op + strlen (sfs_prefix[w]);
  122. break;
  123. case '3':
  124. ptr = cache;
  125. break;
  126. case '%':
  127. COPY_CHAR;
  128. continue;
  129. }
  130. COPY_STRING (ptr);
  131. } else {
  132. if (*s == '%')
  133. was_percent = 1;
  134. else
  135. COPY_CHAR;
  136. }
  137. }
  138. g_free (pqname);
  139. open_error_pipe ();
  140. if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) {
  141. close_error_pipe (D_ERROR, NULL);
  142. return -1;
  143. }
  144. close_error_pipe (D_NORMAL, NULL);
  145. return 0; /* OK */
  146. }
  147. static const char *
  148. sfs_redirect (struct vfs_class *me, const char *name)
  149. {
  150. struct cachedfile *cur = head;
  151. char *cache;
  152. int handle;
  153. while (cur) {
  154. if (!strcmp (name, cur->name)) {
  155. vfs_stamp (&vfs_sfs_ops, cur);
  156. return cur->cache;
  157. }
  158. cur = cur->next;
  159. }
  160. handle = vfs_mkstemps (&cache, "sfs", name);
  161. if (handle == -1) {
  162. return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
  163. }
  164. close (handle);
  165. if (!sfs_vfmake (me, name, cache)) {
  166. cur = g_new (struct cachedfile, 1);
  167. cur->name = g_strdup (name);
  168. cur->cache = cache;
  169. cur->next = head;
  170. head = cur;
  171. vfs_stamp_create (&vfs_sfs_ops, head);
  172. return cache;
  173. }
  174. unlink (cache);
  175. g_free (cache);
  176. return "/I_MUST_NOT_EXIST";
  177. }
  178. static void *
  179. sfs_open (struct vfs_class *me, const char *path, int flags, int mode)
  180. {
  181. int *sfs_info;
  182. int fd;
  183. path = sfs_redirect (me, path);
  184. fd = open (path, NO_LINEAR (flags), mode);
  185. if (fd == -1)
  186. return 0;
  187. sfs_info = g_new (int, 1);
  188. *sfs_info = fd;
  189. return sfs_info;
  190. }
  191. static int sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
  192. {
  193. path = sfs_redirect (me, path);
  194. return stat (path, buf);
  195. }
  196. static int sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
  197. {
  198. path = sfs_redirect (me, path);
  199. #ifndef HAVE_STATLSTAT
  200. return lstat (path, buf);
  201. #else
  202. return statlstat (path, buf);
  203. #endif
  204. }
  205. static int sfs_chmod (struct vfs_class *me, const char *path, int mode)
  206. {
  207. path = sfs_redirect (me, path);
  208. return chmod (path, mode);
  209. }
  210. static int sfs_chown (struct vfs_class *me, const char *path, int owner, int group)
  211. {
  212. path = sfs_redirect (me, path);
  213. return chown (path, owner, group);
  214. }
  215. static int sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
  216. {
  217. path = sfs_redirect (me, path);
  218. return utime (path, times);
  219. }
  220. static int
  221. sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
  222. {
  223. path = sfs_redirect (me, path);
  224. return readlink (path, buf, size);
  225. }
  226. static vfsid
  227. sfs_getid (struct vfs_class *me, const char *path)
  228. {
  229. struct cachedfile *cur = head;
  230. (void) me;
  231. while (cur) {
  232. if (!strcmp (path, cur->name))
  233. break;
  234. cur = cur->next;
  235. }
  236. return (vfsid) cur;
  237. }
  238. static void sfs_free (vfsid id)
  239. {
  240. struct cachedfile *which = (struct cachedfile *) id;
  241. struct cachedfile *cur, *prev;
  242. for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
  243. ;
  244. if (!cur)
  245. vfs_die( "Free of thing which is unknown to me\n" );
  246. unlink (cur->cache);
  247. if (prev)
  248. prev->next = cur->next;
  249. else
  250. head = cur->next;
  251. g_free (cur->cache);
  252. g_free (cur->name);
  253. g_free (cur);
  254. }
  255. static void sfs_fill_names (struct vfs_class *me, fill_names_f func)
  256. {
  257. struct cachedfile *cur = head;
  258. (void) me;
  259. while (cur){
  260. (*func)(cur->name);
  261. cur = cur->next;
  262. }
  263. }
  264. static int sfs_nothingisopen (vfsid id)
  265. {
  266. /* FIXME: Investigate whether have to guard this like in
  267. the other VFSs (see fd_usage in extfs) -- Norbert */
  268. (void) id;
  269. return 1;
  270. }
  271. static char *
  272. sfs_getlocalcopy (struct vfs_class *me, const char *path)
  273. {
  274. path = sfs_redirect (me, path);
  275. return g_strdup (path);
  276. }
  277. static int
  278. sfs_ungetlocalcopy (struct vfs_class *me, const char *path,
  279. const char *local, int has_changed)
  280. {
  281. (void) me;
  282. (void) path;
  283. (void) local;
  284. (void) has_changed;
  285. return 0;
  286. }
  287. static int sfs_init (struct vfs_class *me)
  288. {
  289. char *mc_sfsini;
  290. FILE *cfg;
  291. char key[256];
  292. (void) me;
  293. mc_sfsini = g_build_filename (mc_home, "sfs.ini", (char *) NULL);
  294. cfg = fopen (mc_sfsini, "r");
  295. if (cfg == NULL) {
  296. fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
  297. g_free (mc_sfsini);
  298. return 0;
  299. }
  300. g_free (mc_sfsini);
  301. sfs_no = 0;
  302. while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg)) {
  303. char *c, *semi = NULL, flags = 0;
  304. if (*key == '#' || *key == '\n')
  305. continue;
  306. for (c = key; *c; c++)
  307. if ((*c == ':') || (*c == '/')){
  308. semi = c;
  309. if (*c == '/'){
  310. *c = 0;
  311. flags |= F_FULLMATCH;
  312. }
  313. break;
  314. }
  315. if (!semi){
  316. invalid_line:
  317. fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"),
  318. "sfs.ini", key);
  319. continue;
  320. }
  321. c = semi + 1;
  322. while (*c && (*c != ' ') && (*c != '\t')) {
  323. switch (*c) {
  324. case '1': flags |= F_1; break;
  325. case '2': flags |= F_2; break;
  326. case 'R': flags |= F_NOLOCALCOPY; break;
  327. default:
  328. fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"),
  329. *c, "sfs.ini", key);
  330. }
  331. c++;
  332. }
  333. if (!*c)
  334. goto invalid_line;
  335. c++;
  336. *(semi+1) = 0;
  337. semi = strchr (c, '\n');
  338. if (semi != NULL)
  339. *semi = 0;
  340. sfs_prefix [sfs_no] = g_strdup (key);
  341. sfs_command [sfs_no] = g_strdup (c);
  342. sfs_flags [sfs_no] = flags;
  343. sfs_no++;
  344. }
  345. fclose (cfg);
  346. return 1;
  347. }
  348. static void
  349. sfs_done (struct vfs_class *me)
  350. {
  351. int i;
  352. (void) me;
  353. for (i = 0; i < sfs_no; i++){
  354. g_free (sfs_prefix [i]);
  355. g_free (sfs_command [i]);
  356. sfs_prefix [i] = sfs_command [i] = NULL;
  357. }
  358. sfs_no = 0;
  359. }
  360. static int
  361. sfs_which (struct vfs_class *me, const char *path)
  362. {
  363. int i;
  364. (void) me;
  365. for (i = 0; i < sfs_no; i++)
  366. if (sfs_flags [i] & F_FULLMATCH) {
  367. if (!strcmp (path, sfs_prefix [i]))
  368. return i;
  369. } else
  370. if (!strncmp (path, sfs_prefix [i], strlen (sfs_prefix [i])))
  371. return i;
  372. return -1;
  373. }
  374. void
  375. init_sfs (void)
  376. {
  377. vfs_sfs_ops.name = "sfs";
  378. vfs_sfs_ops.init = sfs_init;
  379. vfs_sfs_ops.done = sfs_done;
  380. vfs_sfs_ops.fill_names = sfs_fill_names;
  381. vfs_sfs_ops.which = sfs_which;
  382. vfs_sfs_ops.open = sfs_open;
  383. vfs_sfs_ops.close = local_close;
  384. vfs_sfs_ops.read = local_read;
  385. vfs_sfs_ops.stat = sfs_stat;
  386. vfs_sfs_ops.lstat = sfs_lstat;
  387. vfs_sfs_ops.fstat = local_fstat;
  388. vfs_sfs_ops.chmod = sfs_chmod;
  389. vfs_sfs_ops.chown = sfs_chown;
  390. vfs_sfs_ops.utime = sfs_utime;
  391. vfs_sfs_ops.readlink = sfs_readlink;
  392. vfs_sfs_ops.ferrno = local_errno;
  393. vfs_sfs_ops.lseek = local_lseek;
  394. vfs_sfs_ops.getid = sfs_getid;
  395. vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
  396. vfs_sfs_ops.free = sfs_free;
  397. vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
  398. vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
  399. vfs_register_class (&vfs_sfs_ops);
  400. }