Blame view
fs/isofs/namei.c
4.07 KB
1da177e4c
|
1 2 3 4 5 6 7 |
/* * linux/fs/isofs/namei.c * * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. * * (C) 1991 Linus Torvalds - minix filesystem */ |
1da177e4c
|
8 |
#include <linux/smp_lock.h> |
94f2f7157
|
9 |
#include "isofs.h" |
1da177e4c
|
10 11 12 13 14 15 16 |
/* * ok, we cannot use strncmp, as the name is not in our data space. * Thus we'll have to use isofs_match. No big problem. Match also makes * some sanity tests. */ static int |
c3ed85a36
|
17 |
isofs_cmp(struct dentry *dentry, const char *compare, int dlen) |
1da177e4c
|
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
{ struct qstr qstr; if (!compare) return 1; /* check special "." and ".." files */ if (dlen == 1) { /* "." */ if (compare[0] == 0) { if (!dentry->d_name.len) return 0; compare = "."; } else if (compare[0] == 1) { compare = ".."; dlen = 2; } } qstr.name = compare; qstr.len = dlen; return dentry->d_op->d_compare(dentry, &dentry->d_name, &qstr); } /* * isofs_find_entry() * * finds an entry in the specified directory with the wanted name. It * returns the inode number of the found entry, or 0 on error. */ static unsigned long isofs_find_entry(struct inode *dir, struct dentry *dentry, |
c3ed85a36
|
50 51 |
unsigned long *block_rv, unsigned long *offset_rv, char *tmpname, struct iso_directory_record *tmpde) |
1da177e4c
|
52 53 54 55 |
{ unsigned long bufsize = ISOFS_BUFFER_SIZE(dir); unsigned char bufbits = ISOFS_BUFFER_BITS(dir); unsigned long block, f_pos, offset, block_saved, offset_saved; |
c3ed85a36
|
56 |
struct buffer_head *bh = NULL; |
1da177e4c
|
57 58 59 60 |
struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb); if (!ISOFS_I(dir)->i_first_extent) return 0; |
c3ed85a36
|
61 |
|
1da177e4c
|
62 63 64 65 66 |
f_pos = 0; offset = 0; block = 0; while (f_pos < dir->i_size) { |
c3ed85a36
|
67 |
struct iso_directory_record *de; |
1da177e4c
|
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
int de_len, match, i, dlen; char *dpnt; if (!bh) { bh = isofs_bread(dir, block); if (!bh) return 0; } de = (struct iso_directory_record *) (bh->b_data + offset); de_len = *(unsigned char *) de; if (!de_len) { brelse(bh); bh = NULL; f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1); block = f_pos >> bufbits; offset = 0; continue; } block_saved = bh->b_blocknr; offset_saved = offset; offset += de_len; f_pos += de_len; /* Make sure we have a full directory entry */ if (offset >= bufsize) { int slop = bufsize - offset + de_len; memcpy(tmpde, de, slop); offset &= bufsize - 1; block++; brelse(bh); bh = NULL; if (offset) { bh = isofs_bread(dir, block); if (!bh) return 0; memcpy((void *) tmpde + slop, bh->b_data, offset); } de = tmpde; } dlen = de->name_len[0]; dpnt = de->name; if (sbi->s_rock && ((i = get_rock_ridge_filename(de, tmpname, dir)))) { |
c3ed85a36
|
116 |
dlen = i; /* possibly -1 */ |
1da177e4c
|
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
dpnt = tmpname; #ifdef CONFIG_JOLIET } else if (sbi->s_joliet_level) { dlen = get_joliet_filename(de, tmpname, dir); dpnt = tmpname; #endif } else if (sbi->s_mapping == 'a') { dlen = get_acorn_filename(de, tmpname, dir); dpnt = tmpname; } else if (sbi->s_mapping == 'n') { dlen = isofs_name_translate(de, tmpname, dir); dpnt = tmpname; } /* |
9769f4eb3
|
132 133 |
* Skip hidden or associated files unless hide or showassoc, * respectively, is set |
1da177e4c
|
134 135 136 |
*/ match = 0; if (dlen > 0 && |
9769f4eb3
|
137 138 139 140 141 |
(sbi->s_hide =='n' || (!(de->flags[-sbi->s_high_sierra] & 1))) && (sbi->s_showassoc =='y' || (!(de->flags[-sbi->s_high_sierra] & 4)))) { match = (isofs_cmp(dentry, dpnt, dlen) == 0); |
1da177e4c
|
142 143 144 145 146 |
} if (match) { isofs_normalize_block_and_offset(de, &block_saved, &offset_saved); |
c3ed85a36
|
147 148 |
*block_rv = block_saved; *offset_rv = offset_saved; |
9769f4eb3
|
149 |
brelse(bh); |
1da177e4c
|
150 151 152 |
return 1; } } |
9769f4eb3
|
153 |
brelse(bh); |
1da177e4c
|
154 155 |
return 0; } |
c3ed85a36
|
156 |
struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
1da177e4c
|
157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
{ int found; unsigned long block, offset; struct inode *inode; struct page *page; dentry->d_op = dir->i_sb->s_root->d_op; page = alloc_page(GFP_USER); if (!page) return ERR_PTR(-ENOMEM); lock_kernel(); found = isofs_find_entry(dir, dentry, |
c3ed85a36
|
171 172 173 |
&block, &offset, page_address(page), 1024 + page_address(page)); |
1da177e4c
|
174 175 176 177 178 179 180 181 182 183 184 |
__free_page(page); inode = NULL; if (found) { inode = isofs_iget(dir->i_sb, block, offset); if (!inode) { unlock_kernel(); return ERR_PTR(-EACCES); } } unlock_kernel(); |
2ff6b1c25
|
185 |
return d_splice_alias(inode, dentry); |
1da177e4c
|
186 |
} |