| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/buffer_head.h> | 
| Al Viro | 964f536 | 2009-06-07 09:47:13 -0400 | [diff] [blame] | 16 | #include "qnx4.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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) { | 
| Anders Larsen | 891ddb9 | 2009-09-26 20:15:09 +0200 | [diff] [blame] | 32 | printk(KERN_WARNING "qnx4: matching unassigned buffer !\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ | 
|  | 43 | if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) { | 
|  | 44 | return 1; | 
|  | 45 | } | 
|  | 46 | thislen = strlen( de->di_fname ); | 
|  | 47 | if ( thislen > namelen ) | 
|  | 48 | thislen = namelen; | 
|  | 49 | if (len != thislen) { | 
|  | 50 | return 0; | 
|  | 51 | } | 
|  | 52 | if (strncmp(name, de->di_fname, len) == 0) { | 
|  | 53 | if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) { | 
|  | 54 | return 1; | 
|  | 55 | } | 
|  | 56 | } | 
|  | 57 | return 0; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, | 
|  | 61 | const char *name, struct qnx4_inode_entry **res_dir, int *ino) | 
|  | 62 | { | 
|  | 63 | unsigned long block, offset, blkofs; | 
|  | 64 | struct buffer_head *bh; | 
|  | 65 |  | 
|  | 66 | *res_dir = NULL; | 
|  | 67 | if (!dir->i_sb) { | 
| Anders Larsen | 891ddb9 | 2009-09-26 20:15:09 +0200 | [diff] [blame] | 68 | printk(KERN_WARNING "qnx4: no superblock on dir.\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | return NULL; | 
|  | 70 | } | 
|  | 71 | bh = NULL; | 
|  | 72 | block = offset = blkofs = 0; | 
|  | 73 | while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) { | 
|  | 74 | if (!bh) { | 
|  | 75 | bh = qnx4_bread(dir, blkofs, 0); | 
|  | 76 | if (!bh) { | 
|  | 77 | blkofs++; | 
|  | 78 | continue; | 
|  | 79 | } | 
|  | 80 | } | 
|  | 81 | *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset); | 
|  | 82 | if (qnx4_match(len, name, bh, &offset)) { | 
|  | 83 | block = qnx4_block_map( dir, blkofs ); | 
|  | 84 | *ino = block * QNX4_INODES_PER_BLOCK + | 
|  | 85 | (offset / QNX4_DIR_ENTRY_SIZE) - 1; | 
|  | 86 | return bh; | 
|  | 87 | } | 
|  | 88 | if (offset < bh->b_size) { | 
|  | 89 | continue; | 
|  | 90 | } | 
|  | 91 | brelse(bh); | 
|  | 92 | bh = NULL; | 
|  | 93 | offset = 0; | 
|  | 94 | blkofs++; | 
|  | 95 | } | 
|  | 96 | brelse(bh); | 
|  | 97 | *res_dir = NULL; | 
|  | 98 | return NULL; | 
|  | 99 | } | 
|  | 100 |  | 
|  | 101 | struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 
|  | 102 | { | 
|  | 103 | int ino; | 
|  | 104 | struct qnx4_inode_entry *de; | 
|  | 105 | struct qnx4_link_info *lnk; | 
|  | 106 | struct buffer_head *bh; | 
|  | 107 | const char *name = dentry->d_name.name; | 
|  | 108 | int len = dentry->d_name.len; | 
|  | 109 | struct inode *foundinode = NULL; | 
|  | 110 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) | 
|  | 112 | goto out; | 
|  | 113 | /* The entry is linked, let's get the real info */ | 
|  | 114 | if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) { | 
|  | 115 | lnk = (struct qnx4_link_info *) de; | 
|  | 116 | ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) * | 
|  | 117 | QNX4_INODES_PER_BLOCK + | 
|  | 118 | lnk->dl_inode_ndx; | 
|  | 119 | } | 
|  | 120 | brelse(bh); | 
|  | 121 |  | 
| David Howells | 2b7e5bc | 2008-02-07 00:15:45 -0800 | [diff] [blame] | 122 | foundinode = qnx4_iget(dir->i_sb, ino); | 
|  | 123 | if (IS_ERR(foundinode)) { | 
| Anders Larsen | 891ddb9 | 2009-09-26 20:15:09 +0200 | [diff] [blame] | 124 | QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n", | 
| David Howells | 2b7e5bc | 2008-02-07 00:15:45 -0800 | [diff] [blame] | 125 | PTR_ERR(foundinode))); | 
|  | 126 | return ERR_CAST(foundinode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | } | 
|  | 128 | out: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | d_add(dentry, foundinode); | 
|  | 130 |  | 
|  | 131 | return NULL; | 
|  | 132 | } |