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