sfs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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" /* D_ERROR, D_NORMAL */
  43. #include "src/main.h" /* mc_home */
  44. #include "src/execute.h" /* EXECUTE_AS_SHELL */
  45. #include "vfs-impl.h"
  46. #include "utilvfs.h"
  47. #include "local.h"
  48. #include "gc.h" /* vfs_stamp_create */
  49. /*** global variables ****************************************************************************/
  50. /*** file scope macro definitions ****************************************************************/
  51. #define MAXFS 32
  52. #define F_1 1
  53. #define F_2 2
  54. #define F_NOLOCALCOPY 4
  55. #define F_FULLMATCH 8
  56. #define COPY_CHAR \
  57. if ((size_t) (t-pad) > sizeof(pad)) { \
  58. g_free (pqname); \
  59. return -1; \
  60. } \
  61. else \
  62. *t++ = *s;
  63. #define COPY_STRING(a) \
  64. if ((t-pad)+strlen(a)>sizeof(pad)) { \
  65. g_free (pqname); \
  66. return -1; \
  67. } else { \
  68. strcpy (t, a); \
  69. t+= strlen(a); \
  70. }
  71. /*** file scope type declarations ****************************************************************/
  72. struct cachedfile
  73. {
  74. char *name, *cache;
  75. struct cachedfile *next;
  76. };
  77. /*** file scope variables ************************************************************************/
  78. static struct cachedfile *head;
  79. static struct vfs_class vfs_sfs_ops;
  80. static int sfs_no = 0;
  81. static char *sfs_prefix[MAXFS];
  82. static char *sfs_command[MAXFS];
  83. static int sfs_flags[MAXFS];
  84. /*** file scope functions ************************************************************************/
  85. /* --------------------------------------------------------------------------------------------- */
  86. static int
  87. sfs_vfmake (struct vfs_class *me, const char *name, char *cache)
  88. {
  89. char *inpath, *op;
  90. int w;
  91. char pad[10240];
  92. char *s, *t = pad;
  93. int was_percent = 0;
  94. char *pname; /* name of parent archive */
  95. char *pqname; /* name of parent archive, quoted */
  96. pname = g_strdup (name);
  97. vfs_split (pname, &inpath, &op);
  98. w = (*me->which) (me, op);
  99. if (w == -1)
  100. vfs_die ("This cannot happen... Hopefully.\n");
  101. if (!(sfs_flags[w] & F_1) && strcmp (pname, "/"))
  102. {
  103. g_free (pname);
  104. return -1;
  105. }
  106. /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
  107. if (!(sfs_flags[w] & F_NOLOCALCOPY))
  108. {
  109. s = mc_getlocalcopy (pname);
  110. if (!s)
  111. {
  112. g_free (pname);
  113. return -1;
  114. }
  115. pqname = name_quote (s, 0);
  116. g_free (s);
  117. }
  118. else
  119. {
  120. pqname = name_quote (pname, 0);
  121. }
  122. g_free (pname);
  123. for (s = sfs_command[w]; *s; s++)
  124. {
  125. if (was_percent)
  126. {
  127. const char *ptr = NULL;
  128. was_percent = 0;
  129. switch (*s)
  130. {
  131. case '1':
  132. ptr = pqname;
  133. break;
  134. case '2':
  135. ptr = op + strlen (sfs_prefix[w]);
  136. break;
  137. case '3':
  138. ptr = cache;
  139. break;
  140. case '%':
  141. COPY_CHAR;
  142. continue;
  143. }
  144. COPY_STRING (ptr);
  145. }
  146. else
  147. {
  148. if (*s == '%')
  149. was_percent = 1;
  150. else
  151. COPY_CHAR;
  152. }
  153. }
  154. g_free (pqname);
  155. open_error_pipe ();
  156. if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad))
  157. {
  158. close_error_pipe (D_ERROR, NULL);
  159. return -1;
  160. }
  161. close_error_pipe (D_NORMAL, NULL);
  162. return 0; /* OK */
  163. }
  164. /* --------------------------------------------------------------------------------------------- */
  165. static const char *
  166. sfs_redirect (struct vfs_class *me, const char *name)
  167. {
  168. struct cachedfile *cur = head;
  169. char *cache;
  170. int handle;
  171. while (cur)
  172. {
  173. if (!strcmp (name, cur->name))
  174. {
  175. vfs_stamp (&vfs_sfs_ops, cur);
  176. return cur->cache;
  177. }
  178. cur = cur->next;
  179. }
  180. handle = vfs_mkstemps (&cache, "sfs", name);
  181. if (handle == -1)
  182. {
  183. return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
  184. }
  185. close (handle);
  186. if (!sfs_vfmake (me, name, cache))
  187. {
  188. cur = g_new (struct cachedfile, 1);
  189. cur->name = g_strdup (name);
  190. cur->cache = cache;
  191. cur->next = head;
  192. head = cur;
  193. vfs_stamp_create (&vfs_sfs_ops, head);
  194. return cache;
  195. }
  196. unlink (cache);
  197. g_free (cache);
  198. return "/I_MUST_NOT_EXIST";
  199. }
  200. /* --------------------------------------------------------------------------------------------- */
  201. static void *
  202. sfs_open (struct vfs_class *me, const char *path, int flags, mode_t mode)
  203. {
  204. int *sfs_info;
  205. int fd;
  206. path = sfs_redirect (me, path);
  207. fd = open (path, NO_LINEAR (flags), mode);
  208. if (fd == -1)
  209. return 0;
  210. sfs_info = g_new (int, 1);
  211. *sfs_info = fd;
  212. return sfs_info;
  213. }
  214. /* --------------------------------------------------------------------------------------------- */
  215. static int
  216. sfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
  217. {
  218. path = sfs_redirect (me, path);
  219. return stat (path, buf);
  220. }
  221. /* --------------------------------------------------------------------------------------------- */
  222. static int
  223. sfs_lstat (struct vfs_class *me, const char *path, struct stat *buf)
  224. {
  225. path = sfs_redirect (me, path);
  226. #ifndef HAVE_STATLSTAT
  227. return lstat (path, buf);
  228. #else
  229. return statlstat (path, buf);
  230. #endif
  231. }
  232. /* --------------------------------------------------------------------------------------------- */
  233. static int
  234. sfs_chmod (struct vfs_class *me, const char *path, int mode)
  235. {
  236. path = sfs_redirect (me, path);
  237. return chmod (path, mode);
  238. }
  239. /* --------------------------------------------------------------------------------------------- */
  240. static int
  241. sfs_chown (struct vfs_class *me, const char *path, uid_t owner, gid_t group)
  242. {
  243. path = sfs_redirect (me, path);
  244. return chown (path, owner, group);
  245. }
  246. /* --------------------------------------------------------------------------------------------- */
  247. static int
  248. sfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
  249. {
  250. path = sfs_redirect (me, path);
  251. return utime (path, times);
  252. }
  253. /* --------------------------------------------------------------------------------------------- */
  254. static int
  255. sfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
  256. {
  257. path = sfs_redirect (me, path);
  258. return readlink (path, buf, size);
  259. }
  260. /* --------------------------------------------------------------------------------------------- */
  261. static vfsid
  262. sfs_getid (struct vfs_class *me, const char *path)
  263. {
  264. struct cachedfile *cur = head;
  265. (void) me;
  266. while (cur)
  267. {
  268. if (!strcmp (path, cur->name))
  269. break;
  270. cur = cur->next;
  271. }
  272. return (vfsid) cur;
  273. }
  274. /* --------------------------------------------------------------------------------------------- */
  275. static void
  276. sfs_free (vfsid id)
  277. {
  278. struct cachedfile *which = (struct cachedfile *) id;
  279. struct cachedfile *cur, *prev;
  280. for (cur = head, prev = 0; cur && cur != which; prev = cur, cur = cur->next)
  281. ;
  282. if (!cur)
  283. vfs_die ("Free of thing which is unknown to me\n");
  284. unlink (cur->cache);
  285. if (prev)
  286. prev->next = cur->next;
  287. else
  288. head = cur->next;
  289. g_free (cur->cache);
  290. g_free (cur->name);
  291. g_free (cur);
  292. }
  293. /* --------------------------------------------------------------------------------------------- */
  294. static void
  295. sfs_fill_names (struct vfs_class *me, fill_names_f func)
  296. {
  297. struct cachedfile *cur = head;
  298. (void) me;
  299. while (cur)
  300. {
  301. (*func) (cur->name);
  302. cur = cur->next;
  303. }
  304. }
  305. /* --------------------------------------------------------------------------------------------- */
  306. static int
  307. sfs_nothingisopen (vfsid id)
  308. {
  309. /* FIXME: Investigate whether have to guard this like in
  310. the other VFSs (see fd_usage in extfs) -- Norbert */
  311. (void) id;
  312. return 1;
  313. }
  314. /* --------------------------------------------------------------------------------------------- */
  315. static char *
  316. sfs_getlocalcopy (struct vfs_class *me, const char *path)
  317. {
  318. path = sfs_redirect (me, path);
  319. return g_strdup (path);
  320. }
  321. /* --------------------------------------------------------------------------------------------- */
  322. static int
  323. sfs_ungetlocalcopy (struct vfs_class *me, const char *path, const char *local, int has_changed)
  324. {
  325. (void) me;
  326. (void) path;
  327. (void) local;
  328. (void) has_changed;
  329. return 0;
  330. }
  331. /* --------------------------------------------------------------------------------------------- */
  332. static int
  333. sfs_init (struct vfs_class *me)
  334. {
  335. char *mc_sfsini;
  336. FILE *cfg;
  337. char key[256];
  338. (void) me;
  339. mc_sfsini = g_build_filename (mc_home, "sfs.ini", (char *) NULL);
  340. cfg = fopen (mc_sfsini, "r");
  341. if (cfg == NULL)
  342. {
  343. fprintf (stderr, _("Warning: file %s not found\n"), mc_sfsini);
  344. g_free (mc_sfsini);
  345. return 0;
  346. }
  347. g_free (mc_sfsini);
  348. sfs_no = 0;
  349. while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg))
  350. {
  351. char *c, *semi = NULL, flags = 0;
  352. if (*key == '#' || *key == '\n')
  353. continue;
  354. for (c = key; *c; c++)
  355. if ((*c == ':') || (*c == '/'))
  356. {
  357. semi = c;
  358. if (*c == '/')
  359. {
  360. *c = 0;
  361. flags |= F_FULLMATCH;
  362. }
  363. break;
  364. }
  365. if (!semi)
  366. {
  367. invalid_line:
  368. fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
  369. continue;
  370. }
  371. c = semi + 1;
  372. while (*c && (*c != ' ') && (*c != '\t'))
  373. {
  374. switch (*c)
  375. {
  376. case '1':
  377. flags |= F_1;
  378. break;
  379. case '2':
  380. flags |= F_2;
  381. break;
  382. case 'R':
  383. flags |= F_NOLOCALCOPY;
  384. break;
  385. default:
  386. fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
  387. }
  388. c++;
  389. }
  390. if (!*c)
  391. goto invalid_line;
  392. c++;
  393. *(semi + 1) = 0;
  394. semi = strchr (c, '\n');
  395. if (semi != NULL)
  396. *semi = 0;
  397. sfs_prefix[sfs_no] = g_strdup (key);
  398. sfs_command[sfs_no] = g_strdup (c);
  399. sfs_flags[sfs_no] = flags;
  400. sfs_no++;
  401. }
  402. fclose (cfg);
  403. return 1;
  404. }
  405. /* --------------------------------------------------------------------------------------------- */
  406. static void
  407. sfs_done (struct vfs_class *me)
  408. {
  409. int i;
  410. (void) me;
  411. for (i = 0; i < sfs_no; i++)
  412. {
  413. g_free (sfs_prefix[i]);
  414. g_free (sfs_command[i]);
  415. sfs_prefix[i] = sfs_command[i] = NULL;
  416. }
  417. sfs_no = 0;
  418. }
  419. /* --------------------------------------------------------------------------------------------- */
  420. static int
  421. sfs_which (struct vfs_class *me, const char *path)
  422. {
  423. int i;
  424. (void) me;
  425. for (i = 0; i < sfs_no; i++)
  426. if (sfs_flags[i] & F_FULLMATCH)
  427. {
  428. if (!strcmp (path, sfs_prefix[i]))
  429. return i;
  430. }
  431. else if (!strncmp (path, sfs_prefix[i], strlen (sfs_prefix[i])))
  432. return i;
  433. return -1;
  434. }
  435. /* --------------------------------------------------------------------------------------------- */
  436. /*** public functions ****************************************************************************/
  437. /* --------------------------------------------------------------------------------------------- */
  438. void
  439. init_sfs (void)
  440. {
  441. vfs_sfs_ops.name = "sfs";
  442. vfs_sfs_ops.init = sfs_init;
  443. vfs_sfs_ops.done = sfs_done;
  444. vfs_sfs_ops.fill_names = sfs_fill_names;
  445. vfs_sfs_ops.which = sfs_which;
  446. vfs_sfs_ops.open = sfs_open;
  447. vfs_sfs_ops.close = local_close;
  448. vfs_sfs_ops.read = local_read;
  449. vfs_sfs_ops.stat = sfs_stat;
  450. vfs_sfs_ops.lstat = sfs_lstat;
  451. vfs_sfs_ops.fstat = local_fstat;
  452. vfs_sfs_ops.chmod = sfs_chmod;
  453. vfs_sfs_ops.chown = sfs_chown;
  454. vfs_sfs_ops.utime = sfs_utime;
  455. vfs_sfs_ops.readlink = sfs_readlink;
  456. vfs_sfs_ops.ferrno = local_errno;
  457. vfs_sfs_ops.lseek = local_lseek;
  458. vfs_sfs_ops.getid = sfs_getid;
  459. vfs_sfs_ops.nothingisopen = sfs_nothingisopen;
  460. vfs_sfs_ops.free = sfs_free;
  461. vfs_sfs_ops.getlocalcopy = sfs_getlocalcopy;
  462. vfs_sfs_ops.ungetlocalcopy = sfs_ungetlocalcopy;
  463. vfs_register_class (&vfs_sfs_ops);
  464. }
  465. /* --------------------------------------------------------------------------------------------- */