Import 2.1.118
[davej-history.git] / fs / isofs / dir.c
blobf73ec5271fd2c15c9ae9dd75987caf4891f345c8
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, /* readpage */
61 NULL, /* writepage */
62 isofs_bmap, /* bmap */
63 NULL, /* truncate */
64 NULL /* permission */
67 static int isofs_name_translate(char * old, int len, char * new)
69 int i, c;
71 for (i = 0; i < len; i++) {
72 c = old[i];
73 if (!c)
74 break;
75 if (c >= 'A' && c <= 'Z')
76 c |= 0x20; /* lower case */
78 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
79 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
80 break;
82 /* Drop trailing ';1' */
83 if (c == ';' && i == len - 2 && old[i + 1] == '1')
84 break;
86 /* Convert remaining ';' to '.' */
87 if (c == ';')
88 c = '.';
90 new[i] = c;
92 return i;
95 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
96 int get_acorn_filename(struct iso_directory_record * de,
97 char * retname, struct inode * inode)
99 int std;
100 unsigned char * chr;
101 int retnamlen = isofs_name_translate(de->name,
102 de->name_len[0], retname);
103 if (retnamlen == 0) return 0;
104 std = sizeof(struct iso_directory_record) + de->name_len[0];
105 if (std & 1) std++;
106 if ((*((unsigned char *) de) - std) != 32) return retnamlen;
107 chr = ((unsigned char *) de) + std;
108 if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
109 if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
110 if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
111 && ((chr[12] & 0xf0) == 0xf0))
113 retname[retnamlen] = ',';
114 sprintf(retname+retnamlen+1, "%3.3x",
115 ((chr[12] & 0xf) << 8) | chr[11]);
116 retnamlen += 4;
118 return retnamlen;
122 * This should _really_ be cleaned up some day..
124 static int do_isofs_readdir(struct inode *inode, struct file *filp,
125 void *dirent, filldir_t filldir,
126 char * tmpname, struct iso_directory_record * tmpde)
128 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
129 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
130 unsigned int block, offset;
131 int inode_number = 0; /* Quiet GCC */
132 struct buffer_head *bh;
133 int len;
134 int map;
135 int high_sierra;
136 int first_de = 1;
137 char *p = NULL; /* Quiet GCC */
138 struct iso_directory_record *de;
140 if (filp->f_pos >= inode->i_size)
141 return 0;
143 offset = filp->f_pos & (bufsize - 1);
144 block = isofs_bmap(inode, filp->f_pos >> bufbits);
145 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
147 if (!block)
148 return 0;
150 if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
151 return 0;
153 while (filp->f_pos < inode->i_size) {
154 int de_len;
155 #ifdef DEBUG
156 printk("Block, offset, f_pos: %x %x %x\n",
157 block, offset, filp->f_pos);
158 printk("inode->i_size = %x\n",inode->i_size);
159 #endif
160 de = (struct iso_directory_record *) (bh->b_data + offset);
161 if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
163 de_len = *(unsigned char *) de;
164 #ifdef DEBUG
165 printk("de_len = %ld\n", de_len);
166 #endif
169 /* If the length byte is zero, we should move on to the next
170 CDROM sector. If we are at the end of the directory, we
171 kick out of the while loop. */
173 if ((de_len == 0) || (offset >= bufsize) ) {
174 brelse(bh);
175 if (de_len == 0) {
176 filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
177 + ISOFS_BLOCK_SIZE);
178 offset = 0;
179 } else {
180 offset -= bufsize;
181 filp->f_pos += offset;
184 if (filp->f_pos >= inode->i_size)
185 return 0;
187 block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
188 if (!block)
189 return 0;
190 bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
191 if (!bh)
192 return 0;
193 continue;
196 offset += de_len;
197 if (offset > bufsize) {
199 * This would only normally happen if we had
200 * a buggy cdrom image. All directory
201 * entries should terminate with a null size
202 * or end exactly at the end of the sector.
204 printk("next_offset (%x) > bufsize (%lx)\n",
205 offset,bufsize);
206 break;
209 if(de->flags[-high_sierra] & 0x80) {
210 first_de = 0;
211 filp->f_pos += de_len;
212 continue;
214 first_de = 1;
216 /* Handle the case of the '.' directory */
217 if (de->name_len[0] == 1 && de->name[0] == 0) {
218 if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
219 break;
220 filp->f_pos += de_len;
221 continue;
224 len = 0;
226 /* Handle the case of the '..' directory */
227 if (de->name_len[0] == 1 && de->name[0] == 1) {
228 inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
229 if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
230 break;
231 filp->f_pos += de_len;
232 continue;
235 /* Handle everything else. Do name translation if there
236 is no Rock Ridge NM field. */
237 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
238 /* Do not report hidden or associated files */
239 if (de->flags[-high_sierra] & 5) {
240 filp->f_pos += de_len;
241 continue;
245 map = 1;
246 if (inode->i_sb->u.isofs_sb.s_rock) {
247 len = get_rock_ridge_filename(de, tmpname, inode);
248 if (len != 0) {
249 p = tmpname;
250 map = 0;
253 if (map) {
254 #ifdef CONFIG_JOLIET
255 if (inode->i_sb->u.isofs_sb.s_joliet_level) {
256 len = get_joliet_filename(de, inode, tmpname);
257 p = tmpname;
258 } else
259 #endif
260 if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
261 len = get_acorn_filename(de, tmpname, inode);
262 p = tmpname;
263 } else
264 if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
265 len = isofs_name_translate(de->name,
266 de->name_len[0], tmpname);
267 p = tmpname;
268 } else {
269 p = de->name;
270 len = de->name_len[0];
273 if (len > 0) {
274 if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
275 break;
277 filp->f_pos += de_len;
279 continue;
281 brelse(bh);
282 return 0;
286 * Handle allocation of temporary space for name translation and
287 * handling split directory entries.. The real work is done by
288 * "do_isofs_readdir()".
290 static int isofs_readdir(struct file *filp,
291 void *dirent, filldir_t filldir)
293 int result;
294 char * tmpname;
295 struct iso_directory_record * tmpde;
296 struct inode *inode = filp->f_dentry->d_inode;
298 if (!inode || !S_ISDIR(inode->i_mode))
299 return -EBADF;
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;