namei.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * QNX4 file system, Linux implementation.
  3. *
  4. * Version : 0.2.1
  5. *
  6. * Using parts of the xiafs filesystem.
  7. *
  8. * History :
  9. *
  10. * 01-06-1998 by Richard Frowijn : first release.
  11. * 21-06-1998 by Frank Denis : dcache support, fixed error codes.
  12. * 04-07-1998 by Frank Denis : first step for rmdir/unlink.
  13. */
  14. #include <linux/config.h>
  15. #include <linux/time.h>
  16. #include <linux/fs.h>
  17. #include <linux/qnx4_fs.h>
  18. #include <linux/kernel.h>
  19. #include <linux/string.h>
  20. #include <linux/stat.h>
  21. #include <linux/fcntl.h>
  22. #include <linux/errno.h>
  23. #include <linux/smp_lock.h>
  24. #include <linux/buffer_head.h>
  25. /*
  26. * check if the filename is correct. For some obscure reason, qnx writes a
  27. * new file twice in the directory entry, first with all possible options at 0
  28. * and for a second time the way it is, they want us not to access the qnx
  29. * filesystem when whe are using linux.
  30. */
  31. static int qnx4_match(int len, const char *name,
  32. struct buffer_head *bh, unsigned long *offset)
  33. {
  34. struct qnx4_inode_entry *de;
  35. int namelen, thislen;
  36. if (bh == NULL) {
  37. printk("qnx4: matching unassigned buffer !\n");
  38. return 0;
  39. }
  40. de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
  41. *offset += QNX4_DIR_ENTRY_SIZE;
  42. if ((de->di_status & QNX4_FILE_LINK) != 0) {
  43. namelen = QNX4_NAME_MAX;
  44. } else {
  45. namelen = QNX4_SHORT_NAME_MAX;
  46. }
  47. /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
  48. if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) {
  49. return 1;
  50. }
  51. thislen = strlen( de->di_fname );
  52. if ( thislen > namelen )
  53. thislen = namelen;
  54. if (len != thislen) {
  55. return 0;
  56. }
  57. if (strncmp(name, de->di_fname, len) == 0) {
  58. if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) {
  59. return 1;
  60. }
  61. }
  62. return 0;
  63. }
  64. static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
  65. const char *name, struct qnx4_inode_entry **res_dir, int *ino)
  66. {
  67. unsigned long block, offset, blkofs;
  68. struct buffer_head *bh;
  69. *res_dir = NULL;
  70. if (!dir->i_sb) {
  71. printk("qnx4: no superblock on dir.\n");
  72. return NULL;
  73. }
  74. bh = NULL;
  75. block = offset = blkofs = 0;
  76. while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
  77. if (!bh) {
  78. bh = qnx4_bread(dir, blkofs, 0);
  79. if (!bh) {
  80. blkofs++;
  81. continue;
  82. }
  83. }
  84. *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
  85. if (qnx4_match(len, name, bh, &offset)) {
  86. block = qnx4_block_map( dir, blkofs );
  87. *ino = block * QNX4_INODES_PER_BLOCK +
  88. (offset / QNX4_DIR_ENTRY_SIZE) - 1;
  89. return bh;
  90. }
  91. if (offset < bh->b_size) {
  92. continue;
  93. }
  94. brelse(bh);
  95. bh = NULL;
  96. offset = 0;
  97. blkofs++;
  98. }
  99. brelse(bh);
  100. *res_dir = NULL;
  101. return NULL;
  102. }
  103. struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
  104. {
  105. int ino;
  106. struct qnx4_inode_entry *de;
  107. struct qnx4_link_info *lnk;
  108. struct buffer_head *bh;
  109. const char *name = dentry->d_name.name;
  110. int len = dentry->d_name.len;
  111. struct inode *foundinode = NULL;
  112. lock_kernel();
  113. if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
  114. goto out;
  115. /* The entry is linked, let's get the real info */
  116. if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
  117. lnk = (struct qnx4_link_info *) de;
  118. ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) *
  119. QNX4_INODES_PER_BLOCK +
  120. lnk->dl_inode_ndx;
  121. }
  122. brelse(bh);
  123. if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
  124. unlock_kernel();
  125. QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
  126. return ERR_PTR(-EACCES);
  127. }
  128. out:
  129. unlock_kernel();
  130. d_add(dentry, foundinode);
  131. return NULL;
  132. }
  133. #ifdef CONFIG_QNX4FS_RW
  134. int qnx4_create(struct inode *dir, struct dentry *dentry, int mode,
  135. struct nameidata *nd)
  136. {
  137. QNX4DEBUG(("qnx4: qnx4_create\n"));
  138. if (dir == NULL) {
  139. return -ENOENT;
  140. }
  141. return -ENOSPC;
  142. }
  143. int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
  144. {
  145. struct buffer_head *bh;
  146. struct qnx4_inode_entry *de;
  147. struct inode *inode;
  148. int retval;
  149. int ino;
  150. QNX4DEBUG(("qnx4: qnx4_rmdir [%s]\n", dentry->d_name.name));
  151. lock_kernel();
  152. bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
  153. &de, &ino);
  154. if (bh == NULL) {
  155. unlock_kernel();
  156. return -ENOENT;
  157. }
  158. inode = dentry->d_inode;
  159. if (inode->i_ino != ino) {
  160. retval = -EIO;
  161. goto end_rmdir;
  162. }
  163. #if 0
  164. if (!empty_dir(inode)) {
  165. retval = -ENOTEMPTY;
  166. goto end_rmdir;
  167. }
  168. #endif
  169. if (inode->i_nlink != 2) {
  170. QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink));
  171. }
  172. QNX4DEBUG(("qnx4: deleting directory\n"));
  173. de->di_status = 0;
  174. memset(de->di_fname, 0, sizeof de->di_fname);
  175. de->di_mode = 0;
  176. mark_buffer_dirty(bh);
  177. inode->i_nlink = 0;
  178. mark_inode_dirty(inode);
  179. inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
  180. dir->i_nlink--;
  181. mark_inode_dirty(dir);
  182. retval = 0;
  183. end_rmdir:
  184. brelse(bh);
  185. unlock_kernel();
  186. return retval;
  187. }
  188. int qnx4_unlink(struct inode *dir, struct dentry *dentry)
  189. {
  190. struct buffer_head *bh;
  191. struct qnx4_inode_entry *de;
  192. struct inode *inode;
  193. int retval;
  194. int ino;
  195. QNX4DEBUG(("qnx4: qnx4_unlink [%s]\n", dentry->d_name.name));
  196. lock_kernel();
  197. bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
  198. &de, &ino);
  199. if (bh == NULL) {
  200. unlock_kernel();
  201. return -ENOENT;
  202. }
  203. inode = dentry->d_inode;
  204. if (inode->i_ino != ino) {
  205. retval = -EIO;
  206. goto end_unlink;
  207. }
  208. retval = -EPERM;
  209. if (!inode->i_nlink) {
  210. QNX4DEBUG(("Deleting nonexistent file (%s:%lu), %d\n",
  211. inode->i_sb->s_id,
  212. inode->i_ino, inode->i_nlink));
  213. inode->i_nlink = 1;
  214. }
  215. de->di_status = 0;
  216. memset(de->di_fname, 0, sizeof de->di_fname);
  217. de->di_mode = 0;
  218. mark_buffer_dirty(bh);
  219. dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
  220. mark_inode_dirty(dir);
  221. inode->i_nlink--;
  222. inode->i_ctime = dir->i_ctime;
  223. mark_inode_dirty(inode);
  224. retval = 0;
  225. end_unlink:
  226. unlock_kernel();
  227. brelse(bh);
  228. return retval;
  229. }
  230. #endif