Import 2.1.55pre1
[davej-history.git] / fs / isofs / dir.c
bloba198141d8f620eb9c18fb33c080137a9d506fbc0
1 /*
2 * linux/fs/isofs/dir.c
4 * (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 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>
24 #include <asm/uaccess.h>
26 static int isofs_readdir(struct file *, void *, filldir_t);
28 static struct file_operations isofs_dir_operations =
30 NULL, /* lseek - default */
31 NULL, /* read */
32 NULL, /* write - bad */
33 isofs_readdir, /* readdir */
34 NULL, /* poll - default */
35 NULL, /* ioctl - default */
36 NULL, /* no special open code */
37 NULL, /* no special release code */
38 NULL /* fsync */
42 * directories can handle most operations...
44 struct inode_operations isofs_dir_inode_operations =
46 &isofs_dir_operations, /* default directory file-ops */
47 NULL, /* create */
48 isofs_lookup, /* lookup */
49 NULL, /* link */
50 NULL, /* unlink */
51 NULL, /* symlink */
52 NULL, /* mkdir */
53 NULL, /* rmdir */
54 NULL, /* mknod */
55 NULL, /* rename */
56 NULL, /* readlink */
57 NULL, /* follow_link */
58 NULL, /* readpage */
59 NULL, /* writepage */
60 isofs_bmap, /* bmap */
61 NULL, /* truncate */
62 NULL /* permission */
65 static int isofs_name_translate(char * old, int len, char * new)
67 int i, c;
69 for (i = 0; i < len; i++) {
70 c = old[i];
71 if (!c)
72 break;
73 if (c >= 'A' && c <= 'Z')
74 c |= 0x20; /* lower case */
76 /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
77 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
78 break;
80 /* Drop trailing ';1' */
81 if (c == ';' && i == len - 2 && old[i + 1] == '1')
82 break;
84 /* Convert remaining ';' to '.' */
85 if (c == ';')
86 c = '.';
88 new[i] = c;
90 return i;
94 * This should _really_ be cleaned up some day..
96 static int do_isofs_readdir(struct inode *inode, struct file *filp,
97 void *dirent, filldir_t filldir,
98 char * tmpname, struct iso_directory_record * tmpde)
100 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
101 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
102 unsigned int block, offset;
103 int inode_number;
104 struct buffer_head *bh;
105 int len, rrflag;
106 int high_sierra = 0;
107 char *name;
108 struct iso_directory_record *de;
110 if( filp->f_pos >= inode->i_size ) {
111 return 0;
115 offset = filp->f_pos & (bufsize - 1);
116 block = isofs_bmap(inode, filp->f_pos >> bufbits);
118 if (!block)
119 return 0;
121 if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
122 return 0;
124 while (filp->f_pos < inode->i_size) {
125 int de_len;
126 #ifdef DEBUG
127 printk("Block, offset, f_pos: %x %x %x\n",
128 block, offset, filp->f_pos);
129 printk("inode->i_size = %x\n",inode->i_size);
130 #endif
131 de = (struct iso_directory_record *) (bh->b_data + offset);
132 inode_number = (block << bufbits) + (offset & (bufsize - 1));
134 de_len = *(unsigned char *) de;
135 #ifdef DEBUG
136 printk("de_len = %ld\n", de_len);
137 #endif
140 /* If the length byte is zero, we should move on to the next
141 CDROM sector. If we are at the end of the directory, we
142 kick out of the while loop. */
144 if ((de_len == 0) || (offset == bufsize) ) {
145 brelse(bh);
146 filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
147 + ISOFS_BLOCK_SIZE);
148 offset = 0;
149 if( filp->f_pos >= inode->i_size )
151 return 0;
154 block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
155 if (!block)
156 return 0;
157 bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
158 if (!bh)
159 return 0;
160 continue;
163 offset += de_len;
164 if (offset > bufsize) {
166 * This would only normally happen if we had
167 * a buggy cdrom image. All directory
168 * entries should terminate with a null size
169 * or end exactly at the end of the sector.
171 printk("next_offset (%x) > bufsize (%lx)\n",
172 offset,bufsize);
173 break;
176 /* Handle the case of the '.' directory */
177 if (de->name_len[0] == 1 && de->name[0] == 0) {
178 if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
179 break;
180 filp->f_pos += de_len;
181 continue;
184 /* Handle the case of the '..' directory */
185 if (de->name_len[0] == 1 && de->name[0] == 1) {
186 inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
187 if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
188 break;
189 filp->f_pos += de_len;
190 continue;
193 /* Handle everything else. Do name translation if there
194 is no Rock Ridge NM field. */
196 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
197 /* Do not report hidden or associated files */
198 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
199 if (de->flags[-high_sierra] & 5) {
200 filp->f_pos += de_len;
201 continue;
205 /* Check Rock Ridge name translation.. */
206 len = de->name_len[0];
207 name = de->name;
208 rrflag = get_rock_ridge_filename(de, &name, &len, inode);
209 if (rrflag) {
210 /* rrflag == 1 means that we have a new name (kmalloced) */
211 if (rrflag == 1) {
212 rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
213 kfree(name); /* this was allocated in get_r_r_filename.. */
214 if (rrflag < 0)
215 break;
217 filp->f_pos += de_len;
218 continue;
221 if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
222 len = isofs_name_translate(name, len, tmpname);
223 if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
224 break;
225 filp->f_pos += de_len;
226 continue;
229 if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
230 break;
232 filp->f_pos += de_len;
233 continue;
235 brelse(bh);
236 return 0;
240 * Handle allocation of temporary space for name translation and
241 * handling split directory entries.. The real work is done by
242 * "do_isofs_readdir()".
244 static int isofs_readdir(struct file *filp,
245 void *dirent, filldir_t filldir)
247 int result;
248 char * tmpname;
249 struct iso_directory_record * tmpde;
250 struct inode *inode = filp->f_dentry->d_inode;
252 if (!inode || !S_ISDIR(inode->i_mode))
253 return -EBADF;
255 tmpname = (char *) __get_free_page(GFP_KERNEL);
256 if (!tmpname)
257 return -ENOMEM;
258 tmpde = (struct iso_directory_record *) (tmpname+256);
260 result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
262 free_page((unsigned long) tmpname);
263 return result;