direntry.c 28 KB

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