This source file includes following definitions.
- isofs_match
- isofs_find_entry
- isofs_lookup
1
2
3
4
5
6
7
8
9 #include <linux/sched.h>
10 #include <linux/iso_fs.h>
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/stat.h>
14 #include <linux/fcntl.h>
15 #include <asm/segment.h>
16 #include <linux/malloc.h>
17
18 #include <linux/errno.h>
19
20
21
22
23
24
25
26
27 static int isofs_match(int len,const char * name, char * compare, int dlen)
28 {
29 register int same __asm__("ax");
30
31 if (!compare) return 0;
32
33 if (!len && (compare[0]==0) && (dlen==1))
34 return 1;
35
36 if (compare[0]==0 && dlen==1 && len == 1)
37 compare = ".";
38 if (compare[0]==1 && dlen==1 && len == 2) {
39 compare = "..";
40 dlen = 2;
41 };
42 #if 0
43 if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
44 #endif
45
46 if (dlen != len)
47 return 0;
48 __asm__("cld\n\t"
49 "repe ; cmpsb\n\t"
50 "setz %%al"
51 :"=a" (same)
52 :"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len)
53 :"cx","di","si");
54 return same;
55 }
56
57
58
59
60
61
62
63
64
65 static struct buffer_head * isofs_find_entry(struct inode * dir,
66 const char * name, int namelen, int * ino, int * ino_back)
67 {
68 unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
69 unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
70 unsigned int block, i, f_pos, offset, inode_number;
71 struct buffer_head * bh;
72 void * cpnt = NULL;
73 unsigned int old_offset;
74 unsigned int backlink;
75 int dlen, rrflag, match;
76 char * dpnt;
77 struct iso_directory_record * de;
78 char c;
79
80 *ino = 0;
81 if (!dir) return NULL;
82
83 if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
84
85 f_pos = 0;
86
87 offset = f_pos & (bufsize - 1);
88 block = isofs_bmap(dir,f_pos >> bufbits);
89
90 if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
91
92 while (f_pos < dir->i_size) {
93 de = (struct iso_directory_record *) (bh->b_data + offset);
94 backlink = dir->i_ino;
95 inode_number = (block << bufbits) + (offset & (bufsize - 1));
96
97
98
99
100 if (*((unsigned char *) de) == 0) {
101 brelse(bh);
102 offset = 0;
103 f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
104 + ISOFS_BLOCK_SIZE);
105 block = isofs_bmap(dir,f_pos>>bufbits);
106 if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
107 return 0;
108 continue;
109 }
110
111 old_offset = offset;
112 offset += *((unsigned char *) de);
113 f_pos += *((unsigned char *) de);
114
115
116
117 if (offset >= bufsize) {
118 cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
119 memcpy(cpnt, bh->b_data, bufsize);
120 de = (struct iso_directory_record *)
121 ((char *)cpnt + old_offset);
122 brelse(bh);
123 offset = f_pos & (bufsize - 1);
124 block = isofs_bmap(dir,f_pos>>bufbits);
125 if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
126 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
127 return 0;
128 };
129 memcpy((char *)cpnt+bufsize,bh->b_data,bufsize);
130 }
131
132
133
134 if (de->name[0]==0 && de->name_len[0]==1) {
135 inode_number = dir->i_ino;
136 backlink = 0;
137 }
138
139
140
141 if (de->name[0]==1 && de->name_len[0]==1) {
142 #if 0
143 printk("Doing .. (%d %d)",
144 dir->i_sb->s_firstdatazone << bufbits,
145 dir->i_ino);
146 #endif
147 if((dir->i_sb->u.isofs_sb.s_firstdatazone
148 << bufbits) != dir->i_ino)
149 inode_number = dir->u.isofs_i.i_backlink;
150 else
151 inode_number = dir->i_ino;
152 backlink = 0;
153 }
154
155 dlen = de->name_len[0];
156 dpnt = de->name;
157
158 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
159 if (rrflag) {
160 if (rrflag == -1) goto out;
161 } else {
162 if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
163 for (i = 0; i < dlen; i++) {
164 c = dpnt[i];
165 if (c >= 'A' && c <= 'Z') c |= 0x20;
166 if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
167 dlen -= 2;
168 break;
169 }
170 if (c == ';') c = '.';
171 de->name[i] = c;
172 }
173
174
175 if(dpnt[dlen-1] == '.' && namelen == dlen-1)
176 dlen--;
177 }
178 }
179 match = isofs_match(namelen,name,dpnt,dlen);
180 if (cpnt) {
181 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
182 cpnt = NULL;
183 }
184
185 if(rrflag) kfree(dpnt);
186 if (match) {
187 if(inode_number == -1) {
188
189 inode_number =
190 isofs_lookup_grandparent(dir,
191 find_rock_ridge_relocation(de,dir));
192 if(inode_number == -1){
193
194 printk("Backlink not properly set.\n");
195 goto out;
196 }
197 }
198 *ino = inode_number;
199 *ino_back = backlink;
200 return bh;
201 }
202 }
203 out:
204 if (cpnt)
205 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
206 brelse(bh);
207 return NULL;
208 }
209
210 int isofs_lookup(struct inode * dir,const char * name, int len,
211 struct inode ** result)
212 {
213 int ino, ino_back;
214 struct buffer_head * bh;
215
216 #ifdef DEBUG
217 printk("lookup: %x %d\n",dir->i_ino, len);
218 #endif
219 *result = NULL;
220 if (!dir)
221 return -ENOENT;
222
223 if (!S_ISDIR(dir->i_mode)) {
224 iput(dir);
225 return -ENOENT;
226 }
227
228 ino = 0;
229 if (dir->i_dev == cache.dev &&
230 dir->i_ino == cache.dir &&
231 len == cache.dlen &&
232 isofs_match(len, name, cache.filename, cache.dlen))
233 {
234 ino = cache.ino;
235 ino_back = dir->i_ino;
236
237
238 if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
239 if (cache.dlen == 2 && cache.filename[0] == '.' &&
240 cache.filename[1] == '.') ino = 0;
241 };
242
243 if (!ino) {
244 if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))) {
245 iput(dir);
246 return -ENOENT;
247 }
248 brelse(bh);
249 };
250
251 if (!(*result = iget(dir->i_sb,ino))) {
252 iput(dir);
253 return -EACCES;
254 }
255
256
257
258
259
260
261
262 if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
263 (*result)->u.isofs_i.i_backlink = ino_back;
264 }
265
266 iput(dir);
267 return 0;
268 }