dir.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:20k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/umsdos/dir.c
  3.  *
  4.  *  Written 1993 by Jacques Gelinas
  5.  *      Inspired from linux/fs/msdos/... : Werner Almesberger
  6.  *
  7.  *  Extended MS-DOS directory handling functions
  8.  */
  9. #include <linux/sched.h>
  10. #include <linux/string.h>
  11. #include <linux/fs.h>
  12. #include <linux/msdos_fs.h>
  13. #include <linux/errno.h>
  14. #include <linux/stat.h>
  15. #include <linux/limits.h>
  16. #include <linux/umsdos_fs.h>
  17. #include <linux/slab.h>
  18. #include <linux/pagemap.h>
  19. #define UMSDOS_SPECIAL_DIRFPOS 3
  20. extern struct dentry *saved_root;
  21. extern struct inode *pseudo_root;
  22. /* #define UMSDOS_DEBUG_VERBOSE 1 */
  23. /*
  24.  * Dentry operations routines
  25.  */
  26. /* nothing for now ... */
  27. static int umsdos_dentry_validate(struct dentry *dentry, int flags)
  28. {
  29. return 1;
  30. }
  31. /* for now, drop everything to force lookups ... */
  32. /* ITYM s/everything/& positive/... */
  33. static int umsdos_dentry_dput(struct dentry *dentry)
  34. {
  35. struct inode *inode = dentry->d_inode;
  36. if (inode) {
  37. return 1;
  38. }
  39. return 0;
  40. }
  41. struct dentry_operations umsdos_dentry_operations =
  42. {
  43. d_revalidate: umsdos_dentry_validate,
  44. d_delete: umsdos_dentry_dput,
  45. };
  46. struct UMSDOS_DIR_ONCE {
  47. void *dirbuf;
  48. filldir_t filldir;
  49. int count;
  50. int stop;
  51. };
  52. /*
  53.  * Record a single entry the first call.
  54.  * Return -EINVAL the next one.
  55.  * NOTE: filldir DOES NOT use a dentry
  56.  */
  57. static int umsdos_dir_once ( void *buf,
  58. const char *name,
  59. int len,
  60. loff_t offset,
  61. ino_t ino,
  62. unsigned type)
  63. {
  64. int ret = -EINVAL;
  65. struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
  66. if (d->count == 0) {
  67. PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ldn", 
  68. len, name, offset));
  69. ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);
  70. d->stop = ret < 0;
  71. d->count = 1;
  72. }
  73. return ret;
  74. }
  75. /*
  76.  * Read count directory entries from directory filp
  77.  * Return a negative value from linux/errno.h.
  78.  * Return > 0 if success (the number of bytes written by filldir).
  79.  * 
  80.  * This function is used by the normal readdir VFS entry point,
  81.  * and in order to get the directory entry from a file's dentry.
  82.  * See umsdos_dentry_to_entry() below.
  83.  */
  84.  
  85. static int umsdos_readdir_x (struct inode *dir, struct file *filp,
  86. void *dirbuf, struct umsdos_dirent *u_entry,
  87. filldir_t filldir)
  88. {
  89. struct dentry *demd;
  90. off_t start_fpos;
  91. int ret = 0;
  92. loff_t pos;
  93. umsdos_startlookup (dir);
  94. if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) {
  95. /*
  96.  * We don't need to simulate this pseudo directory
  97.  * when umsdos_readdir_x is called for internal operation
  98.  * of umsdos. This is why dirent_in_fs is tested
  99.  */
  100. /* #Specification: pseudo root / directory /DOS
  101.  * When umsdos operates in pseudo root mode (C:linux is the
  102.  * linux root), it simulate a directory /DOS which points to
  103.  * the real root of the file system.
  104.  */
  105. Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOSn"));
  106. if (filldir (dirbuf, "DOS", 3, 
  107. UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) {
  108. filp->f_pos++;
  109. }
  110. goto out_end;
  111. }
  112. if (filp->f_pos < 2 || 
  113.     (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
  114. int last_f_pos = filp->f_pos;
  115. struct UMSDOS_DIR_ONCE bufk;
  116. Printk (("umsdos_readdir_x: . or .. /mn/?n"));
  117. bufk.dirbuf = dirbuf;
  118. bufk.filldir = filldir;
  119. bufk.count = 0;
  120. ret = fat_readdir (filp, &bufk, umsdos_dir_once);
  121. if (last_f_pos > 0 && filp->f_pos > last_f_pos)
  122. filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
  123. if (u_entry != NULL)
  124. u_entry->flags = 0;
  125. goto out_end;
  126. }
  127. Printk (("umsdos_readdir_x: normal file /mn/?n"));
  128. /* get the EMD dentry */
  129. demd = umsdos_get_emd_dentry(filp->f_dentry);
  130. ret = PTR_ERR(demd);
  131. if (IS_ERR(demd))
  132. goto out_end;
  133. ret = -EIO;
  134. if (!demd->d_inode) {
  135. printk(KERN_WARNING 
  136. "umsdos_readir_x: EMD file %s/%s not foundn",
  137. demd->d_parent->d_name.name, demd->d_name.name);
  138. goto out_dput;
  139. }
  140. pos = filp->f_pos;
  141. start_fpos = filp->f_pos;
  142. if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
  143. pos = 0;
  144. ret = 0;
  145. while (pos < demd->d_inode->i_size) {
  146. off_t cur_f_pos = pos;
  147. struct dentry *dret;
  148. struct inode *inode;
  149. struct umsdos_dirent entry;
  150. struct umsdos_info info;
  151. ret = -EIO;
  152. if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0)
  153. break;
  154. if (entry.name_len == 0)
  155. continue;
  156. #ifdef UMSDOS_DEBUG_VERBOSE
  157. if (entry.flags & UMSDOS_HLINK)
  158. printk("umsdos_readdir_x: %s/%s is hardlinkn",
  159. filp->f_dentry->d_name.name, entry.name);
  160. #endif
  161. umsdos_parse (entry.name, entry.name_len, &info);
  162. info.f_pos = cur_f_pos;
  163. umsdos_manglename (&info);
  164. /*
  165.  * Do a real lookup on the short name.
  166.  */
  167. dret = umsdos_covered(filp->f_dentry, info.fake.fname,
  168.  info.fake.len);
  169. ret = PTR_ERR(dret);
  170. if (IS_ERR(dret))
  171. break;
  172. /*
  173.  * If the file wasn't found, remove it from the EMD.
  174.  */
  175. inode = dret->d_inode;
  176. if (!inode)
  177. goto remove_name;
  178. #ifdef UMSDOS_DEBUG_VERBOSE
  179. if (inode->u.umsdos_i.i_is_hlink)
  180. printk("umsdos_readdir_x: %s/%s already resolved, ino=%ldn",
  181. dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
  182. #endif
  183. Printk (("Found %s/%s, ino=%ld, flags=%xn",
  184. dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
  185. entry.flags));
  186. /* check whether to resolve a hard-link */
  187. if ((entry.flags & UMSDOS_HLINK) &&
  188.     !inode->u.umsdos_i.i_is_hlink) {
  189. dret = umsdos_solve_hlink (dret);
  190. ret = PTR_ERR(dret);
  191. if (IS_ERR(dret))
  192. break;
  193. inode = dret->d_inode;
  194. if (!inode) {
  195. printk("umsdos_readdir_x: %s/%s negative after linkn",
  196. dret->d_parent->d_name.name, dret->d_name.name);
  197. goto clean_up;
  198. }
  199. }
  200. /* #Specification:  pseudo root / reading real root
  201.  * The pseudo root (/linux) is logically
  202.  * erased from the real root.  This means that
  203.  * ls /DOS, won't show "linux". This avoids
  204.  * infinite recursion (/DOS/linux/DOS/linux/...) while
  205.  * walking the file system.
  206.  */
  207. if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) {
  208. if (filldir (dirbuf, entry.name, entry.name_len,
  209.  cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {
  210. pos = cur_f_pos;
  211. }
  212. Printk(("umsdos_readdir_x: got %s/%s, ino=%ldn",
  213. dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));
  214. if (u_entry != NULL)
  215. *u_entry = entry;
  216. dput(dret);
  217. ret = 0;
  218. break;
  219. }
  220. clean_up:
  221. dput(dret);
  222. continue;
  223. remove_name:
  224. /* #Specification:  umsdos / readdir / not in MSDOS
  225.  * During a readdir operation, if the file is not
  226.  * in the MS-DOS directory any more, the entry is
  227.  * removed from the EMD file silently.
  228.  */
  229. #ifdef UMSDOS_PARANOIA
  230. printk("umsdos_readdir_x: %s/%s out of sync, erasingn",
  231. filp->f_dentry->d_name.name, info.entry.name);
  232. #endif
  233. ret = umsdos_delentry(filp->f_dentry, &info, 
  234. S_ISDIR(info.entry.mode));
  235. if (ret)
  236. printk(KERN_WARNING 
  237. "umsdos_readdir_x: delentry %s, err=%dn",
  238. info.entry.name, ret);
  239. goto clean_up;
  240. }
  241. /*
  242.  * If the fillbuf has failed, f_pos is back to 0.
  243.  * To avoid getting back into the . and .. state
  244.  * (see comments at the beginning), we put back
  245.  * the special offset.
  246.  */
  247. filp->f_pos = pos;
  248. if (filp->f_pos == 0)
  249. filp->f_pos = start_fpos;
  250. out_dput:
  251. dput(demd);
  252. out_end:
  253. umsdos_endlookup (dir);
  254. Printk ((KERN_DEBUG "read dir %p pos %Ld ret %dn",
  255. dir, filp->f_pos, ret));
  256. return ret;
  257. }
  258. /*
  259.  * Read count directory entries from directory filp.
  260.  * Return a negative value from linux/errno.h.
  261.  * Return 0 or positive if successful.
  262.  */
  263.  
  264. static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
  265. {
  266. struct inode *dir = filp->f_dentry->d_inode;
  267. int ret = 0, count = 0;
  268. struct UMSDOS_DIR_ONCE bufk;
  269. bufk.dirbuf = dirbuf;
  270. bufk.filldir = filldir;
  271. bufk.stop = 0;
  272. Printk (("UMSDOS_readdir inn"));
  273. while (ret == 0 && bufk.stop == 0) {
  274. struct umsdos_dirent entry;
  275. bufk.count = 0;
  276. ret = umsdos_readdir_x (dir, filp, &bufk, &entry, 
  277. umsdos_dir_once);
  278. if (bufk.count == 0)
  279. break;
  280. count += bufk.count;
  281. }
  282. Printk (("UMSDOS_readdir out %d count %d pos %Ldn", 
  283. ret, count, filp->f_pos));
  284. return count ? : ret;
  285. }
  286. /*
  287.  * Complete the inode content with info from the EMD file.
  288.  *
  289.  * This function modifies the state of a dir inode.  It decides
  290.  * whether the dir is a UMSDOS or DOS directory.  This is done
  291.  * deeper in umsdos_patch_inode() called at the end of this function.
  292.  * 
  293.  * Because it is does disk access, umsdos_patch_inode() may block.
  294.  * At the same time, another process may get here to initialise
  295.  * the same directory inode. There are three cases.
  296.  * 
  297.  * 1) The inode is already initialised.  We do nothing.
  298.  * 2) The inode is not initialised.  We lock access and do it.
  299.  * 3) Like 2 but another process has locked the inode, so we try
  300.  * to lock it and check right afterward check whether
  301.  * initialisation is still needed.
  302.  * 
  303.  * 
  304.  * Thanks to the "mem" option of the kernel command line, it was
  305.  * possible to consistently reproduce this problem by limiting
  306.  * my memory to 4 MB and running X.
  307.  *
  308.  * Do this only if the inode is freshly read, because we will lose
  309.  * the current (updated) content.
  310.  *
  311.  * A lookup of a mount point directory yield the inode into
  312.  * the other fs, so we don't care about initialising it. iget()
  313.  * does this automatically.
  314.  */
  315. void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
  316. {
  317. struct inode *inode = dentry->d_inode;
  318. struct umsdos_dirent *entry = &info->entry;
  319. /*
  320.  * This part of the initialization depends only on i_patched.
  321.  */
  322. if (inode->u.umsdos_i.i_patched)
  323. goto out;
  324. inode->u.umsdos_i.i_patched = 1;
  325. if (S_ISREG (entry->mode))
  326. entry->mtime = inode->i_mtime;
  327. inode->i_mode = entry->mode;
  328. inode->i_rdev = to_kdev_t (entry->rdev);
  329. inode->i_atime = entry->atime;
  330. inode->i_ctime = entry->ctime;
  331. inode->i_mtime = entry->mtime;
  332. inode->i_uid = entry->uid;
  333. inode->i_gid = entry->gid;
  334. /* #Specification: umsdos / i_nlink
  335.  * The nlink field of an inode is maintained by the MSDOS file system
  336.  * for directory and by UMSDOS for other files.  The logic is that
  337.  * MSDOS is already figuring out what to do for directories and
  338.  * does nothing for other files.  For MSDOS, there are no hard links
  339.  * so all file carry nlink==1.  UMSDOS use some info in the
  340.  * EMD file to plug the correct value.
  341.  */
  342. if (!S_ISDIR (entry->mode)) {
  343. if (entry->nlink > 0) {
  344. inode->i_nlink = entry->nlink;
  345. } else {
  346. printk (KERN_ERR 
  347. "UMSDOS:  lookup_patch entry->nlink < 1 ???n");
  348. }
  349. }
  350. /*
  351.  * The mode may have changed, so patch the inode again.
  352.  */
  353. umsdos_patch_dentry_inode(dentry, info->f_pos);
  354. umsdos_set_dirinfo_new(dentry, info->f_pos);
  355. out:
  356. return;
  357. }
  358. /*
  359.  * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
  360.  */
  361. int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
  362. {
  363. /* #Specification: pseudo root / DOS hard coded
  364.  * The pseudo sub-directory DOS in the pseudo root is hard coded.
  365.  * The name is DOS. This is done this way to help standardised
  366.  * the umsdos layout. The idea is that from now on /DOS is
  367.  * a reserved path and nobody will think of using such a path
  368.  * for a package.
  369.  */
  370. return dir == pseudo_root
  371.     && dentry->d_name.len == 3
  372.     && dentry->d_name.name[0] == 'D'
  373.     && dentry->d_name.name[1] == 'O'
  374.     && dentry->d_name.name[2] == 'S';
  375. }
  376. /*
  377.  * Check whether a file exists in the current directory.
  378.  * Return 0 if OK, negative error code if not (ex: -ENOENT).
  379.  *
  380.  * fills dentry->d_inode with found inode, and increments its count.
  381.  * if not found, return -ENOENT.
  382.  */
  383. /* #Specification: umsdos / lookup
  384.  * A lookup for a file is done in two steps.  First, we
  385.  * locate the file in the EMD file.  If not present, we
  386.  * return an error code (-ENOENT).  If it is there, we
  387.  * repeat the operation on the msdos file system. If
  388.  * this fails, it means that the file system is not in
  389.  * sync with the EMD file.   We silently remove this
  390.  * entry from the EMD file, and return ENOENT.
  391.  */
  392. struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
  393. {
  394. struct dentry *dret = NULL;
  395. struct inode *inode;
  396. int ret = -ENOENT;
  397. struct umsdos_info info;
  398. #ifdef UMSDOS_DEBUG_VERBOSE
  399. printk("umsdos_lookup_x: looking for %s/%sn", 
  400. dentry->d_parent->d_name.name, dentry->d_name.name);
  401. #endif
  402. umsdos_startlookup (dir);
  403. if (umsdos_is_pseudodos (dir, dentry)) {
  404. /* #Specification: pseudo root / lookup(DOS)
  405.  * A lookup of DOS in the pseudo root will always succeed
  406.  * and return the inode of the real root.
  407.  */
  408. Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOSn"));
  409. inode = saved_root->d_inode;
  410. goto out_add;
  411. }
  412. ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  413. if (ret) {
  414. printk("umsdos_lookup_x: %s/%s parse failed, ret=%dn", 
  415. dentry->d_parent->d_name.name, dentry->d_name.name, ret);
  416. goto out;
  417. }
  418. ret = umsdos_findentry (dentry->d_parent, &info, 0);
  419. if (ret) {
  420. if (ret != -ENOENT)
  421. printk("umsdos_lookup_x: %s/%s findentry failed, ret=%dn", 
  422. dentry->d_parent->d_name.name, dentry->d_name.name, ret);
  423. goto out;
  424. }
  425. Printk (("lookup %.*s pos %lu ret %d len %d ", 
  426. info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
  427. /* do a real lookup to get the short name ... */
  428. dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  429. ret = PTR_ERR(dret);
  430. if (IS_ERR(dret)) {
  431. printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%dn", 
  432. dentry->d_parent->d_name.name, dentry->d_name.name, ret);
  433. goto out;
  434. }
  435. inode = dret->d_inode;
  436. if (!inode)
  437. goto out_remove;
  438. umsdos_lookup_patch_new(dret, &info);
  439. #ifdef UMSDOS_DEBUG_VERBOSE
  440. printk("umsdos_lookup_x: found %s/%s, ino=%ldn", 
  441. dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
  442. #endif
  443. /* Check for a hard link */
  444. if ((info.entry.flags & UMSDOS_HLINK) &&
  445.     !inode->u.umsdos_i.i_is_hlink) {
  446. dret = umsdos_solve_hlink (dret);
  447. ret = PTR_ERR(dret);
  448. if (IS_ERR(dret))
  449. goto out;
  450. ret = -ENOENT;
  451. inode = dret->d_inode;
  452. if (!inode) {
  453. printk("umsdos_lookup_x: %s/%s negative after linkn", 
  454. dret->d_parent->d_name.name, dret->d_name.name);
  455. goto out_dput;
  456. }
  457. }
  458. if (inode == pseudo_root && !nopseudo) {
  459. /* #Specification: pseudo root / dir lookup
  460.  * For the same reason as readdir, a lookup in /DOS for
  461.  * the pseudo root directory (linux) will fail.
  462.  */
  463. /*
  464.  * This has to be allowed for resolving hard links
  465.  * which are recorded independently of the pseudo-root
  466.  * mode.
  467.  */
  468. printk("umsdos_lookup_x: skipping DOS/linuxn");
  469. ret = -ENOENT;
  470. goto out_dput;
  471. }
  472. /*
  473.  * We've found it OK.  Now hash the dentry with the inode.
  474.  */
  475. out_add:
  476. atomic_inc(&inode->i_count);
  477. d_add (dentry, inode);
  478. dentry->d_op = &umsdos_dentry_operations;
  479. ret = 0;
  480. out_dput:
  481. if (dret && dret != dentry)
  482. d_drop(dret);
  483. dput(dret);
  484. out:
  485. umsdos_endlookup (dir);
  486. return ERR_PTR(ret);
  487. out_remove:
  488. printk(KERN_WARNING "UMSDOS:  entry %s/%s out of sync, erasedn",
  489. dentry->d_parent->d_name.name, dentry->d_name.name);
  490. umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
  491. ret = -ENOENT;
  492. goto out_dput;
  493. }
  494. /*
  495.  * Check whether a file exists in the current directory.
  496.  * Return 0 if OK, negative error code if not (ex: -ENOENT).
  497.  * 
  498.  * Called by VFS; should fill dentry->d_inode via d_add.
  499.  */
  500. struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
  501. {
  502. struct dentry *ret;
  503. ret = umsdos_lookup_x (dir, dentry, 0);
  504. /* Create negative dentry if not found. */
  505. if (ret == ERR_PTR(-ENOENT)) {
  506. Printk ((KERN_DEBUG 
  507. "UMSDOS_lookup: converting -ENOENT to negativen"));
  508. d_add (dentry, NULL);
  509. dentry->d_op = &umsdos_dentry_operations;
  510. ret = NULL;
  511. }
  512. return ret;
  513. }
  514. struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
  515. {
  516. struct dentry *result, *dentry;
  517. struct qstr qstr;
  518. qstr.name = name;
  519. qstr.len  = len;
  520. qstr.hash = full_name_hash(name, len);
  521. result = ERR_PTR(-ENOMEM);
  522. dentry = d_alloc(parent, &qstr);
  523. if (dentry) {
  524. /* XXXXXXXXXXXXXXXXXXX Race alert! */
  525. result = UMSDOS_rlookup(parent->d_inode, dentry);
  526. d_drop(dentry);
  527. if (result)
  528. goto out_fail;
  529. return dentry;
  530. }
  531. out:
  532. return result;
  533. out_fail:
  534. dput(dentry);
  535. goto out;
  536. }
  537. /*
  538.  * Lookup or create a dentry from within the filesystem.
  539.  *
  540.  * We need to use this instead of lookup_dentry, as the 
  541.  * directory semaphore lock is already held.
  542.  */
  543. struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
  544. int real)
  545. {
  546. struct dentry *result, *dentry;
  547. struct qstr qstr;
  548. qstr.name = name;
  549. qstr.len  = len;
  550. qstr.hash = full_name_hash(name, len);
  551. result = d_lookup(parent, &qstr);
  552. if (!result) {
  553. result = ERR_PTR(-ENOMEM);
  554. dentry = d_alloc(parent, &qstr);
  555. if (dentry) {
  556. result = real ?
  557. UMSDOS_rlookup(parent->d_inode, dentry) :
  558. UMSDOS_lookup(parent->d_inode, dentry);
  559. if (result)
  560. goto out_fail;
  561. return dentry;
  562. }
  563. }
  564. out:
  565. return result;
  566. out_fail:
  567. dput(dentry);
  568. goto out;
  569. }
  570. /*
  571.  * Return a path relative to our root.
  572.  */
  573. char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
  574. {
  575. struct dentry * old_root;
  576. char * path;
  577. read_lock(&current->fs->lock);
  578. old_root = dget(current->fs->root);
  579. read_unlock(&current->fs->lock);
  580. spin_lock(&dcache_lock);
  581. path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */
  582. spin_unlock(&dcache_lock);
  583. if (*path == '/')
  584. path++; /* skip leading '/' */
  585. if (current->fs->root->d_inode == pseudo_root)
  586. {
  587. *(path-1) = '/';
  588. path -= (UMSDOS_PSDROOT_LEN+1);
  589. memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
  590. }
  591. dput(old_root);
  592. return path;
  593. }
  594. /*
  595.  * Return the dentry which points to a pseudo-hardlink.
  596.  *
  597.  * it should try to find file it points to
  598.  * if file is found, return new dentry/inode
  599.  * The resolved inode will have i_is_hlink set.
  600.  *
  601.  * Note: the original dentry is always dput(), even if an error occurs.
  602.  */
  603. struct dentry *umsdos_solve_hlink (struct dentry *hlink)
  604. {
  605. /* root is our root for resolving pseudo-hardlink */
  606. struct dentry *base = hlink->d_sb->s_root;
  607. struct dentry *dentry_dst;
  608. char *path, *pt;
  609. int len;
  610. struct address_space *mapping = hlink->d_inode->i_mapping;
  611. struct page *page;
  612. page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL);
  613. dentry_dst=(struct dentry *)page;
  614. if (IS_ERR(page))
  615. goto out;
  616. wait_on_page(page);
  617. if (!Page_Uptodate(page))
  618. goto async_fail;
  619. dentry_dst = ERR_PTR(-ENOMEM);
  620. path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
  621. if (path == NULL)
  622. goto out_release;
  623. memcpy(path, kmap(page), hlink->d_inode->i_size);
  624. kunmap(page);
  625. page_cache_release(page);
  626. len = hlink->d_inode->i_size;
  627. /* start at root dentry */
  628. dentry_dst = dget(base);
  629. path[len] = '';
  630. pt = path;
  631. if (*path == '/')
  632. pt++; /* skip leading '/' */
  633. if (base->d_inode == pseudo_root)
  634. pt += (UMSDOS_PSDROOT_LEN + 1);
  635. while (1) {
  636. struct dentry *dir = dentry_dst, *demd;
  637. char *start = pt;
  638. int real;
  639. while (*pt != '' && *pt != '/') pt++;
  640. len = (int) (pt - start);
  641. if (*pt == '/') *pt++ = '';
  642. real = 1;
  643. demd = umsdos_get_emd_dentry(dir);
  644. if (!IS_ERR(demd)) {
  645. if (demd->d_inode)
  646. real = 0;
  647. dput(demd);
  648. }
  649. #ifdef UMSDOS_DEBUG_VERBOSE
  650. printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%dn",
  651. dir->d_parent->d_name.name, dir->d_name.name, start, real);
  652. #endif
  653. dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
  654. /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
  655. if (real)
  656. d_drop(dir);
  657. dput (dir);
  658. if (IS_ERR(dentry_dst))
  659. break;
  660. /* not found? stop search ... */
  661. if (!dentry_dst->d_inode) {
  662. break;
  663. }
  664. if (*pt == '') /* we're finished! */
  665. break;
  666. } /* end while */
  667. if (!IS_ERR(dentry_dst)) {
  668. struct inode *inode = dentry_dst->d_inode;
  669. if (inode) {
  670. inode->u.umsdos_i.i_is_hlink = 1;
  671. #ifdef UMSDOS_DEBUG_VERBOSE
  672. printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ldn",
  673. dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
  674. #endif
  675. } else {
  676. #ifdef UMSDOS_DEBUG_VERBOSE
  677. printk ("umsdos_solve_hlink: resolved link %s/%s negative!n",
  678. dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name);
  679. #endif
  680. }
  681. } else
  682. printk(KERN_WARNING
  683. "umsdos_solve_hlink: err=%ldn", PTR_ERR(dentry_dst));
  684. kfree (path);
  685. out:
  686. dput(hlink); /* original hlink no longer needed */
  687. return dentry_dst;
  688. async_fail:
  689. dentry_dst = ERR_PTR(-EIO);
  690. out_release:
  691. page_cache_release(page);
  692. goto out;
  693. }
  694. struct file_operations umsdos_dir_operations =
  695. {
  696. read: generic_read_dir,
  697. readdir: UMSDOS_readdir,
  698. ioctl: UMSDOS_ioctl_dir,
  699. };
  700. struct inode_operations umsdos_dir_inode_operations =
  701. {
  702. create: UMSDOS_create,
  703. lookup: UMSDOS_lookup,
  704. link: UMSDOS_link,
  705. unlink: UMSDOS_unlink,
  706. symlink: UMSDOS_symlink,
  707. mkdir: UMSDOS_mkdir,
  708. rmdir: UMSDOS_rmdir,
  709. mknod: UMSDOS_mknod,
  710. rename: UMSDOS_rename,
  711. setattr: UMSDOS_notify_change,
  712. };