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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/hpfs/dir.c
  3.  *
  4.  *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
  5.  *
  6.  *  directory VFS functions
  7.  */
  8. #include "hpfs_fn.h"
  9. #include <linux/sched.h>
  10. #include <linux/smp_lock.h>
  11. int hpfs_dir_release(struct inode *inode, struct file *filp)
  12. {
  13. lock_kernel();
  14. hpfs_del_pos(inode, &filp->f_pos);
  15. /*hpfs_write_if_changed(inode);*/
  16. unlock_kernel();
  17. return 0;
  18. }
  19. /* This is slow, but it's not used often */
  20. loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
  21. {
  22. loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
  23. loff_t pos;
  24. struct quad_buffer_head qbh;
  25. struct inode *i = filp->f_dentry->d_inode;
  26. struct super_block *s = i->i_sb;
  27. /*printk("dir lseekn");*/
  28. if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
  29. hpfs_lock_inode(i);
  30. pos = ((loff_t) hpfs_de_as_down_as_possible(s, i->i_hpfs_dno) << 4) + 1;
  31. while (pos != new_off) {
  32. if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
  33. else goto fail;
  34. if (pos == 12) goto fail;
  35. }
  36. hpfs_unlock_inode(i);
  37. ok:
  38. return filp->f_pos = new_off;
  39. fail:
  40. hpfs_unlock_inode(i);
  41. /*printk("illegal lseek: %016llxn", new_off);*/
  42. return -ESPIPE;
  43. }
  44. int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  45. {
  46. struct inode *inode = filp->f_dentry->d_inode;
  47. struct quad_buffer_head qbh;
  48. struct hpfs_dirent *de;
  49. int lc;
  50. long old_pos;
  51. char *tempname;
  52. int c1, c2 = 0;
  53. if (inode->i_sb->s_hpfs_chk) {
  54. if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
  55. return -EFSERROR;
  56. if (hpfs_chk_sectors(inode->i_sb, inode->i_hpfs_dno, 4, "dir_dnode"))
  57. return -EFSERROR;
  58. }
  59. if (inode->i_sb->s_hpfs_chk >= 2) {
  60. struct buffer_head *bh;
  61. struct fnode *fno;
  62. int e = 0;
  63. if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh)))
  64. return -EIOERROR;
  65. if (!fno->dirflag) {
  66. e = 1;
  67. hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino);
  68. }
  69. if (inode->i_hpfs_dno != fno->u.external[0].disk_secno) {
  70. e = 1;
  71. hpfs_error(inode->i_sb, "corrupted inode: i_hpfs_dno == %08x, fnode -> dnode == %08x", inode->i_hpfs_dno, fno->u.external[0].disk_secno);
  72. }
  73. brelse(bh);
  74. if (e) return -EFSERROR;
  75. }
  76. lc = inode->i_sb->s_hpfs_lowercase;
  77. if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */
  78. filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */
  79. return 0;
  80. }
  81. if (filp->f_pos == 13) return -ENOENT;
  82. hpfs_lock_inode(inode);
  83. while (1) {
  84. again:
  85. /* This won't work when cycle is longer than number of dirents
  86.    accepted by filldir, but what can I do?
  87.    maybe killall -9 ls helps */
  88. if (inode->i_sb->s_hpfs_chk)
  89. if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
  90. hpfs_unlock_inode(inode);
  91. return -EFSERROR;
  92. }
  93. if (filp->f_pos == 12) {
  94. hpfs_unlock_inode(inode);
  95. return 0;
  96. }
  97. if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
  98. printk("HPFS: warning: pos==%dn",(int)filp->f_pos);
  99. hpfs_unlock_inode(inode);
  100. return 0;
  101. }
  102. if (filp->f_pos == 0) {
  103. if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
  104. hpfs_unlock_inode(inode);
  105. return 0;
  106. }
  107. filp->f_pos = 11;
  108. }
  109. if (filp->f_pos == 11) {
  110. if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir, DT_DIR) < 0) {
  111. hpfs_unlock_inode(inode);
  112. return 0;
  113. }
  114. filp->f_pos = 1;
  115. }
  116. if (filp->f_pos == 1) {
  117. filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, inode->i_hpfs_dno) << 4) + 1;
  118. hpfs_add_pos(inode, &filp->f_pos);
  119. filp->f_version = inode->i_version;
  120. }
  121. /*if (filp->f_version != inode->i_version) {
  122. hpfs_unlock_inode(inode);
  123. return -ENOENT;
  124. }*/
  125. old_pos = filp->f_pos;
  126. if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
  127. hpfs_unlock_inode(inode);
  128. return -EIOERROR;
  129. }
  130. if (de->first || de->last) {
  131. if (inode->i_sb->s_hpfs_chk) {
  132. if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08x", old_pos);
  133. if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \377 entry; pos = %08x", old_pos);
  134. }
  135. hpfs_brelse4(&qbh);
  136. goto again;
  137. }
  138. tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
  139. if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) {
  140. filp->f_pos = old_pos;
  141. if (tempname != (char *)de->name) kfree(tempname);
  142. hpfs_brelse4(&qbh);
  143. hpfs_unlock_inode(inode);
  144. return 0;
  145. }
  146. if (tempname != (char *)de->name) kfree(tempname);
  147. hpfs_brelse4(&qbh);
  148. }
  149. }
  150. /*
  151.  * lookup.  Search the specified directory for the specified name, set
  152.  * *result to the corresponding inode.
  153.  *
  154.  * lookup uses the inode number to tell read_inode whether it is reading
  155.  * the inode of a directory or a file -- file ino's are odd, directory
  156.  * ino's are even.  read_inode avoids i/o for file inodes; everything
  157.  * needed is up here in the directory.  (And file fnodes are out in
  158.  * the boondocks.)
  159.  *
  160.  *    - M.P.: this is over, sometimes we've got to read file's fnode for eas
  161.  *       inode numbers are just fnode sector numbers; iget lock is used
  162.  *       to tell read_inode to read fnode or not.
  163.  */
  164. struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
  165. {
  166. const char *name = dentry->d_name.name;
  167. unsigned len = dentry->d_name.len;
  168. struct quad_buffer_head qbh;
  169. struct hpfs_dirent *de;
  170. ino_t ino;
  171. int err;
  172. struct inode *result = NULL;
  173. if ((err = hpfs_chk_name((char *)name, &len))) {
  174. if (err == -ENAMETOOLONG) return ERR_PTR(-ENAMETOOLONG);
  175. goto end_add;
  176. }
  177. hpfs_lock_inode(dir);
  178. /*
  179.  * '.' and '..' will never be passed here.
  180.  */
  181. de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh);
  182. /*
  183.  * This is not really a bailout, just means file not found.
  184.  */
  185. if (!de) goto end;
  186. /*
  187.  * Get inode number, what we're after.
  188.  */
  189. ino = de->fnode;
  190. /*
  191.  * Go find or make an inode.
  192.  */
  193. hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && dir->i_sb->s_hpfs_eas) ? 1 : 2);
  194. if (!(result = iget(dir->i_sb, ino))) {
  195. hpfs_unlock_iget(dir->i_sb);
  196. hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
  197. goto bail1;
  198. }
  199. if (!de->directory) result->i_hpfs_parent_dir = dir->i_ino;
  200. hpfs_unlock_iget(dir->i_sb);
  201. hpfs_decide_conv(result, (char *)name, len);
  202. if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
  203. hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
  204. goto bail1;
  205. }
  206. /*
  207.  * Fill in the info from the directory if this is a newly created
  208.  * inode.
  209.  */
  210. if (!result->i_ctime) {
  211. if (!(result->i_ctime = local_to_gmt(dir->i_sb, de->creation_date)))
  212. result->i_ctime = 1;
  213. result->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
  214. result->i_atime = local_to_gmt(dir->i_sb, de->read_date);
  215. result->i_hpfs_ea_size = de->ea_size;
  216. if (!result->i_hpfs_ea_mode && de->read_only)
  217. result->i_mode &= ~0222;
  218. if (!de->directory) {
  219. if (result->i_size == -1) {
  220. result->i_size = de->file_size;
  221. result->i_data.a_ops = &hpfs_aops;
  222. result->u.hpfs_i.mmu_private = result->i_size;
  223. /*
  224.  * i_blocks should count the fnode and any anodes.
  225.  * We count 1 for the fnode and don't bother about
  226.  * anodes -- the disk heads are on the directory band
  227.  * and we want them to stay there.
  228.  */
  229. result->i_blocks = 1 + ((result->i_size + 511) >> 9);
  230. }
  231. }
  232. }
  233. hpfs_brelse4(&qbh);
  234. /*
  235.  * Made it.
  236.  */
  237. end:
  238. hpfs_unlock_inode(dir);
  239. end_add:
  240. hpfs_set_dentry_operations(dentry);
  241. d_add(dentry, result);
  242. return NULL;
  243. /*
  244.  * Didn't.
  245.  */
  246. bail1:
  247. hpfs_brelse4(&qbh);
  248. /*bail:*/
  249. hpfs_unlock_inode(dir);
  250. return ERR_PTR(-ENOENT);
  251. }