- pre6:
[davej-history.git] / fs / isofs / dir.c
blob8d77ed2f7483f017db2d085b0ddc5de73d6ca6d9
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 struct file_operations isofs_dir_operations =
31 read: generic_read_dir,
32 readdir: isofs_readdir,
36 * directories can handle most operations...
38 struct inode_operations isofs_dir_inode_operations =
40 lookup: isofs_lookup,
43 static int isofs_name_translate(char * old, int len, char * new)
45 int i, c;
47 for (i = 0; i < len; i++) {
48 c = old[i];
49 if (!c)
50 break;
51 if (c >= 'A' && c <= 'Z')
52 c |= 0x20; /* lower case */
54 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
55 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
56 break;
58 /* Drop trailing ';1' */
59 if (c == ';' && i == len - 2 && old[i + 1] == '1')
60 break;
62 /* Convert remaining ';' to '.' */
63 if (c == ';')
64 c = '.';
66 new[i] = c;
68 return i;
71 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
72 int get_acorn_filename(struct iso_directory_record * de,
73 char * retname, struct inode * inode)
75 int std;
76 unsigned char * chr;
77 int retnamlen = isofs_name_translate(de->name,
78 de->name_len[0], retname);
79 if (retnamlen == 0) return 0;
80 std = sizeof(struct iso_directory_record) + de->name_len[0];
81 if (std & 1) std++;
82 if ((*((unsigned char *) de) - std) != 32) return retnamlen;
83 chr = ((unsigned char *) de) + std;
84 if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
85 if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
86 if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
87 && ((chr[12] & 0xf0) == 0xf0))
89 retname[retnamlen] = ',';
90 sprintf(retname+retnamlen+1, "%3.3x",
91 ((chr[12] & 0xf) << 8) | chr[11]);
92 retnamlen += 4;
94 return retnamlen;
97 static struct buffer_head *isofs_bread(struct inode *inode, unsigned int bufsize, unsigned int block)
99 unsigned int blknr = isofs_bmap(inode, block);
100 if (!blknr)
101 return NULL;
102 return bread(inode->i_dev, blknr, bufsize);
106 * This should _really_ be cleaned up some day..
108 static int do_isofs_readdir(struct inode *inode, struct file *filp,
109 void *dirent, filldir_t filldir,
110 char * tmpname, struct iso_directory_record * tmpde)
112 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
113 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
114 unsigned int block, offset;
115 int inode_number = 0; /* Quiet GCC */
116 struct buffer_head *bh = NULL;
117 int len;
118 int map;
119 int high_sierra;
120 int first_de = 1;
121 char *p = NULL; /* Quiet GCC */
122 struct iso_directory_record *de;
124 if (filp->f_pos >= inode->i_size)
125 return 0;
127 offset = filp->f_pos & (bufsize - 1);
128 block = filp->f_pos >> bufbits;
129 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
131 while (filp->f_pos < inode->i_size) {
132 int de_len;
134 if (!bh) {
135 bh = isofs_bread(inode, bufsize, block);
136 if (!bh)
137 return 0;
140 de = (struct iso_directory_record *) (bh->b_data + offset);
141 if (first_de) inode_number = (bh->b_blocknr << bufbits) + (offset & (bufsize - 1));
143 de_len = *(unsigned char *) de;
144 #ifdef DEBUG
145 printk("de_len = %d\n", de_len);
146 #endif
148 /* If the length byte is zero, we should move on to the next
149 CDROM sector. If we are at the end of the directory, we
150 kick out of the while loop. */
152 if (de_len == 0) {
153 brelse(bh);
154 bh = NULL;
155 filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE);
156 block = filp->f_pos >> bufbits;
157 offset = 0;
158 continue;
161 offset += de_len;
162 if (offset == bufsize) {
163 offset = 0;
164 block++;
165 brelse(bh);
166 bh = NULL;
169 /* Make sure we have a full directory entry */
170 if (offset > bufsize) {
171 int slop = bufsize - offset + de_len;
172 memcpy(tmpde, de, slop);
173 offset &= bufsize - 1;
174 block++;
175 brelse(bh);
176 bh = isofs_bread(inode, bufsize, block);
177 if (!bh)
178 return 0;
179 memcpy((void *) tmpde + slop, bh->b_data, de_len - slop);
180 de = tmpde;
183 if (de->flags[-high_sierra] & 0x80) {
184 first_de = 0;
185 filp->f_pos += de_len;
186 continue;
188 first_de = 1;
190 /* Handle the case of the '.' directory */
191 if (de->name_len[0] == 1 && de->name[0] == 0) {
192 if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
193 break;
194 filp->f_pos += de_len;
195 continue;
198 len = 0;
200 /* Handle the case of the '..' directory */
201 if (de->name_len[0] == 1 && de->name[0] == 1) {
202 inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
203 if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
204 break;
205 filp->f_pos += de_len;
206 continue;
209 /* Handle everything else. Do name translation if there
210 is no Rock Ridge NM field. */
211 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
212 /* Do not report hidden or associated files */
213 if (de->flags[-high_sierra] & 5) {
214 filp->f_pos += de_len;
215 continue;
219 map = 1;
220 if (inode->i_sb->u.isofs_sb.s_rock) {
221 len = get_rock_ridge_filename(de, tmpname, inode);
222 if (len != 0) {
223 p = tmpname;
224 map = 0;
227 if (map) {
228 #ifdef CONFIG_JOLIET
229 if (inode->i_sb->u.isofs_sb.s_joliet_level) {
230 len = get_joliet_filename(de, inode, tmpname);
231 p = tmpname;
232 } else
233 #endif
234 if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
235 len = get_acorn_filename(de, tmpname, inode);
236 p = tmpname;
237 } else
238 if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
239 len = isofs_name_translate(de->name,
240 de->name_len[0], tmpname);
241 p = tmpname;
242 } else {
243 p = de->name;
244 len = de->name_len[0];
247 if (len > 0) {
248 if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
249 break;
251 filp->f_pos += de_len;
253 continue;
255 brelse(bh);
256 return 0;
260 * Handle allocation of temporary space for name translation and
261 * handling split directory entries.. The real work is done by
262 * "do_isofs_readdir()".
264 static int isofs_readdir(struct file *filp,
265 void *dirent, filldir_t filldir)
267 int result;
268 char * tmpname;
269 struct iso_directory_record * tmpde;
270 struct inode *inode = filp->f_dentry->d_inode;
272 tmpname = (char *) __get_free_page(GFP_KERNEL);
273 if (!tmpname)
274 return -ENOMEM;
275 tmpde = (struct iso_directory_record *) (tmpname+1024);
277 result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
279 free_page((unsigned long) tmpname);
280 return result;