direntry.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. /** \file
  2. * \brief Source: directory cache support
  3. *
  4. * So that you do not have copy of this in each and every filesystem.
  5. *
  6. * Very loosely based on tar.c from midnight and archives.[ch] from
  7. * avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
  8. *
  9. * Unfortunately, I was unable to keep all filesystems
  10. * uniform. tar-like filesystems use tree structure where each
  11. * directory has pointers to its subdirectories. We can do this
  12. * because we have full information about our archive.
  13. *
  14. * At ftp-like filesystems, situation is a little bit different. When
  15. * you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
  16. * /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
  17. * listed. That means that we do not have complete information, and if
  18. * /usr is symlink to /4, we will not know. Also we have to time out
  19. * entries and things would get messy with tree-like approach. So we
  20. * do different trick: root directory is completely special and
  21. * completely fake, it contains entries such as 'usr', 'usr/src', ...,
  22. * and we'll try to use custom find_entry function.
  23. *
  24. * \author Pavel Machek <pavel@ucw.cz>, distribute under LGPL.
  25. * \date 1998
  26. *
  27. * \warning Paths here do _not_ begin with '/', so root directory of
  28. * archive/site is simply "".
  29. */
  30. #include <config.h>
  31. #include <errno.h>
  32. #include <fcntl.h> /* include fcntl.h -> sys/fcntl.h only */
  33. /* includes fcntl.h see IEEE Std 1003.1-2008 */
  34. #include <time.h>
  35. #include <sys/time.h> /* gettimeofday() */
  36. #include "lib/global.h"
  37. #include "lib/tty/tty.h" /* enable/disable interrupt key */
  38. #include "src/wtools.h" /* message() */
  39. #include "src/main.h" /* print_vfs_message */
  40. #include "vfs.h"
  41. #include "utilvfs.h"
  42. #include "vfs-impl.h"
  43. #include "gc.h" /* vfs_rmstamp */
  44. #include "xdirentry.h"
  45. #define CALL(x) if (MEDATA->x) MEDATA->x
  46. static volatile int total_inodes = 0, total_entries = 0;
  47. struct vfs_s_inode *
  48. vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
  49. {
  50. struct vfs_s_inode *ino;
  51. ino = g_try_new0 (struct vfs_s_inode, 1);
  52. if (ino == NULL)
  53. return NULL;
  54. if (initstat)
  55. ino->st = *initstat;
  56. ino->super = super;
  57. ino->st.st_nlink = 0;
  58. ino->st.st_ino = MEDATA->inode_counter++;
  59. ino->st.st_dev = MEDATA->rdev;
  60. super->ino_usage++;
  61. total_inodes++;
  62. CALL (init_inode) (me, ino);
  63. return ino;
  64. }
  65. struct vfs_s_entry *
  66. vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
  67. {
  68. struct vfs_s_entry *entry;
  69. entry = g_new0 (struct vfs_s_entry, 1);
  70. total_entries++;
  71. if (name)
  72. entry->name = g_strdup (name);
  73. entry->ino = inode;
  74. entry->ino->ent = entry;
  75. CALL (init_entry) (me, entry);
  76. return entry;
  77. }
  78. static void
  79. vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
  80. {
  81. if (!ino)
  82. vfs_die ("Don't pass NULL to me");
  83. /* ==0 can happen if freshly created entry is deleted */
  84. if (ino->st.st_nlink <= 1){
  85. while (ino->subdir){
  86. vfs_s_free_entry (me, ino->subdir);
  87. }
  88. CALL (free_inode) (me, ino);
  89. g_free (ino->linkname);
  90. if (ino->localname){
  91. unlink (ino->localname);
  92. g_free(ino->localname);
  93. }
  94. total_inodes--;
  95. ino->super->ino_usage--;
  96. g_free(ino);
  97. } else ino->st.st_nlink--;
  98. }
  99. void
  100. vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
  101. {
  102. if (ent->prevp){ /* It is possible that we are deleting freshly created entry */
  103. *ent->prevp = ent->next;
  104. if (ent->next)
  105. ent->next->prevp = ent->prevp;
  106. }
  107. g_free (ent->name);
  108. ent->name = NULL;
  109. if (ent->ino){
  110. ent->ino->ent = NULL;
  111. vfs_s_free_inode (me, ent->ino);
  112. ent->ino = NULL;
  113. }
  114. total_entries--;
  115. g_free(ent);
  116. }
  117. void
  118. vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
  119. {
  120. struct vfs_s_entry **ep;
  121. (void) me;
  122. for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
  123. ;
  124. ent->prevp = ep;
  125. ent->next = NULL;
  126. ent->dir = dir;
  127. *ep = ent;
  128. ent->ino->st.st_nlink++;
  129. }
  130. struct stat *
  131. vfs_s_default_stat (struct vfs_class *me, mode_t mode)
  132. {
  133. static struct stat st;
  134. int myumask;
  135. (void) me;
  136. myumask = umask (022);
  137. umask (myumask);
  138. mode &= ~myumask;
  139. st.st_mode = mode;
  140. st.st_ino = 0;
  141. st.st_dev = 0;
  142. st.st_rdev = 0;
  143. st.st_uid = getuid ();
  144. st.st_gid = getgid ();
  145. st.st_size = 0;
  146. st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
  147. return &st;
  148. }
  149. struct vfs_s_entry *
  150. vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent, mode_t mode)
  151. {
  152. struct vfs_s_inode *inode;
  153. struct stat *st;
  154. st = vfs_s_default_stat (me, mode);
  155. inode = vfs_s_new_inode (me, parent->super, st);
  156. return vfs_s_new_entry (me, name, inode);
  157. }
  158. /* We were asked to create entries automagically */
  159. static struct vfs_s_entry *
  160. vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
  161. {
  162. struct vfs_s_entry *res;
  163. char *sep = strchr (path, PATH_SEP);
  164. if (sep)
  165. *sep = 0;
  166. res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
  167. vfs_s_insert_entry (me, dir, res);
  168. if (sep)
  169. *sep = PATH_SEP;
  170. return res;
  171. }
  172. /* If the entry is a symlink, find the entry for its target */
  173. static struct vfs_s_entry *
  174. vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry,
  175. int follow)
  176. {
  177. char *linkname;
  178. char *fullname = NULL;
  179. struct vfs_s_entry *target;
  180. if (follow == LINK_NO_FOLLOW)
  181. return entry;
  182. if (follow == 0)
  183. ERRNOR (ELOOP, NULL);
  184. if (!entry)
  185. ERRNOR (ENOENT, NULL);
  186. if (!S_ISLNK (entry->ino->st.st_mode))
  187. return entry;
  188. linkname = entry->ino->linkname;
  189. if (linkname == NULL)
  190. ERRNOR (EFAULT, NULL);
  191. /* make full path from relative */
  192. if (*linkname != PATH_SEP) {
  193. char *fullpath = vfs_s_fullpath (me, entry->dir);
  194. if (fullpath) {
  195. fullname = g_strconcat (fullpath, "/", linkname, (char *) NULL);
  196. linkname = fullname;
  197. g_free (fullpath);
  198. }
  199. }
  200. target =
  201. (MEDATA->find_entry) (me, entry->dir->super->root, linkname,
  202. follow - 1, 0);
  203. g_free (fullname);
  204. return target;
  205. }
  206. /*
  207. * Follow > 0: follow links, serves as loop protect,
  208. * == -1: do not follow links
  209. */
  210. static struct vfs_s_entry *
  211. vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
  212. const char *a_path, int follow, int flags)
  213. {
  214. size_t pseg;
  215. struct vfs_s_entry *ent = NULL;
  216. char * const pathref = g_strdup (a_path);
  217. char *path = pathref;
  218. /* canonicalize as well, but don't remove '../' from path */
  219. custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
  220. while (root) {
  221. while (*path == PATH_SEP) /* Strip leading '/' */
  222. path++;
  223. if (!path[0]) {
  224. g_free (pathref);
  225. return ent;
  226. }
  227. for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++);
  228. for (ent = root->subdir; ent != NULL; ent = ent->next)
  229. if (strlen (ent->name) == pseg
  230. && (!strncmp (ent->name, path, pseg)))
  231. /* FOUND! */
  232. break;
  233. if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
  234. ent = vfs_s_automake (me, root, path, flags);
  235. if (!ent) {
  236. me->verrno = ENOENT;
  237. goto cleanup;
  238. }
  239. path += pseg;
  240. /* here we must follow leading directories always;
  241. only the actual file is optional */
  242. ent =
  243. vfs_s_resolve_symlink (me, ent,
  244. strchr (path,
  245. PATH_SEP) ? LINK_FOLLOW :
  246. follow);
  247. if (!ent)
  248. goto cleanup;
  249. root = ent->ino;
  250. }
  251. cleanup:
  252. g_free (pathref);
  253. return NULL;
  254. }
  255. static void
  256. split_dir_name (struct vfs_class *me, char *path, char **dir, char **name, char **save)
  257. {
  258. char *s;
  259. (void) me;
  260. s = strrchr (path, PATH_SEP);
  261. if (s == NULL) {
  262. *save = NULL;
  263. *name = path;
  264. *dir = path + strlen(path); /* an empty string */
  265. } else {
  266. *save = s;
  267. *dir = path;
  268. *s++ = '\0';
  269. *name = s;
  270. }
  271. }
  272. static struct vfs_s_entry *
  273. vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
  274. const char *a_path, int follow, int flags)
  275. {
  276. struct vfs_s_entry *ent = NULL;
  277. char * const path = g_strdup (a_path);
  278. struct vfs_s_entry *retval = NULL;
  279. if (root->super->root != root)
  280. vfs_die ("We have to use _real_ root. Always. Sorry.");
  281. /* canonicalize as well, but don't remove '../' from path */
  282. custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
  283. if (!(flags & FL_DIR)) {
  284. char *dirname, *name, *save;
  285. struct vfs_s_inode *ino;
  286. split_dir_name (me, path, &dirname, &name, &save);
  287. ino =
  288. vfs_s_find_inode (me, root->super, dirname, follow,
  289. flags | FL_DIR);
  290. if (save)
  291. *save = PATH_SEP;
  292. retval = vfs_s_find_entry_tree (me, ino, name, follow, flags);
  293. g_free (path);
  294. return retval;
  295. }
  296. for (ent = root->subdir; ent != NULL; ent = ent->next)
  297. if (!strcmp (ent->name, path))
  298. break;
  299. if (ent && (!(MEDATA->dir_uptodate) (me, ent->ino))) {
  300. #if 1
  301. print_vfs_message (_("Directory cache expired for %s"), path);
  302. #endif
  303. vfs_s_free_entry (me, ent);
  304. ent = NULL;
  305. }
  306. if (!ent) {
  307. struct vfs_s_inode *ino;
  308. ino =
  309. vfs_s_new_inode (me, root->super,
  310. vfs_s_default_stat (me, S_IFDIR | 0755));
  311. ent = vfs_s_new_entry (me, path, ino);
  312. if ((MEDATA->dir_load) (me, ino, path) == -1) {
  313. vfs_s_free_entry (me, ent);
  314. g_free (path);
  315. return NULL;
  316. }
  317. vfs_s_insert_entry (me, root, ent);
  318. for (ent = root->subdir; ent != NULL; ent = ent->next)
  319. if (!strcmp (ent->name, path))
  320. break;
  321. }
  322. if (!ent)
  323. vfs_die ("find_linear: success but directory is not there\n");
  324. #if 0
  325. if (!vfs_s_resolve_symlink (me, ent, follow)) {
  326. g_free (path);
  327. return NULL;
  328. }
  329. #endif
  330. g_free (path);
  331. return ent;
  332. }
  333. struct vfs_s_inode *
  334. vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
  335. const char *path, int follow, int flags)
  336. {
  337. struct vfs_s_entry *ent;
  338. if (((MEDATA->flags & VFS_S_REMOTE) == 0) && (*path == '\0'))
  339. return super->root;
  340. ent = (MEDATA->find_entry) (me, super->root, path, follow, flags);
  341. return (ent != NULL) ? ent->ino : NULL;
  342. }
  343. /* Ook, these were functions around directory entries / inodes */
  344. /* -------------------------------- superblock games -------------------------- */
  345. static struct vfs_s_super *
  346. vfs_s_new_super (struct vfs_class *me)
  347. {
  348. struct vfs_s_super *super;
  349. super = g_new0 (struct vfs_s_super, 1);
  350. super->me = me;
  351. return super;
  352. }
  353. static void
  354. vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
  355. {
  356. super->next = MEDATA->supers;
  357. super->prevp = &MEDATA->supers;
  358. if (MEDATA->supers != NULL)
  359. MEDATA->supers->prevp = &super->next;
  360. MEDATA->supers = super;
  361. }
  362. static void
  363. vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
  364. {
  365. if (super->root){
  366. vfs_s_free_inode (me, super->root);
  367. super->root = NULL;
  368. }
  369. #if 0
  370. /* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
  371. if (super->ino_usage)
  372. message (D_ERROR, " Direntry warning ",
  373. "Super ino_usage is %d, memory leak",
  374. super->ino_usage);
  375. if (super->want_stale)
  376. message (D_ERROR, " Direntry warning ", "Super has want_stale set");
  377. #endif
  378. if (super->prevp){
  379. *super->prevp = super->next;
  380. if (super->next)
  381. super->next->prevp = super->prevp;
  382. }
  383. CALL (free_archive) (me, super);
  384. g_free (super->name);
  385. g_free(super);
  386. }
  387. /*
  388. * Dissect the path and create corresponding superblock. Note that inname
  389. * can be changed and the result may point inside the original string.
  390. */
  391. const char *
  392. vfs_s_get_path_mangle (struct vfs_class *me, char *inname,
  393. struct vfs_s_super **archive, int flags)
  394. {
  395. const char *retval;
  396. char *local, *op;
  397. const char *archive_name;
  398. int result = -1;
  399. struct vfs_s_super *super;
  400. void *cookie = NULL;
  401. archive_name = inname;
  402. vfs_split (inname, &local, &op);
  403. retval = (local) ? local : "";
  404. if (MEDATA->archive_check)
  405. if (!(cookie = MEDATA->archive_check (me, archive_name, op)))
  406. return NULL;
  407. for (super = MEDATA->supers; super != NULL; super = super->next) {
  408. /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
  409. int i = MEDATA->archive_same (me, super, archive_name, op, cookie);
  410. if (i != 0) {
  411. if (i == 1)
  412. goto return_success;
  413. else
  414. break;
  415. }
  416. }
  417. if (flags & FL_NO_OPEN)
  418. ERRNOR (EIO, NULL);
  419. super = vfs_s_new_super (me);
  420. result = MEDATA->open_archive (me, super, archive_name, op);
  421. if (result == -1) {
  422. vfs_s_free_super (me, super);
  423. ERRNOR (EIO, NULL);
  424. }
  425. if (!super->name)
  426. vfs_die ("You have to fill name\n");
  427. if (!super->root)
  428. vfs_die ("You have to fill root inode\n");
  429. vfs_s_insert_super (me, super);
  430. vfs_stamp_create (me, super);
  431. return_success:
  432. *archive = super;
  433. return retval;
  434. }
  435. /*
  436. * Dissect the path and create corresponding superblock.
  437. * The result should be freed.
  438. */
  439. static char *
  440. vfs_s_get_path (struct vfs_class *me, const char *inname,
  441. struct vfs_s_super **archive, int flags)
  442. {
  443. char *buf, *retval;
  444. buf = g_strdup (inname);
  445. retval = g_strdup (vfs_s_get_path_mangle (me, buf, archive, flags));
  446. g_free (buf);
  447. return retval;
  448. }
  449. void
  450. vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
  451. {
  452. if (!super->want_stale){
  453. vfs_s_free_inode (me, super->root);
  454. super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
  455. }
  456. }
  457. char *
  458. vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
  459. {
  460. if (!ino->ent)
  461. ERRNOR (EAGAIN, NULL);
  462. if (!(MEDATA->flags & VFS_S_REMOTE)) {
  463. /* archives */
  464. char *newpath;
  465. char *path = g_strdup (ino->ent->name);
  466. while (1) {
  467. ino = ino->ent->dir;
  468. if (ino == ino->super->root)
  469. break;
  470. newpath = g_strconcat (ino->ent->name, "/", path, (char *) NULL);
  471. g_free (path);
  472. path = newpath;
  473. }
  474. return path;
  475. }
  476. /* remote systems */
  477. if ((!ino->ent->dir) || (!ino->ent->dir->ent))
  478. return g_strdup (ino->ent->name);
  479. return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR,
  480. ino->ent->name, (char *) NULL);
  481. }
  482. /* Support of archives */
  483. /* ------------------------ readdir & friends ----------------------------- */
  484. static struct vfs_s_inode *
  485. vfs_s_inode_from_path (struct vfs_class *me, const char *name, int flags)
  486. {
  487. struct vfs_s_super *super;
  488. struct vfs_s_inode *ino;
  489. char *q;
  490. if (!(q = vfs_s_get_path (me, name, &super, 0)))
  491. return NULL;
  492. ino =
  493. vfs_s_find_inode (me, super, q,
  494. flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW,
  495. flags & ~FL_FOLLOW);
  496. if ((!ino) && (!*q))
  497. /* We are asking about / directory of ftp server: assume it exists */
  498. ino =
  499. vfs_s_find_inode (me, super, q,
  500. flags & FL_FOLLOW ? LINK_FOLLOW :
  501. LINK_NO_FOLLOW,
  502. FL_DIR | (flags & ~FL_FOLLOW));
  503. g_free (q);
  504. return ino;
  505. }
  506. struct dirhandle {
  507. struct vfs_s_entry *cur;
  508. struct vfs_s_inode *dir;
  509. };
  510. static void *
  511. vfs_s_opendir (struct vfs_class *me, const char *dirname)
  512. {
  513. struct vfs_s_inode *dir;
  514. struct dirhandle *info;
  515. dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
  516. if (!dir)
  517. return NULL;
  518. if (!S_ISDIR (dir->st.st_mode))
  519. ERRNOR (ENOTDIR, NULL);
  520. dir->st.st_nlink++;
  521. #if 0
  522. if (!dir->subdir) /* This can actually happen if we allow empty directories */
  523. ERRNOR (EAGAIN, NULL);
  524. #endif
  525. info = g_new (struct dirhandle, 1);
  526. info->cur = dir->subdir;
  527. info->dir = dir;
  528. return info;
  529. }
  530. static void *
  531. vfs_s_readdir(void *data)
  532. {
  533. static union vfs_dirent dir;
  534. struct dirhandle *info = (struct dirhandle *) data;
  535. if (!(info->cur))
  536. return NULL;
  537. if (info->cur->name) {
  538. g_strlcpy (dir.dent.d_name, info->cur->name, MC_MAXPATHLEN);
  539. } else {
  540. vfs_die("Null in structure-cannot happen");
  541. }
  542. compute_namelen(&dir.dent);
  543. info->cur = info->cur->next;
  544. return (void *) &dir;
  545. }
  546. static int
  547. vfs_s_closedir (void *data)
  548. {
  549. struct dirhandle *info = (struct dirhandle *) data;
  550. struct vfs_s_inode *dir = info->dir;
  551. vfs_s_free_inode (dir->super->me, dir);
  552. g_free (data);
  553. return 0;
  554. }
  555. static int
  556. vfs_s_chdir (struct vfs_class *me, const char *path)
  557. {
  558. void *data;
  559. if (!(data = vfs_s_opendir (me, path)))
  560. return -1;
  561. vfs_s_closedir (data);
  562. return 0;
  563. }
  564. /* --------------------------- stat and friends ---------------------------- */
  565. static int
  566. vfs_s_internal_stat (struct vfs_class *me, const char *path, struct stat *buf, int flag)
  567. {
  568. struct vfs_s_inode *ino;
  569. if (!(ino = vfs_s_inode_from_path (me, path, flag)))
  570. return -1;
  571. *buf = ino->st;
  572. return 0;
  573. }
  574. static int
  575. vfs_s_stat (struct vfs_class *me, const char *path, struct stat *buf)
  576. {
  577. return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
  578. }
  579. static int
  580. vfs_s_lstat (struct vfs_class *me, const char *path, struct stat *buf)
  581. {
  582. return vfs_s_internal_stat (me, path, buf, FL_NONE);
  583. }
  584. static int
  585. vfs_s_fstat (void *fh, struct stat *buf)
  586. {
  587. *buf = FH->ino->st;
  588. return 0;
  589. }
  590. static int
  591. vfs_s_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
  592. {
  593. struct vfs_s_inode *ino;
  594. size_t len;
  595. ino = vfs_s_inode_from_path (me, path, 0);
  596. if (!ino)
  597. return -1;
  598. if (!S_ISLNK (ino->st.st_mode))
  599. ERRNOR (EINVAL, -1);
  600. if (ino->linkname == NULL)
  601. ERRNOR (EFAULT, -1);
  602. len = strlen (ino->linkname);
  603. if (size < len)
  604. len = size;
  605. /* readlink() does not append a NUL character to buf */
  606. memcpy (buf, ino->linkname, len);
  607. return len;
  608. }
  609. void *
  610. vfs_s_open (struct vfs_class *me, const char *file, int flags, int mode)
  611. {
  612. int was_changed = 0;
  613. struct vfs_s_fh *fh;
  614. struct vfs_s_super *super;
  615. char *q;
  616. struct vfs_s_inode *ino;
  617. if ((q = vfs_s_get_path (me, file, &super, 0)) == NULL)
  618. return NULL;
  619. ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
  620. if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
  621. g_free (q);
  622. ERRNOR (EEXIST, NULL);
  623. }
  624. if (!ino) {
  625. char *dirname, *name, *save;
  626. struct vfs_s_entry *ent;
  627. struct vfs_s_inode *dir;
  628. int tmp_handle;
  629. /* If the filesystem is read-only, disable file creation */
  630. if (!(flags & O_CREAT) || !(me->write)) {
  631. g_free (q);
  632. return NULL;
  633. }
  634. split_dir_name (me, q, &dirname, &name, &save);
  635. /* FIXME: check if vfs_s_find_inode returns NULL */
  636. dir = vfs_s_find_inode (me, super, dirname, LINK_FOLLOW, FL_DIR);
  637. if (save)
  638. *save = PATH_SEP;
  639. ent = vfs_s_generate_entry (me, name, dir, 0755);
  640. ino = ent->ino;
  641. vfs_s_insert_entry (me, dir, ent);
  642. tmp_handle = vfs_mkstemps (&ino->localname, me->name, name);
  643. if (tmp_handle == -1) {
  644. g_free (q);
  645. return NULL;
  646. }
  647. close (tmp_handle);
  648. was_changed = 1;
  649. }
  650. g_free (q);
  651. if (S_ISDIR (ino->st.st_mode))
  652. ERRNOR (EISDIR, NULL);
  653. fh = g_new (struct vfs_s_fh, 1);
  654. fh->pos = 0;
  655. fh->ino = ino;
  656. fh->handle = -1;
  657. fh->changed = was_changed;
  658. fh->linear = 0;
  659. if (IS_LINEAR (flags)) {
  660. if (MEDATA->linear_start) {
  661. print_vfs_message (_("Starting linear transfer..."));
  662. fh->linear = LS_LINEAR_PREOPEN;
  663. }
  664. } else if ((MEDATA->fh_open)
  665. && (MEDATA->fh_open (me, fh, flags, mode))) {
  666. g_free (fh);
  667. return NULL;
  668. }
  669. if (fh->ino->localname) {
  670. fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
  671. if (fh->handle == -1) {
  672. g_free (fh);
  673. ERRNOR (errno, NULL);
  674. }
  675. }
  676. /* i.e. we had no open files and now we have one */
  677. vfs_rmstamp (me, (vfsid) super);
  678. super->fd_usage++;
  679. fh->ino->st.st_nlink++;
  680. return fh;
  681. }
  682. static ssize_t
  683. vfs_s_read (void *fh, char *buffer, int count)
  684. {
  685. int n;
  686. struct vfs_class *me = FH_SUPER->me;
  687. if (FH->linear == LS_LINEAR_PREOPEN) {
  688. if (!MEDATA->linear_start (me, FH, FH->pos))
  689. return -1;
  690. }
  691. if (FH->linear == LS_LINEAR_CLOSED)
  692. vfs_die ("linear_start() did not set linear_state!");
  693. if (FH->linear == LS_LINEAR_OPEN)
  694. return MEDATA->linear_read (me, FH, buffer, count);
  695. if (FH->handle != -1){
  696. n = read (FH->handle, buffer, count);
  697. if (n < 0)
  698. me->verrno = errno;
  699. return n;
  700. }
  701. vfs_die ("vfs_s_read: This should not happen\n");
  702. return -1;
  703. }
  704. static ssize_t
  705. vfs_s_write (void *fh, const char *buffer, int count)
  706. {
  707. int n;
  708. struct vfs_class *me = FH_SUPER->me;
  709. if (FH->linear)
  710. vfs_die ("no writing to linear files, please");
  711. FH->changed = 1;
  712. if (FH->handle != -1){
  713. n = write (FH->handle, buffer, count);
  714. if (n < 0)
  715. me->verrno = errno;
  716. return n;
  717. }
  718. vfs_die ("vfs_s_write: This should not happen\n");
  719. return 0;
  720. }
  721. static off_t
  722. vfs_s_lseek (void *fh, off_t offset, int whence)
  723. {
  724. off_t size = FH->ino->st.st_size;
  725. if (FH->linear == LS_LINEAR_OPEN)
  726. vfs_die ("cannot lseek() after linear_read!");
  727. if (FH->handle != -1){ /* If we have local file opened, we want to work with it */
  728. int retval = lseek (FH->handle, offset, whence);
  729. if (retval == -1)
  730. FH->ino->super->me->verrno = errno;
  731. return retval;
  732. }
  733. switch (whence){
  734. case SEEK_CUR:
  735. offset += FH->pos; break;
  736. case SEEK_END:
  737. offset += size; break;
  738. }
  739. if (offset < 0)
  740. FH->pos = 0;
  741. else if (offset < size)
  742. FH->pos = offset;
  743. else
  744. FH->pos = size;
  745. return FH->pos;
  746. }
  747. static int
  748. vfs_s_close (void *fh)
  749. {
  750. int res = 0;
  751. struct vfs_class *me = FH_SUPER->me;
  752. FH_SUPER->fd_usage--;
  753. if (!FH_SUPER->fd_usage)
  754. vfs_stamp_create (me, FH_SUPER);
  755. if (FH->linear == LS_LINEAR_OPEN)
  756. MEDATA->linear_close (me, fh);
  757. if (MEDATA->fh_close)
  758. res = MEDATA->fh_close (me, fh);
  759. if (FH->changed && MEDATA->file_store){
  760. char *s = vfs_s_fullpath (me, FH->ino);
  761. if (!s)
  762. res = -1;
  763. else {
  764. res = MEDATA->file_store (me, fh, s, FH->ino->localname);
  765. g_free (s);
  766. }
  767. vfs_s_invalidate (me, FH_SUPER);
  768. }
  769. if (FH->handle != -1)
  770. close (FH->handle);
  771. vfs_s_free_inode (me, FH->ino);
  772. g_free (fh);
  773. return res;
  774. }
  775. static void
  776. vfs_s_print_stats (const char *fs_name, const char *action,
  777. const char *file_name, off_t have, off_t need)
  778. {
  779. static const char *i18n_percent_transf_format = NULL;
  780. static const char *i18n_transf_format = NULL;
  781. if (i18n_percent_transf_format == NULL) {
  782. i18n_percent_transf_format =
  783. _("%s: %s: %s %3d%% (%lu bytes transferred)");
  784. i18n_transf_format = _("%s: %s: %s %lu bytes transferred");
  785. }
  786. if (need)
  787. print_vfs_message (i18n_percent_transf_format, fs_name, action,
  788. file_name, (int) ((double) have * 100 / need),
  789. (unsigned long) have);
  790. else
  791. print_vfs_message (i18n_transf_format, fs_name, action, file_name,
  792. (unsigned long) have);
  793. }
  794. int
  795. vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
  796. {
  797. /* If you want reget, you'll have to open file with O_LINEAR */
  798. off_t total = 0;
  799. char buffer[8192];
  800. int handle, n;
  801. off_t stat_size = ino->st.st_size;
  802. struct vfs_s_fh fh;
  803. memset (&fh, 0, sizeof (fh));
  804. fh.ino = ino;
  805. fh.handle = -1;
  806. handle = vfs_mkstemps (&ino->localname, me->name, ino->ent->name);
  807. if (handle == -1) {
  808. me->verrno = errno;
  809. goto error_4;
  810. }
  811. if (!MEDATA->linear_start (me, &fh, 0))
  812. goto error_3;
  813. /* Clear the interrupt status */
  814. tty_got_interrupt ();
  815. tty_enable_interrupt_key ();
  816. while ((n = MEDATA->linear_read (me, &fh, buffer, sizeof (buffer)))) {
  817. int t;
  818. if (n < 0)
  819. goto error_1;
  820. total += n;
  821. vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name,
  822. total, stat_size);
  823. if (tty_got_interrupt ())
  824. goto error_1;
  825. t = write (handle, buffer, n);
  826. if (t != n) {
  827. if (t == -1)
  828. me->verrno = errno;
  829. goto error_1;
  830. }
  831. }
  832. MEDATA->linear_close (me, &fh);
  833. close (handle);
  834. tty_disable_interrupt_key ();
  835. return 0;
  836. error_1:
  837. MEDATA->linear_close (me, &fh);
  838. error_3:
  839. tty_disable_interrupt_key ();
  840. close (handle);
  841. unlink (ino->localname);
  842. error_4:
  843. g_free (ino->localname);
  844. ino->localname = NULL;
  845. return -1;
  846. }
  847. /* ------------------------------- mc support ---------------------------- */
  848. static void
  849. vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
  850. {
  851. struct vfs_s_super *a = MEDATA->supers;
  852. char *name;
  853. while (a){
  854. name = g_strconcat ( a->name, "#", me->prefix, "/",
  855. /* a->current_dir->name, */ (char *) NULL);
  856. (*func)(name);
  857. g_free (name);
  858. a = a->next;
  859. }
  860. }
  861. static int
  862. vfs_s_ferrno (struct vfs_class *me)
  863. {
  864. return me->verrno;
  865. }
  866. /*
  867. * Get local copy of the given file. We reuse the existing file cache
  868. * for remote filesystems. Archives use standard VFS facilities.
  869. */
  870. static char *
  871. vfs_s_getlocalcopy (struct vfs_class *me, const char *path)
  872. {
  873. struct vfs_s_fh *fh;
  874. char *local;
  875. fh = vfs_s_open (me, path, O_RDONLY, 0);
  876. if (!fh || !fh->ino || !fh->ino->localname)
  877. return NULL;
  878. local = g_strdup (fh->ino->localname);
  879. vfs_s_close (fh);
  880. return local;
  881. }
  882. /*
  883. * Return the local copy. Since we are using our cache, we do nothing -
  884. * the cache will be removed when the archive is closed.
  885. */
  886. static int
  887. vfs_s_ungetlocalcopy (struct vfs_class *me, const char *path,
  888. const char *local, int has_changed)
  889. {
  890. (void) me;
  891. (void) path;
  892. (void) local;
  893. (void) has_changed;
  894. return 0;
  895. }
  896. static int
  897. vfs_s_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
  898. {
  899. switch (ctlop) {
  900. case VFS_SETCTL_STALE_DATA:
  901. {
  902. struct vfs_s_inode *ino = vfs_s_inode_from_path (me, path, 0);
  903. if (!ino)
  904. return 0;
  905. if (arg)
  906. ino->super->want_stale = 1;
  907. else {
  908. ino->super->want_stale = 0;
  909. vfs_s_invalidate (me, ino->super);
  910. }
  911. return 1;
  912. }
  913. case VFS_SETCTL_LOGFILE:
  914. MEDATA->logfile = fopen ((char *) arg, "w");
  915. return 1;
  916. case VFS_SETCTL_FLUSH:
  917. MEDATA->flush = 1;
  918. return 1;
  919. }
  920. return 0;
  921. }
  922. /* ----------------------------- Stamping support -------------------------- */
  923. static vfsid
  924. vfs_s_getid (struct vfs_class *me, const char *path)
  925. {
  926. struct vfs_s_super *archive;
  927. char *p;
  928. if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
  929. return NULL;
  930. g_free(p);
  931. return (vfsid) archive;
  932. }
  933. static int
  934. vfs_s_nothingisopen (vfsid id)
  935. {
  936. (void) id;
  937. /* Our data structures should survive free of superblock at any time */
  938. return 1;
  939. }
  940. static void
  941. vfs_s_free (vfsid id)
  942. {
  943. vfs_s_free_super (((struct vfs_s_super *)id)->me, (struct vfs_s_super *)id);
  944. }
  945. static int
  946. vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
  947. {
  948. struct timeval tim;
  949. if (MEDATA->flush) {
  950. MEDATA->flush = 0;
  951. return 0;
  952. }
  953. gettimeofday(&tim, NULL);
  954. if (tim.tv_sec < ino->timestamp.tv_sec)
  955. return 1;
  956. return 0;
  957. }
  958. /* Initialize one of our subclasses - fill common functions */
  959. void
  960. vfs_s_init_class (struct vfs_class *vclass, struct vfs_s_subclass *sub)
  961. {
  962. vclass->data = sub;
  963. vclass->fill_names = vfs_s_fill_names;
  964. vclass->open = vfs_s_open;
  965. vclass->close = vfs_s_close;
  966. vclass->read = vfs_s_read;
  967. if (!(sub->flags & VFS_S_READONLY)) {
  968. vclass->write = vfs_s_write;
  969. }
  970. vclass->opendir = vfs_s_opendir;
  971. vclass->readdir = vfs_s_readdir;
  972. vclass->closedir = vfs_s_closedir;
  973. vclass->stat = vfs_s_stat;
  974. vclass->lstat = vfs_s_lstat;
  975. vclass->fstat = vfs_s_fstat;
  976. vclass->readlink = vfs_s_readlink;
  977. vclass->chdir = vfs_s_chdir;
  978. vclass->ferrno = vfs_s_ferrno;
  979. vclass->lseek = vfs_s_lseek;
  980. vclass->getid = vfs_s_getid;
  981. vclass->nothingisopen = vfs_s_nothingisopen;
  982. vclass->free = vfs_s_free;
  983. if (sub->flags & VFS_S_REMOTE) {
  984. vclass->getlocalcopy = vfs_s_getlocalcopy;
  985. vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
  986. sub->find_entry = vfs_s_find_entry_linear;
  987. } else {
  988. sub->find_entry = vfs_s_find_entry_tree;
  989. }
  990. vclass->setctl = vfs_s_setctl;
  991. sub->dir_uptodate = vfs_s_dir_uptodate;
  992. }
  993. /* ----------- Utility functions for networked filesystems -------------- */
  994. #ifdef USE_NETCODE
  995. int
  996. vfs_s_select_on_two (int fd1, int fd2)
  997. {
  998. fd_set set;
  999. struct timeval time_out;
  1000. int v;
  1001. int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
  1002. time_out.tv_sec = 1;
  1003. time_out.tv_usec = 0;
  1004. FD_ZERO (&set);
  1005. FD_SET (fd1, &set);
  1006. FD_SET (fd2, &set);
  1007. v = select (maxfd, &set, 0, 0, &time_out);
  1008. if (v <= 0)
  1009. return v;
  1010. if (FD_ISSET (fd1, &set))
  1011. return 1;
  1012. if (FD_ISSET (fd2, &set))
  1013. return 2;
  1014. return -1;
  1015. }
  1016. int
  1017. vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
  1018. {
  1019. FILE *logfile = MEDATA->logfile;
  1020. int i;
  1021. char c;
  1022. for (i = 0; i < buf_len - 1; i++, buf++){
  1023. if (read (sock, buf, sizeof(char)) <= 0)
  1024. return 0;
  1025. if (logfile){
  1026. fwrite (buf, 1, 1, logfile);
  1027. fflush (logfile);
  1028. }
  1029. if (*buf == term){
  1030. *buf = 0;
  1031. return 1;
  1032. }
  1033. }
  1034. /* Line is too long - terminate buffer and discard the rest of line */
  1035. *buf = 0;
  1036. while (read (sock, &c, sizeof (c)) > 0) {
  1037. if (logfile){
  1038. fwrite (&c, 1, 1, logfile);
  1039. fflush (logfile);
  1040. }
  1041. if (c == '\n')
  1042. return 1;
  1043. }
  1044. return 0;
  1045. }
  1046. int
  1047. vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
  1048. {
  1049. int n;
  1050. int i;
  1051. (void) me;
  1052. tty_enable_interrupt_key ();
  1053. for (i = 0; i < size-1; i++){
  1054. n = read (fd, buffer+i, 1);
  1055. tty_disable_interrupt_key ();
  1056. if (n == -1 && errno == EINTR){
  1057. buffer [i] = 0;
  1058. return EINTR;
  1059. }
  1060. if (n == 0){
  1061. buffer [i] = 0;
  1062. return 0;
  1063. }
  1064. if (buffer [i] == '\n'){
  1065. buffer [i] = 0;
  1066. return 1;
  1067. }
  1068. }
  1069. buffer [size-1] = 0;
  1070. return 0;
  1071. }
  1072. #endif /* USE_NETCODE */