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;
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__ __volatile__(
49 "cld\n\t"
50 "repe ; cmpsb\n\t"
51 "setz %%al"
52 :"=a" (same)
53 :"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len)
54 :"cx","di","si");
55 return same;
56 }
57
58
59
60
61
62
63
64
65
66 static struct buffer_head * isofs_find_entry(struct inode * dir,
67 const char * name, int namelen, unsigned long * ino, unsigned long * ino_back)
68 {
69 unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
70 unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
71 unsigned int block, i, f_pos, offset, inode_number;
72 struct buffer_head * bh;
73 void * cpnt = NULL;
74 unsigned int old_offset;
75 unsigned int backlink;
76 int dlen, rrflag, match;
77 char * dpnt;
78 struct iso_directory_record * de;
79 char c;
80
81 *ino = 0;
82 if (!dir) return NULL;
83
84 if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
85
86 f_pos = 0;
87
88 offset = f_pos & (bufsize - 1);
89 block = isofs_bmap(dir,f_pos >> bufbits);
90
91 if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
92
93 while (f_pos < dir->i_size) {
94 de = (struct iso_directory_record *) (bh->b_data + offset);
95 backlink = dir->i_ino;
96 inode_number = (block << bufbits) + (offset & (bufsize - 1));
97
98
99
100
101 if (*((unsigned char *) de) == 0) {
102 brelse(bh);
103 offset = 0;
104 f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
105 + ISOFS_BLOCK_SIZE);
106 block = isofs_bmap(dir,f_pos>>bufbits);
107 if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
108 return 0;
109 continue;
110 }
111
112 old_offset = offset;
113 offset += *((unsigned char *) de);
114 f_pos += *((unsigned char *) de);
115
116
117
118 if (offset >= bufsize) {
119 unsigned int frag1;
120 frag1 = bufsize - old_offset;
121 cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
122 memcpy(cpnt, bh->b_data + old_offset, frag1);
123
124 de = (struct iso_directory_record *) cpnt;
125 brelse(bh);
126 offset = f_pos & (bufsize - 1);
127 block = isofs_bmap(dir,f_pos>>bufbits);
128 if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
129 kfree(cpnt);
130 return 0;
131 };
132 memcpy((char *)cpnt+frag1, bh->b_data, offset);
133 }
134
135
136
137 if (de->name[0]==0 && de->name_len[0]==1) {
138 inode_number = dir->i_ino;
139 backlink = 0;
140 }
141
142
143
144 if (de->name[0]==1 && de->name_len[0]==1) {
145 #if 0
146 printk("Doing .. (%d %d)",
147 dir->i_sb->s_firstdatazone << bufbits,
148 dir->i_ino);
149 #endif
150 if((dir->i_sb->u.isofs_sb.s_firstdatazone
151 << bufbits) != dir->i_ino)
152 inode_number = dir->u.isofs_i.i_backlink;
153 else
154 inode_number = dir->i_ino;
155 backlink = 0;
156 }
157
158 dlen = de->name_len[0];
159 dpnt = de->name;
160
161 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
162 if (rrflag) {
163 if (rrflag == -1) goto out;
164 } else {
165 if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
166 for (i = 0; i < dlen; i++) {
167 c = dpnt[i];
168 if (c >= 'A' && c <= 'Z') c |= 0x20;
169 if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
170 dlen -= 2;
171 break;
172 }
173 if (c == ';') c = '.';
174 de->name[i] = c;
175 }
176
177
178 if(dpnt[dlen-1] == '.' && namelen == dlen-1)
179 dlen--;
180 }
181 }
182 match = isofs_match(namelen,name,dpnt,dlen);
183 if (cpnt) {
184 kfree(cpnt);
185 cpnt = NULL;
186 }
187
188 if(rrflag) kfree(dpnt);
189 if (match) {
190 if(inode_number == -1) {
191
192 inode_number =
193 isofs_lookup_grandparent(dir,
194 find_rock_ridge_relocation(de,dir));
195 if(inode_number == -1){
196
197 printk("Backlink not properly set.\n");
198 goto out;
199 }
200 }
201 *ino = inode_number;
202 *ino_back = backlink;
203 return bh;
204 }
205 }
206 out:
207 if (cpnt)
208 kfree(cpnt);
209 brelse(bh);
210 return NULL;
211 }
212
213 int isofs_lookup(struct inode * dir,const char * name, int len,
214 struct inode ** result)
215 {
216 unsigned long ino, ino_back;
217 struct buffer_head * bh;
218
219 #ifdef DEBUG
220 printk("lookup: %x %d\n",dir->i_ino, len);
221 #endif
222 *result = NULL;
223 if (!dir)
224 return -ENOENT;
225
226 if (!S_ISDIR(dir->i_mode)) {
227 iput(dir);
228 return -ENOENT;
229 }
230
231 ino = 0;
232
233 if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
234
235 if (!ino) {
236 if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))) {
237 iput(dir);
238 return -ENOENT;
239 }
240 if (ino_back == dir->i_ino)
241 dcache_add(dir, name, len, ino);
242 brelse(bh);
243 };
244
245 if (!(*result = iget(dir->i_sb,ino))) {
246 iput(dir);
247 return -EACCES;
248 }
249
250
251
252
253
254
255
256 if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
257 (*result)->u.isofs_i.i_backlink = ino_back;
258 }
259
260 iput(dir);
261 return 0;
262 }