sfs.c 14 KB

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