direntry.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  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. * Based on tar.c from midnight and archives.[ch] from avfs by Miklos
  7. * 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. static volatile int total_inodes = 0, total_entries = 0;
  27. #include "xdirentry.h"
  28. #define CALL(x) if (MEDATA->x) MEDATA->x
  29. vfs_s_inode *vfs_s_new_inode (vfs *me, vfs_s_super *super, struct stat *initstat)
  30. {
  31. vfs_s_inode *ino;
  32. ino = xmalloc(sizeof (vfs_s_inode), "Dcache inode");
  33. if (!ino) return NULL;
  34. ino->linkname = ino->localname = NULL;
  35. ino->subdir = NULL;
  36. if (initstat)
  37. ino->st = *initstat;
  38. ino->super = super;
  39. ino->ent = NULL;
  40. ino->flags = 0;
  41. ino->st.st_nlink = 0;
  42. super->fd_usage++;
  43. total_inodes++;
  44. CALL(init_inode) (me, ino);
  45. return ino;
  46. }
  47. vfs_s_entry *vfs_s_new_entry (vfs *me, char *name, vfs_s_inode *inode)
  48. {
  49. vfs_s_entry *entry;
  50. entry = (struct vfs_s_entry *) xmalloc (sizeof (struct vfs_s_entry), "Dcache entry");
  51. total_entries++;
  52. if (name)
  53. entry->name = strdup (name);
  54. else entry->name = NULL;
  55. entry->dir = NULL;
  56. entry->next = NULL;
  57. entry->prevp = NULL;
  58. entry->ino = inode;
  59. entry->ino->ent = entry;
  60. CALL(init_entry) (me, entry);
  61. return entry;
  62. }
  63. void vfs_s_free_inode (vfs *me, vfs_s_inode *ino)
  64. {
  65. if (!ino) vfs_die("Don't pass NULL to me");
  66. /* ==0 can happen if freshly created entry is deleted */
  67. if(ino->st.st_nlink <= 1) {
  68. while(ino->subdir) {
  69. vfs_s_entry *ent;
  70. ent = ino->subdir;
  71. vfs_s_free_entry(me, ent);
  72. }
  73. CALL(free_inode) (me, ino);
  74. ifree(ino->linkname);
  75. if (ino->localname) {
  76. unlink(ino->localname);
  77. free(ino->localname);
  78. }
  79. total_inodes--;
  80. ino->super->fd_usage--;
  81. free(ino);
  82. } else ino->st.st_nlink--;
  83. }
  84. void vfs_s_free_entry (vfs *me, vfs_s_entry *ent)
  85. {
  86. int is_dot = 0;
  87. if (ent->prevp) { /* It is possible that we are deleting freshly created entry */
  88. *ent->prevp = ent->next;
  89. if (ent->next) ent->next->prevp = ent->prevp;
  90. }
  91. if (ent->name) {
  92. is_dot = (!strcmp(ent->name, ".")) || (!strcmp(ent->name, ".."));
  93. free (ent->name);
  94. ent->name = NULL;
  95. }
  96. if (!is_dot && ent->ino) {
  97. ent->ino->ent = NULL;
  98. vfs_s_free_inode (me, ent->ino);
  99. ent->ino = NULL;
  100. }
  101. total_entries--;
  102. free(ent);
  103. }
  104. void vfs_s_insert_entry (vfs *me, vfs_s_inode *dir, vfs_s_entry *ent)
  105. {
  106. vfs_s_entry **ep;
  107. for(ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next));
  108. ent->prevp = ep;
  109. ent->next = NULL;
  110. ent->dir = dir;
  111. *ep = ent;
  112. ent->ino->st.st_nlink++;
  113. }
  114. struct stat *vfs_s_default_stat (vfs *me, mode_t mode)
  115. {
  116. static struct stat st;
  117. int myumask;
  118. myumask = umask (022);
  119. umask (myumask);
  120. mode &= ~myumask;
  121. st.st_mode = mode;
  122. st.st_ino = MEDATA->inode_counter++;
  123. st.st_dev = MEDATA->rdev;
  124. st.st_rdev = 0;
  125. st.st_uid = getuid ();
  126. st.st_gid = getgid ();
  127. st.st_size = 0;
  128. st.st_mtime = st.st_atime = st.st_ctime = time (NULL);
  129. return &st;
  130. }
  131. void vfs_s_add_dots (vfs *me, vfs_s_inode *dir, vfs_s_inode *parent)
  132. {
  133. struct vfs_s_entry *dot, *dotdot;
  134. if (!parent)
  135. parent = dir;
  136. dot = vfs_s_new_entry (me, ".", dir);
  137. dotdot = vfs_s_new_entry (me, "..", parent);
  138. vfs_s_insert_entry(me, dir, dot);
  139. vfs_s_insert_entry(me, dir, dotdot);
  140. dir->st.st_nlink--; parent->st.st_nlink--; /* We do not count "." and ".." into nlinks */
  141. }
  142. struct vfs_s_entry *vfs_s_generate_entry (vfs *me, char *name, struct vfs_s_inode *parent, mode_t mode)
  143. {
  144. struct vfs_s_inode *inode;
  145. struct vfs_s_entry *entry;
  146. struct stat *st;
  147. st = vfs_s_default_stat (me, mode);
  148. inode = vfs_s_new_inode (me, parent->super, st);
  149. if (S_ISDIR (mode))
  150. vfs_s_add_dots (me, inode, parent);
  151. entry = vfs_s_new_entry (me, name, inode);
  152. return entry;
  153. }
  154. /* We were asked to create entries automagically */
  155. vfs_s_entry *vfs_s_automake(vfs *me, vfs_s_inode *dir, char *path, int flags)
  156. {
  157. struct vfs_s_entry *res;
  158. char *sep = strchr( path, DIR_SEP_CHAR );
  159. if (sep) *sep = 0;
  160. res = vfs_s_generate_entry(me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777 );
  161. vfs_s_insert_entry(me, dir, res);
  162. if (sep) *sep = DIR_SEP_CHAR;
  163. return res;
  164. }
  165. /* Follow > 0: follow links, serves as loop protect,
  166. * == -1: do not follow links */
  167. vfs_s_entry *vfs_s_find_entry_tree(vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
  168. {
  169. unsigned int pseg;
  170. vfs_s_entry* ent = NULL;
  171. int found;
  172. while(1) {
  173. for(pseg = 0; path[pseg] == DIR_SEP_CHAR; pseg++);
  174. if(!path[pseg]) return ent;
  175. path += pseg;
  176. for(pseg = 0; path[pseg] && path[pseg] != DIR_SEP_CHAR; pseg++);
  177. found = 0;
  178. for(ent = root->subdir; ent != NULL; ent = ent->next)
  179. if(strlen(ent->name) == pseg && (!strncmp(ent->name, path, pseg)))
  180. /* FOUND! */
  181. break;
  182. if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
  183. ent = vfs_s_automake(me, root, path, flags);
  184. if (!ent) ERRNOR (ENOENT, NULL);
  185. path += pseg;
  186. if (!vfs_s_resolve_symlink(me, ent, follow)) return NULL;
  187. root = ent->ino;
  188. }
  189. }
  190. static void split_dir_name(vfs *me, char *path, char **dir, char **name, char **save)
  191. {
  192. char *s;
  193. s = strrchr(path, DIR_SEP_CHAR);
  194. if (!s) {
  195. *save = NULL;
  196. *name = path;
  197. *dir = "";
  198. } else {
  199. *save = s;
  200. *dir = path;
  201. *s++ = 0;
  202. if (!*s) /* This can happen if someone does stat("/"); */
  203. *name = "";
  204. else
  205. *name = s;
  206. }
  207. }
  208. vfs_s_entry *vfs_s_find_entry_linear(vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
  209. {
  210. char *s;
  211. vfs_s_entry* ent = NULL;
  212. if (!(flags & FL_DIR)) {
  213. char *dirname, *name, *save;
  214. vfs_s_inode *ino;
  215. vfs_s_entry *ent;
  216. split_dir_name(me, path, &dirname, &name, &save);
  217. ino = vfs_s_find_inode(me, root, dirname, follow, flags | FL_DIR);
  218. if (save)
  219. *save = DIR_SEP_CHAR;
  220. ent = vfs_s_find_entry_tree(me, ino, name, follow, flags);
  221. return ent;
  222. }
  223. for(ent = root->subdir; ent != NULL; ent = ent->next)
  224. if (!strcmp(ent->name, path))
  225. break;
  226. if (ent && (! (MEDATA->dir_uptodate) (me, ent->ino))) {
  227. #if 0
  228. message_1s( 1, "Dir cache expired for", path);
  229. #endif
  230. vfs_s_free_entry (me, ent);
  231. }
  232. if (!ent) {
  233. vfs_s_inode *ino;
  234. ino = vfs_s_new_inode(me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
  235. ent = vfs_s_new_entry(me, path, ino);
  236. if ((MEDATA->dir_load) (me, ino, path) == -1) {
  237. vfs_s_free_entry(me, ent);
  238. return NULL;
  239. }
  240. vfs_s_insert_entry(me, root, ent);
  241. for(ent = root->subdir; ent != NULL; ent = ent->next)
  242. if (!strcmp(ent->name, path))
  243. break;
  244. }
  245. if (!ent)
  246. vfs_die("find_linear: success but directory is not there\n");
  247. #if 0
  248. if (!vfs_s_resolve_symlink(me, ent, follow)) return NULL;
  249. #endif
  250. return ent;
  251. }
  252. vfs_s_inode *vfs_s_find_inode(vfs *me, vfs_s_inode *root, char *path, int follow, int flags)
  253. {
  254. vfs_s_entry *ent;
  255. if ((MEDATA->find_entry == vfs_s_find_entry_tree) && (!*path))
  256. return root;
  257. ent = (MEDATA->find_entry)(me, root, path, follow, flags);
  258. if (!ent)
  259. return NULL;
  260. return ent->ino;
  261. }
  262. vfs_s_inode *vfs_s_find_root(vfs *me, vfs_s_entry *entry)
  263. {
  264. vfs_die("Implement me");
  265. return NULL;
  266. }
  267. vfs_s_entry *vfs_s_resolve_symlink (vfs *me, vfs_s_entry *entry, int follow)
  268. {
  269. vfs_s_inode *dir;
  270. if (follow == -1)
  271. return entry;
  272. if (follow == 0)
  273. ERRNOR (ELOOP, NULL);
  274. if (!entry)
  275. ERRNOR (ENOENT, NULL);
  276. if (!S_ISLNK(entry->ino->st.st_mode))
  277. return entry;
  278. /* We have to handle "/" by ourself; "." and ".." have
  279. corresponding entries, so there's no problem with them.
  280. FIXME: no longer true */
  281. if (*entry->ino->linkname == '/') dir = vfs_s_find_root(me, entry);
  282. else dir = entry->dir;
  283. return (MEDATA->find_entry) (me, dir, entry->ino->linkname, follow-1, 0);
  284. }
  285. /* Ook, these were functions around direcory entries / inodes */
  286. /* -------------------------------- superblock games -------------------------- */
  287. vfs_s_super *vfs_s_new_super (vfs *me)
  288. {
  289. vfs_s_super *super;
  290. super = xmalloc( sizeof( struct vfs_s_super ), "Direntry: superblock" );
  291. bzero(super, sizeof(struct vfs_s_super));
  292. super->root = NULL;
  293. super->name = NULL;
  294. super->fd_usage = 0;
  295. super->me = me;
  296. }
  297. void vfs_s_insert_super (vfs *me, vfs_s_super *super)
  298. {
  299. super->next = MEDATA->supers;
  300. super->prevp = &MEDATA->supers;
  301. if (MEDATA->supers != NULL) MEDATA->supers->prevp = &super->next;
  302. MEDATA->supers = super;
  303. return super;
  304. }
  305. void vfs_s_free_super (vfs *me, vfs_s_super *super)
  306. {
  307. if (super->root) {
  308. vfs_s_free_inode (me, super->root);
  309. super->root = NULL;
  310. }
  311. #if 0
  312. /* We currently leak small ammount of memory, sometimes. Fix it if you can. */
  313. if (super->fd_usage)
  314. message_1s1d (1, " Direntry warning ", "Super fd_usage is %d, memory leak", super->fd_usage);
  315. #endif
  316. if (super->prevp) {
  317. *super->prevp = super->next;
  318. if (super->next) super->next->prevp = super->prevp;
  319. }
  320. CALL(free_archive) (me, super);
  321. ifree(super->name);
  322. super->name = NULL;
  323. free(super);
  324. }
  325. /* ------------------------------------------------------------------------= */
  326. static void vfs_s_stamp_me (vfs *me, struct vfs_s_super *psup, char *fs_name)
  327. {
  328. struct vfs_stamping *parent;
  329. vfs *v;
  330. v = vfs_type (fs_name);
  331. if (v == &vfs_local_ops) {
  332. parent = NULL;
  333. } else {
  334. parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
  335. parent->v = v;
  336. parent->next = 0;
  337. parent->id = (*v->getid) (v, fs_name, &(parent->parent));
  338. }
  339. vfs_add_noncurrent_stamps (&vfs_tarfs_ops, (vfsid) psup, parent);
  340. vfs_rm_parents (parent);
  341. }
  342. char *vfs_s_get_path_mangle (vfs *me, char *inname, struct vfs_s_super **archive, int flags)
  343. {
  344. char *local, *op, *archive_name;
  345. int result = -1;
  346. struct vfs_s_super *super;
  347. void *cookie;
  348. archive_name = inname;
  349. vfs_split( inname, &local, &op );
  350. if (!local)
  351. local = "";
  352. if (MEDATA->archive_check)
  353. if (! (cookie = MEDATA->archive_check (me, archive_name, op)))
  354. return NULL;
  355. for (super = MEDATA->supers; super != NULL; super = super->next) {
  356. int i; /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
  357. if ((i = MEDATA->archive_same (me, super, archive_name, op, cookie))) {
  358. if (i==1) goto return_success;
  359. else break;
  360. }
  361. }
  362. if (flags & FL_NO_OPEN) ERRNOR (EIO, NULL);
  363. super = vfs_s_new_super (me);
  364. result = MEDATA->open_archive (me, super, archive_name, op);
  365. if (result == -1) {
  366. vfs_s_free_super (me, super);
  367. ERRNOR (EIO, NULL);
  368. }
  369. if (!super->name)
  370. vfs_die( "You have to fill name\n" );
  371. if (!super->root)
  372. vfs_die( "You have to fill root inode\n" );
  373. vfs_s_insert_super (me, super);
  374. vfs_s_stamp_me (me, super, archive_name);
  375. return_success:
  376. *archive = super;
  377. return local;
  378. }
  379. char *vfs_s_get_path (vfs *me, char *inname, struct vfs_s_super **archive, int flags)
  380. {
  381. char *buf = strdup( inname );
  382. char *res = vfs_s_get_path_mangle( me, buf, archive, flags );
  383. char *res2 = NULL;
  384. if (res)
  385. res2 = strdup(res);
  386. free(buf);
  387. return res2;
  388. }
  389. void vfs_s_invalidate (vfs *me, vfs_s_super *super)
  390. {
  391. if (!super->want_stale) {
  392. vfs_s_free_inode(me, super->root);
  393. super->root = vfs_s_new_inode (me, super, vfs_s_default_stat(me, S_IFDIR | 0755));
  394. }
  395. }
  396. char *vfs_s_fullpath (vfs *me, vfs_s_inode *ino)
  397. { /* For now, usable only on filesystems with _linear structure */
  398. if (MEDATA->find_entry != vfs_s_find_entry_linear)
  399. vfs_die( "Implement me!" );
  400. if ((!ino->ent) || (!ino->ent->dir) || (!ino->ent->dir->ent))
  401. ERRNOR(EAGAIN, NULL);
  402. return copy_strings( ino->ent->dir->ent->name, "/", ino->ent->name, NULL );
  403. }
  404. /* Support of archives */
  405. /* ------------------------ readdir & friends ----------------------------- */
  406. vfs_s_super *vfs_s_super_from_path (vfs *me, char *name)
  407. {
  408. struct vfs_s_super *super;
  409. if (!vfs_s_get_path_mangle (me, name, &super, 0))
  410. return NULL;
  411. return super;
  412. }
  413. vfs_s_inode *vfs_s_inode_from_path (vfs *me, char *name, int flags)
  414. {
  415. struct vfs_s_super *super;
  416. struct vfs_s_inode *ino;
  417. char *q;
  418. if (!(q = vfs_s_get_path_mangle (me, name, &super, 0)))
  419. return NULL;
  420. ino = vfs_s_find_inode (me, super->root, q, flags & FL_FOLLOW ? FOLLOW : NO_FOLLOW, flags & ~FL_FOLLOW);
  421. if (ino) return ino;
  422. return ino;
  423. }
  424. struct dirhandle {
  425. vfs_s_entry *cur;
  426. vfs_s_inode *dir;
  427. };
  428. void * vfs_s_opendir (vfs *me, char *dirname)
  429. {
  430. struct vfs_s_inode *dir;
  431. struct dirhandle *info;
  432. dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
  433. if (!dir) return NULL;
  434. if (!S_ISDIR (dir->st.st_mode)) ERRNOR (ENOTDIR, NULL);
  435. dir->st.st_nlink++;
  436. #if 0
  437. if (!dir->subdir) /* This can actually happen if we allow empty directories */
  438. ERRNOR(EAGAIN, NULL);
  439. #endif
  440. info = (struct dirhandle *) xmalloc (sizeof (struct dirhandle), "Shared opendir");
  441. info->cur = dir->subdir;
  442. info->dir = dir;
  443. return info;
  444. }
  445. void * vfs_s_readdir (void *data)
  446. {
  447. static struct {
  448. struct dirent dir;
  449. #ifdef NEED_EXTRA_DIRENT_BUFFER
  450. char extra_buffer [MC_MAXPATHLEN];
  451. #endif
  452. } dir;
  453. struct dirhandle *info = (struct dirhandle *) data;
  454. if (!(info->cur))
  455. return NULL;
  456. if (info->cur->name)
  457. strcpy (&(dir.dir.d_name [0]), info->cur->name);
  458. else
  459. vfs_die( "Null in structure-can not happen");
  460. #ifndef DIRENT_LENGTH_COMPUTED
  461. dir.d_namlen = strlen (dir.dir.d_name);
  462. #endif
  463. info->cur = info->cur->next;
  464. return (void *)&dir;
  465. }
  466. int vfs_s_telldir (void *data)
  467. {
  468. struct dirhandle *info = (struct dirhandle *) data;
  469. struct vfs_s_entry *cur;
  470. int num = 0;
  471. cur = info->dir->subdir;
  472. while (cur!=NULL) {
  473. if (cur == info->cur) return num;
  474. num++;
  475. cur = cur->next;
  476. }
  477. return -1;
  478. }
  479. void vfs_s_seekdir (void *data, int offset)
  480. {
  481. struct dirhandle *info = (struct dirhandle *) data;
  482. int i;
  483. info->cur = info->dir->subdir;
  484. for (i=0; i<offset; i++)
  485. vfs_s_readdir( data );
  486. }
  487. int vfs_s_closedir (void *data)
  488. {
  489. struct dirhandle *info = (struct dirhandle *) data;
  490. struct vfs_s_inode *dir = info->dir;
  491. vfs_s_free_inode(dir->super->me, dir);
  492. free (data);
  493. return 0;
  494. }
  495. int vfs_s_chdir (vfs *me, char *path)
  496. {
  497. void *data;
  498. if (!(data = vfs_s_opendir( me, path )))
  499. return -1;
  500. vfs_s_closedir(data);
  501. return 0;
  502. }
  503. /* --------------------------- stat and friends ---------------------------- */
  504. static int vfs_s_internal_stat (vfs *me, char *path, struct stat *buf, int flag)
  505. {
  506. struct vfs_s_inode *ino;
  507. if (!(ino = vfs_s_inode_from_path( me, path, flag ))) return -1;
  508. *buf = ino->st;
  509. return 0;
  510. }
  511. int vfs_s_stat (vfs *me, char *path, struct stat *buf)
  512. {
  513. return vfs_s_internal_stat (me, path, buf, FL_FOLLOW);
  514. }
  515. int vfs_s_lstat (vfs *me, char *path, struct stat *buf)
  516. {
  517. return vfs_s_internal_stat (me, path, buf, FL_NONE);
  518. }
  519. int vfs_s_fstat (void *fh, struct stat *buf)
  520. {
  521. *buf = FH->ino->st;
  522. return 0;
  523. }
  524. int vfs_s_readlink (vfs *me, char *path, char *buf, int size)
  525. {
  526. struct vfs_s_inode *ino;
  527. ino = vfs_s_inode_from_path(me, path, 0);
  528. if (!ino) return -1;
  529. if (!S_ISLNK (ino->st.st_mode)) ERRNOR (EINVAL, -1);
  530. strncpy (buf, ino->linkname, size);
  531. *(buf+size-1) = 0;
  532. return strlen(buf);
  533. }
  534. void *vfs_s_open (vfs *me, char *file, int flags, int mode)
  535. {
  536. int was_changed = 0;
  537. struct vfs_s_fh *fh;
  538. vfs_s_super *super;
  539. char *q;
  540. struct vfs_s_inode *ino;
  541. if ((q = vfs_s_get_path_mangle (me, file, &super, 0)) == NULL)
  542. return NULL;
  543. ino = vfs_s_find_inode (me, super->root, q, FOLLOW, FL_NONE);
  544. if (ino && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)))
  545. ERRNOR (EEXIST, NULL);
  546. if (!ino) {
  547. char *dirname, *name, *save;
  548. vfs_s_entry *ent;
  549. vfs_s_inode *dir;
  550. if (!(flags & O_CREAT))
  551. return NULL;
  552. split_dir_name(me, q, &dirname, &name, &save);
  553. dir = vfs_s_find_inode(me, super->root, dirname, FOLLOW, FL_DIR);
  554. if (save)
  555. *save = DIR_SEP_CHAR;
  556. ent = vfs_s_generate_entry (me, name, dir, 0755);
  557. ino = ent->ino;
  558. vfs_s_insert_entry(me, dir, ent);
  559. ino->localname = tempnam (NULL, me->name);
  560. was_changed = 1;
  561. }
  562. if (ino && S_ISDIR (ino->st.st_mode)) ERRNOR (EISDIR, NULL);
  563. fh = (struct vfs_s_fh *) xmalloc (sizeof (struct vfs_s_fh), "Direntry: filehandle");
  564. fh->pos = 0;
  565. fh->ino = ino;
  566. fh->handle = -1;
  567. fh->changed = was_changed;
  568. fh->linear = 0;
  569. if (MEDATA->fh_open)
  570. if (MEDATA->fh_open (me, fh, flags, mode)) {
  571. free(fh);
  572. return NULL;
  573. }
  574. if (fh->ino->localname) {
  575. fh->handle = open(fh->ino->localname, flags, mode);
  576. if (fh->handle == -1) {
  577. free(fh);
  578. ERRNOR(errno, NULL);
  579. }
  580. }
  581. /* i.e. we had no open files and now we have one */
  582. vfs_rmstamp (&vfs_tarfs_ops, (vfsid) super, 1);
  583. super->fd_usage++;
  584. fh->ino->st.st_nlink++;
  585. return fh;
  586. }
  587. int vfs_s_read (void *fh, char *buffer, int count)
  588. {
  589. int n;
  590. vfs *me = FH_SUPER->me;
  591. if (FH->linear == LS_LINEAR_CLOSED) {
  592. print_vfs_message ("Starting linear transfer...");
  593. if (!MEDATA->linear_start (me, FH, 0))
  594. return -1;
  595. }
  596. if (FH->linear == LS_LINEAR_CLOSED)
  597. vfs_die ("linear_start() did not set linear_state!");
  598. if (FH->linear == LS_LINEAR_OPEN)
  599. return MEDATA->linear_read (me, FH, buffer, count);
  600. if (FH->handle) {
  601. n = read (FH->handle, buffer, count);
  602. if (n < 0)
  603. me->verrno = errno;
  604. return n;
  605. }
  606. vfs_die( "vfs_s_read: This should not happen\n" );
  607. }
  608. int vfs_s_write (void *fh, char *buffer, int count)
  609. {
  610. int n;
  611. vfs *me = FH_SUPER->me;
  612. if (FH->linear)
  613. vfs_die ("no writing to linear files, please" );
  614. FH->changed = 1;
  615. if (FH->handle) {
  616. n = write (FH->handle, buffer, count);
  617. if (n < 0)
  618. me->verrno = errno;
  619. return n;
  620. }
  621. vfs_die( "vfs_s_write: This should not happen\n" );
  622. }
  623. int vfs_s_lseek (void *fh, off_t offset, int whence)
  624. {
  625. off_t size = FH->ino->st.st_size;
  626. if (FH->handle != -1) { /* If we have local file opened, we want to work with it */
  627. int retval = lseek(FH->handle, offset, whence);
  628. if (retval == -1)
  629. FH->ino->super->me->verrno = errno;
  630. return retval;
  631. }
  632. switch (whence) {
  633. case SEEK_CUR:
  634. offset += FH->pos; break;
  635. case SEEK_END:
  636. offset += size; break;
  637. }
  638. if (offset < 0)
  639. FH->pos = 0;
  640. else if (offset < size)
  641. FH->pos = offset;
  642. else
  643. FH->pos = size;
  644. return FH->pos;
  645. }
  646. int vfs_s_close (void *fh)
  647. {
  648. int res = 0;
  649. vfs *me = FH_SUPER->me;
  650. FH_SUPER->fd_usage--;
  651. if (!FH_SUPER->fd_usage) {
  652. struct vfs_stamping *parent;
  653. vfs *v;
  654. v = vfs_type (FH_SUPER->name);
  655. if (v == &vfs_local_ops) {
  656. parent = NULL;
  657. } else {
  658. parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
  659. parent->v = v;
  660. parent->next = 0;
  661. parent->id = (*v->getid) (v, FH_SUPER->name, &(parent->parent));
  662. }
  663. vfs_add_noncurrent_stamps (&vfs_tarfs_ops, (vfsid) (FH_SUPER), parent);
  664. vfs_rm_parents (parent);
  665. }
  666. if (FH->linear == LS_LINEAR_OPEN)
  667. MEDATA->linear_close (me, fh);
  668. if (MEDATA->fh_close)
  669. res = MEDATA->fh_close (me, fh);
  670. if (FH->changed && MEDATA->file_store) {
  671. char *s = vfs_s_fullpath( me, FH->ino );
  672. if (!s) res = -1;
  673. else res = MEDATA->file_store (me, FH_SUPER, s, FH->ino->localname);
  674. vfs_s_invalidate(me, FH_SUPER);
  675. }
  676. if (FH->handle)
  677. close(FH->handle);
  678. vfs_s_free_inode (me, FH->ino);
  679. free (fh);
  680. return res;
  681. }
  682. /* ------------------------------- mc support ---------------------------- */
  683. void vfs_s_fill_names (vfs *me, void (*func)(char *))
  684. {
  685. struct vfs_s_super *a = MEDATA->supers;
  686. char *name;
  687. while (a){
  688. name = copy_strings ( a->name, "#", me->prefix, "/",
  689. /* a->current_dir->name, */ 0);
  690. (*func)(name);
  691. free (name);
  692. a = a->next;
  693. }
  694. }
  695. int
  696. vfs_s_ferrno(vfs *me)
  697. {
  698. return me->verrno;
  699. }
  700. void
  701. vfs_s_dump(vfs *me, char *prefix, vfs_s_inode *ino)
  702. {
  703. printf( "%s %s %d ", prefix, S_ISDIR(ino->st.st_mode) ? "DIR" : "FILE", ino->st.st_mode );
  704. if (!ino->subdir) printf ("FILE\n");
  705. else
  706. {
  707. struct vfs_s_entry *ent;
  708. ent = ino->subdir;
  709. while(ent) {
  710. char *s;
  711. s = copy_strings(prefix, "/", ent->name, NULL );
  712. if (ent->name[0] == '.')
  713. printf("%s IGNORED\n", s);
  714. else
  715. vfs_s_dump(me, s, ent->ino);
  716. free(s);
  717. ent = ent->next;
  718. }
  719. }
  720. }
  721. char *vfs_s_getlocalcopy (vfs *me, char *path)
  722. {
  723. struct vfs_s_inode *ino;
  724. char buf[MC_MAXPATHLEN];
  725. strcpy( buf, path );
  726. ino = vfs_s_inode_from_path (me, path, FL_FOLLOW | FL_NONE);
  727. if (!ino->localname)
  728. ino->localname = mc_def_getlocalcopy (me, buf);
  729. return ino->localname;
  730. }
  731. int
  732. vfs_s_setctl (vfs *me, char *path, int ctlop, char *arg)
  733. {
  734. vfs_s_inode *ino = vfs_s_inode_from_path(me, path, 0);
  735. if (!ino)
  736. return 0;
  737. switch (ctlop) {
  738. case MCCTL_WANT_STALE_DATA:
  739. #warning Should se this to 1
  740. ino->super->want_stale = 0;
  741. return 1;
  742. case MCCTL_NO_STALE_DATA:
  743. ino->super->want_stale = 0;
  744. vfs_s_invalidate(me, ino->super);
  745. return 1;
  746. #if 0 /* FIXME: We should implement these */
  747. case MCCTL_REMOVELOCALCOPY:
  748. return remove_temp_file (path);
  749. case MCCTL_FORGET_ABOUT:
  750. my_forget(path);
  751. return 0;
  752. #endif
  753. }
  754. return 0;
  755. }
  756. /* ----------------------------- Stamping support -------------------------- */
  757. vfsid vfs_s_getid (vfs *me, char *path, struct vfs_stamping **parent)
  758. {
  759. vfs_s_super *archive;
  760. vfs *v;
  761. char *p;
  762. vfsid id;
  763. struct vfs_stamping *par;
  764. *parent = NULL;
  765. if (!(p = vfs_s_get_path (me, path, &archive, FL_NO_OPEN)))
  766. return (vfsid) -1;
  767. free(p);
  768. v = vfs_type (archive->name);
  769. id = (*v->getid) (v, archive->name, &par);
  770. if (id != (vfsid)-1) {
  771. *parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
  772. (*parent)->v = v;
  773. (*parent)->id = id;
  774. (*parent)->parent = par;
  775. (*parent)->next = NULL;
  776. }
  777. return (vfsid) archive;
  778. }
  779. int vfs_s_nothingisopen (vfsid id)
  780. {
  781. if (((vfs_s_super *)id)->fd_usage <= 0)
  782. return 1;
  783. else
  784. return 0;
  785. }
  786. void vfs_s_free (vfsid id)
  787. {
  788. vfs_s_free_super (((vfs_s_super *)id)->me, (vfs_s_super *)id);
  789. }
  790. /* ----------- Utility functions for networked filesystems -------------- */
  791. int
  792. vfs_s_select_on_two (int fd1, int fd2)
  793. {
  794. fd_set set;
  795. struct timeval timeout;
  796. int v;
  797. int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
  798. timeout.tv_sec = 1;
  799. timeout.tv_usec = 0;
  800. FD_ZERO(&set);
  801. FD_SET(fd1, &set);
  802. FD_SET(fd2, &set);
  803. v = select (maxfd, &set, 0, 0, &timeout);
  804. if (v <= 0)
  805. return v;
  806. if (FD_ISSET (fd1, &set))
  807. return 1;
  808. if (FD_ISSET (fd2, &set))
  809. return 2;
  810. return -1;
  811. }
  812. int
  813. vfs_s_get_line (vfs *me, int sock, char *buf, int buf_len, char term)
  814. {
  815. FILE *logfile = MEDATA->logfile;
  816. int i, status;
  817. char c;
  818. for (i = 0; i < buf_len; i++, buf++) {
  819. if (read(sock, buf, sizeof(char)) <= 0)
  820. return 0;
  821. if (logfile){
  822. fwrite (buf, 1, 1, logfile);
  823. fflush (logfile);
  824. }
  825. if (*buf == term) {
  826. *buf = 0;
  827. return 1;
  828. }
  829. }
  830. *buf = 0;
  831. while ((status = read(sock, &c, sizeof(c))) > 0){
  832. if (logfile){
  833. fwrite (&c, 1, 1, logfile);
  834. fflush (logfile);
  835. }
  836. if (c == '\n')
  837. return 1;
  838. }
  839. return 0;
  840. }
  841. int
  842. vfs_s_get_line_interruptible (vfs *me, char *buffer, int size, int fd)
  843. {
  844. int n;
  845. int i = 0;
  846. enable_interrupt_key();
  847. for (i = 0; i < size-1; i++) {
  848. n = read (fd, buffer+i, 1);
  849. disable_interrupt_key();
  850. if (n == -1 && errno == EINTR){
  851. buffer [i] = 0;
  852. return EINTR;
  853. }
  854. if (n == 0){
  855. buffer [i] = 0;
  856. return 0;
  857. }
  858. if (buffer [i] == '\n'){
  859. buffer [i] = 0;
  860. return 1;
  861. }
  862. }
  863. buffer [size-1] = 0;
  864. return 0;
  865. }