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>
15 #include <linux/iso_fs.h>
16 #include <linux/kernel.h>
17 #include <linux/stat.h>
18 #include <linux/string.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 */
33 NULL
, /* write - bad */
34 isofs_readdir
, /* readdir */
35 NULL
, /* poll - default */
36 NULL
, /* ioctl - default */
37 NULL
, /* no special open code */
39 NULL
, /* no special release code */
44 * directories can handle most operations...
46 struct inode_operations isofs_dir_inode_operations
=
48 &isofs_dir_operations
, /* default directory file-ops */
50 isofs_lookup
, /* lookup */
59 NULL
, /* follow_link */
65 NULL
, /* permission */
70 static int isofs_name_translate(char * old
, int len
, char * new)
74 for (i
= 0; i
< len
; i
++) {
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')
85 /* Drop trailing ';1' */
86 if (c
== ';' && i
== len
- 2 && old
[i
+ 1] == '1')
89 /* Convert remaining ';' to '.' */
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
)
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];
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]);
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
;
140 char *p
= NULL
; /* Quiet GCC */
141 struct iso_directory_record
*de
;
143 if (filp
->f_pos
>= inode
->i_size
)
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
;
153 if (!(bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
)))
156 while (filp
->f_pos
< inode
->i_size
) {
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
);
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
;
168 printk("de_len = %ld\n", de_len
);
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
) ) {
179 filp
->f_pos
= ((filp
->f_pos
& ~(ISOFS_BLOCK_SIZE
- 1))
184 filp
->f_pos
+= offset
;
187 if (filp
->f_pos
>= inode
->i_size
)
190 block
= isofs_bmap(inode
, (filp
->f_pos
) >> bufbits
);
193 bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
);
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",
212 if(de
->flags
[-high_sierra
] & 0x80) {
214 filp
->f_pos
+= de_len
;
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)
223 filp
->f_pos
+= de_len
;
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)
234 filp
->f_pos
+= de_len
;
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
;
249 if (inode
->i_sb
->u
.isofs_sb
.s_rock
) {
250 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
258 if (inode
->i_sb
->u
.isofs_sb
.s_joliet_level
) {
259 len
= get_joliet_filename(de
, inode
, tmpname
);
263 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'a') {
264 len
= get_acorn_filename(de
, tmpname
, inode
);
267 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'n') {
268 len
= isofs_name_translate(de
->name
,
269 de
->name_len
[0], tmpname
);
273 len
= de
->name_len
[0];
277 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
) < 0)
280 filp
->f_pos
+= de_len
;
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
)
298 struct iso_directory_record
* tmpde
;
299 struct inode
*inode
= filp
->f_dentry
->d_inode
;
301 tmpname
= (char *) __get_free_page(GFP_KERNEL
);
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
);