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 15 #include <linux/buffer_head.h> 16 #include "qnx4.h" 17 18 19 /* 20 * check if the filename is correct. For some obscure reason, qnx writes a 21 * new file twice in the directory entry, first with all possible options at 0 22 * and for a second time the way it is, they want us not to access the qnx 23 * filesystem when whe are using linux. 24 */ 25 static int qnx4_match(int len, const char *name, 26 struct buffer_head *bh, unsigned long *offset) 27 { 28 struct qnx4_inode_entry *de; 29 int namelen, thislen; 30 31 if (bh == NULL) { 32 printk(KERN_WARNING "qnx4: matching unassigned buffer !\n"); 33 return 0; 34 } 35 de = (struct qnx4_inode_entry *) (bh->b_data + *offset); 36 *offset += QNX4_DIR_ENTRY_SIZE; 37 if ((de->di_status & QNX4_FILE_LINK) != 0) { 38 namelen = QNX4_NAME_MAX; 39 } else { 40 namelen = QNX4_SHORT_NAME_MAX; 41 } 42 thislen = strlen( de->di_fname ); 43 if ( thislen > namelen ) 44 thislen = namelen; 45 if (len != thislen) { 46 return 0; 47 } 48 if (strncmp(name, de->di_fname, len) == 0) { 49 if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) { 50 return 1; 51 } 52 } 53 return 0; 54 } 55 56 static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, 57 const char *name, struct qnx4_inode_entry **res_dir, int *ino) 58 { 59 unsigned long block, offset, blkofs; 60 struct buffer_head *bh; 61 62 *res_dir = NULL; 63 if (!dir->i_sb) { 64 printk(KERN_WARNING "qnx4: no superblock on dir.\n"); 65 return NULL; 66 } 67 bh = NULL; 68 block = offset = blkofs = 0; 69 while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) { 70 if (!bh) { 71 block = qnx4_block_map(dir, blkofs); 72 if (block) 73 bh = sb_bread(dir->i_sb, block); 74 if (!bh) { 75 blkofs++; 76 continue; 77 } 78 } 79 *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset); 80 if (qnx4_match(len, name, bh, &offset)) { 81 *ino = block * QNX4_INODES_PER_BLOCK + 82 (offset / QNX4_DIR_ENTRY_SIZE) - 1; 83 return bh; 84 } 85 if (offset < bh->b_size) { 86 continue; 87 } 88 brelse(bh); 89 bh = NULL; 90 offset = 0; 91 blkofs++; 92 } 93 brelse(bh); 94 *res_dir = NULL; 95 return NULL; 96 } 97 98 struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 99 { 100 int ino; 101 struct qnx4_inode_entry *de; 102 struct qnx4_link_info *lnk; 103 struct buffer_head *bh; 104 const char *name = dentry->d_name.name; 105 int len = dentry->d_name.len; 106 struct inode *foundinode = NULL; 107 108 if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) 109 goto out; 110 /* The entry is linked, let's get the real info */ 111 if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) { 112 lnk = (struct qnx4_link_info *) de; 113 ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) * 114 QNX4_INODES_PER_BLOCK + 115 lnk->dl_inode_ndx; 116 } 117 brelse(bh); 118 119 foundinode = qnx4_iget(dir->i_sb, ino); 120 if (IS_ERR(foundinode)) { 121 QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n", 122 PTR_ERR(foundinode))); 123 return ERR_CAST(foundinode); 124 } 125 out: 126 d_add(dentry, foundinode); 127 128 return NULL; 129 } 130