* better
[mascara-docs.git] / i386 / linux-2.3.21 / fs / isofs / dir.c
blobbc64dfdd587b6cc1cf1c8bff9a17a83b2675a706
1 /*
2 * linux/fs/isofs/dir.c
4 * (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem.
6 * (C) 1991 Linus Torvalds - minix filesystem
8 * Steve Beynon : Missing last directory entries fixed
9 * (stephen@askone.demon.co.uk) : 21st June 1996
11 * isofs directory handling functions
13 #include <linux/errno.h>
14 #include <linux/fs.h>
15 #include <linux/iso_fs.h>
16 #include <linux/kernel.h>
17 #include <linux/stat.h>
18 #include <linux/string.h>
19 #include <linux/mm.h>
20 #include <linux/malloc.h>
21 #include <linux/sched.h>
22 #include <linux/locks.h>
23 #include <linux/config.h>
25 #include <asm/uaccess.h>
27 static int isofs_readdir(struct file *, void *, filldir_t);
29 static struct file_operations isofs_dir_operations =
31 NULL, /* lseek - default */
32 NULL, /* read */
33 NULL, /* write - bad */
34 isofs_readdir, /* readdir */
35 NULL, /* poll - default */
36 NULL, /* ioctl - default */
37 NULL, /* no special open code */
38 NULL, /* flush */
39 NULL, /* no special release code */
40 NULL /* fsync */
44 * directories can handle most operations...
46 struct inode_operations isofs_dir_inode_operations =
48 &isofs_dir_operations, /* default directory file-ops */
49 NULL, /* create */
50 isofs_lookup, /* lookup */
51 NULL, /* link */
52 NULL, /* unlink */
53 NULL, /* symlink */
54 NULL, /* mkdir */
55 NULL, /* rmdir */
56 NULL, /* mknod */
57 NULL, /* rename */
58 NULL, /* readlink */
59 NULL, /* follow_link */
60 NULL, /* get_block */
61 NULL, /* readpage */
62 NULL, /* writepage */
63 NULL, /* flushpage */
64 NULL, /* truncate */
65 NULL, /* permission */
66 NULL, /* smap */
67 NULL /* revalidate */
70 static int isofs_name_translate(char * old, int len, char * new)
72 int i, c;
74 for (i = 0; i < len; i++) {
75 c = old[i];
76 if (!c)
77 break;
78 if (c >= 'A' && c <= 'Z')
79 c |= 0x20; /* lower case */
81 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
82 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
83 break;
85 /* Drop trailing ';1' */
86 if (c == ';' && i == len - 2 && old[i + 1] == '1')
87 break;
89 /* Convert remaining ';' to '.' */
90 if (c == ';')
91 c = '.';
93 new[i] = c;
95 return i;
98 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
99 int get_acorn_filename(struct iso_directory_record * de,
100 char * retname, struct inode * inode)
102 int std;
103 unsigned char * chr;
104 int retnamlen = isofs_name_translate(de->name,
105 de->name_len[0], retname);
106 if (retnamlen == 0) return 0;
107 std = sizeof(struct iso_directory_record) + de->name_len[0];
108 if (std & 1) std++;
109 if ((*((unsigned char *) de) - std) != 32) return retnamlen;
110 chr = ((unsigned char *) de) + std;
111 if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
112 if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
113 if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
114 && ((chr[12] & 0xf0) == 0xf0))
116 retname[retnamlen] = ',';
117 sprintf(retname+retnamlen+1, "%3.3x",
118 ((chr[12] & 0xf) << 8) | chr[11]);
119 retnamlen += 4;
121 return retnamlen;
125 * This should _really_ be cleaned up some day..
127 static int do_isofs_readdir(struct inode *inode, struct file *filp,
128 void *dirent, filldir_t filldir,
129 char * tmpname, struct iso_directory_record * tmpde)
131 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
132 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
133 unsigned int block, offset;
134 int inode_number = 0; /* Quiet GCC */
135 struct buffer_head *bh;
136 int len;
137 int map;
138 int high_sierra;
139 int first_de = 1;
140 char *p = NULL; /* Quiet GCC */
141 struct iso_directory_record *de;
143 if (filp->f_pos >= inode->i_size)
144 return 0;
146 offset = filp->f_pos & (bufsize - 1);
147 block = isofs_bmap(inode, filp->f_pos >> bufbits);
148 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
150 if (!block)
151 return 0;
153 if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
154 return 0;
156 while (filp->f_pos < inode->i_size) {
157 int de_len;
158 #ifdef DEBUG
159 printk("Block, offset, f_pos: %x %x %x\n",
160 block, offset, filp->f_pos);
161 printk("inode->i_size = %x\n",inode->i_size);
162 #endif
163 de = (struct iso_directory_record *) (bh->b_data + offset);
164 if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
166 de_len = *(unsigned char *) de;
167 #ifdef DEBUG
168 printk("de_len = %ld\n", de_len);
169 #endif
172 /* If the length byte is zero, we should move on to the next
173 CDROM sector. If we are at the end of the directory, we
174 kick out of the while loop. */
176 if ((de_len == 0) || (offset >= bufsize) ) {
177 brelse(bh);
178 if (de_len == 0) {
179 filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
180 + ISOFS_BLOCK_SIZE);
181 offset = 0;
182 } else {
183 offset -= bufsize;
184 filp->f_pos += offset;
187 if (filp->f_pos >= inode->i_size)
188 return 0;
190 block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
191 if (!block)
192 return 0;
193 bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
194 if (!bh)
195 return 0;
196 continue;
199 offset += de_len;
200 if (offset > bufsize) {
202 * This would only normally happen if we had
203 * a buggy cdrom image. All directory
204 * entries should terminate with a null size
205 * or end exactly at the end of the sector.
207 printk("next_offset (%x) > bufsize (%lx)\n",
208 offset,bufsize);
209 break;
212 if(de->flags[-high_sierra] & 0x80) {
213 first_de = 0;
214 filp->f_pos += de_len;
215 continue;
217 first_de = 1;
219 /* Handle the case of the '.' directory */
220 if (de->name_len[0] == 1 && de->name[0] == 0) {
221 if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
222 break;
223 filp->f_pos += de_len;
224 continue;
227 len = 0;
229 /* Handle the case of the '..' directory */
230 if (de->name_len[0] == 1 && de->name[0] == 1) {
231 inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
232 if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
233 break;
234 filp->f_pos += de_len;
235 continue;
238 /* Handle everything else. Do name translation if there
239 is no Rock Ridge NM field. */
240 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
241 /* Do not report hidden or associated files */
242 if (de->flags[-high_sierra] & 5) {
243 filp->f_pos += de_len;
244 continue;
248 map = 1;
249 if (inode->i_sb->u.isofs_sb.s_rock) {
250 len = get_rock_ridge_filename(de, tmpname, inode);
251 if (len != 0) {
252 p = tmpname;
253 map = 0;
256 if (map) {
257 #ifdef CONFIG_JOLIET
258 if (inode->i_sb->u.isofs_sb.s_joliet_level) {
259 len = get_joliet_filename(de, inode, tmpname);
260 p = tmpname;
261 } else
262 #endif
263 if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
264 len = get_acorn_filename(de, tmpname, inode);
265 p = tmpname;
266 } else
267 if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
268 len = isofs_name_translate(de->name,
269 de->name_len[0], tmpname);
270 p = tmpname;
271 } else {
272 p = de->name;
273 len = de->name_len[0];
276 if (len > 0) {
277 if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
278 break;
280 filp->f_pos += de_len;
282 continue;
284 brelse(bh);
285 return 0;
289 * Handle allocation of temporary space for name translation and
290 * handling split directory entries.. The real work is done by
291 * "do_isofs_readdir()".
293 static int isofs_readdir(struct file *filp,
294 void *dirent, filldir_t filldir)
296 int result;
297 char * tmpname;
298 struct iso_directory_record * tmpde;
299 struct inode *inode = filp->f_dentry->d_inode;
301 tmpname = (char *) __get_free_page(GFP_KERNEL);
302 if (!tmpname)
303 return -ENOMEM;
304 tmpde = (struct iso_directory_record *) (tmpname+1024);
306 result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
308 free_page((unsigned long) tmpname);
309 return result;