0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/gfp.h>
0011 #include "isofs.h"
0012
0013
0014
0015
0016
0017
0018 static int
0019 isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
0020 {
0021 struct qstr qstr;
0022 qstr.name = compare;
0023 qstr.len = dlen;
0024 if (likely(!dentry->d_op))
0025 return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
0026 return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
0027 }
0028
0029
0030
0031
0032
0033
0034
0035 static unsigned long
0036 isofs_find_entry(struct inode *dir, struct dentry *dentry,
0037 unsigned long *block_rv, unsigned long *offset_rv,
0038 char *tmpname, struct iso_directory_record *tmpde)
0039 {
0040 unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
0041 unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
0042 unsigned long block, f_pos, offset, block_saved, offset_saved;
0043 struct buffer_head *bh = NULL;
0044 struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
0045
0046 if (!ISOFS_I(dir)->i_first_extent)
0047 return 0;
0048
0049 f_pos = 0;
0050 offset = 0;
0051 block = 0;
0052
0053 while (f_pos < dir->i_size) {
0054 struct iso_directory_record *de;
0055 int de_len, match, i, dlen;
0056 char *dpnt;
0057
0058 if (!bh) {
0059 bh = isofs_bread(dir, block);
0060 if (!bh)
0061 return 0;
0062 }
0063
0064 de = (struct iso_directory_record *) (bh->b_data + offset);
0065
0066 de_len = *(unsigned char *) de;
0067 if (!de_len) {
0068 brelse(bh);
0069 bh = NULL;
0070 f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
0071 block = f_pos >> bufbits;
0072 offset = 0;
0073 continue;
0074 }
0075
0076 block_saved = bh->b_blocknr;
0077 offset_saved = offset;
0078 offset += de_len;
0079 f_pos += de_len;
0080
0081
0082 if (offset >= bufsize) {
0083 int slop = bufsize - offset + de_len;
0084 memcpy(tmpde, de, slop);
0085 offset &= bufsize - 1;
0086 block++;
0087 brelse(bh);
0088 bh = NULL;
0089 if (offset) {
0090 bh = isofs_bread(dir, block);
0091 if (!bh)
0092 return 0;
0093 memcpy((void *) tmpde + slop, bh->b_data, offset);
0094 }
0095 de = tmpde;
0096 }
0097
0098 dlen = de->name_len[0];
0099 dpnt = de->name;
0100
0101 if (de_len < dlen + sizeof(struct iso_directory_record)) {
0102 printk(KERN_NOTICE "iso9660: Corrupted directory entry"
0103 " in block %lu of inode %lu\n", block,
0104 dir->i_ino);
0105 brelse(bh);
0106 return 0;
0107 }
0108
0109 if (sbi->s_rock &&
0110 ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
0111 dlen = i;
0112 dpnt = tmpname;
0113 #ifdef CONFIG_JOLIET
0114 } else if (sbi->s_joliet_level) {
0115 dlen = get_joliet_filename(de, tmpname, dir);
0116 dpnt = tmpname;
0117 #endif
0118 } else if (sbi->s_mapping == 'a') {
0119 dlen = get_acorn_filename(de, tmpname, dir);
0120 dpnt = tmpname;
0121 } else if (sbi->s_mapping == 'n') {
0122 dlen = isofs_name_translate(de, tmpname, dir);
0123 dpnt = tmpname;
0124 }
0125
0126
0127
0128
0129
0130 match = 0;
0131 if (dlen > 0 &&
0132 (!sbi->s_hide ||
0133 (!(de->flags[-sbi->s_high_sierra] & 1))) &&
0134 (sbi->s_showassoc ||
0135 (!(de->flags[-sbi->s_high_sierra] & 4)))) {
0136 if (dpnt && (dlen > 1 || dpnt[0] > 1))
0137 match = (isofs_cmp(dentry, dpnt, dlen) == 0);
0138 }
0139 if (match) {
0140 isofs_normalize_block_and_offset(de,
0141 &block_saved,
0142 &offset_saved);
0143 *block_rv = block_saved;
0144 *offset_rv = offset_saved;
0145 brelse(bh);
0146 return 1;
0147 }
0148 }
0149 brelse(bh);
0150 return 0;
0151 }
0152
0153 struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
0154 {
0155 int found;
0156 unsigned long block;
0157 unsigned long offset;
0158 struct inode *inode;
0159 struct page *page;
0160
0161 page = alloc_page(GFP_USER);
0162 if (!page)
0163 return ERR_PTR(-ENOMEM);
0164
0165 found = isofs_find_entry(dir, dentry,
0166 &block, &offset,
0167 page_address(page),
0168 1024 + page_address(page));
0169 __free_page(page);
0170
0171 inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL;
0172
0173 return d_splice_alias(inode, dentry);
0174 }