direntry.c 29 KB

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