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 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
=
43 static int isofs_name_translate(char * old
, int len
, char * new)
47 for (i
= 0; i
< len
; i
++) {
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')
58 /* Drop trailing ';1' */
59 if (c
== ';' && i
== len
- 2 && old
[i
+ 1] == '1')
62 /* Convert remaining ';' to '.' */
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
)
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];
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]);
98 * This should _really_ be cleaned up some day..
100 static int do_isofs_readdir(struct inode
*inode
, struct file
*filp
,
101 void *dirent
, filldir_t filldir
,
102 char * tmpname
, struct iso_directory_record
* tmpde
)
104 unsigned long bufsize
= ISOFS_BUFFER_SIZE(inode
);
105 unsigned char bufbits
= ISOFS_BUFFER_BITS(inode
);
106 unsigned int block
, offset
;
107 int inode_number
= 0; /* Quiet GCC */
108 struct buffer_head
*bh
;
113 char *p
= NULL
; /* Quiet GCC */
114 struct iso_directory_record
*de
;
116 if (filp
->f_pos
>= inode
->i_size
)
119 offset
= filp
->f_pos
& (bufsize
- 1);
120 block
= isofs_bmap(inode
, filp
->f_pos
>> bufbits
);
121 high_sierra
= inode
->i_sb
->u
.isofs_sb
.s_high_sierra
;
126 if (!(bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
)))
129 while (filp
->f_pos
< inode
->i_size
) {
132 printk("Block, offset, f_pos: %x %x %x\n",
133 block
, offset
, filp
->f_pos
);
134 printk("inode->i_size = %x\n",inode
->i_size
);
136 /* Next directory_record on next CDROM sector */
137 if (offset
>= bufsize
) {
139 printk("offset >= bufsize\n");
143 block
= isofs_bmap(inode
, (filp
->f_pos
) >> bufbits
);
146 bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
);
152 de
= (struct iso_directory_record
*) (bh
->b_data
+ offset
);
153 if(first_de
) inode_number
= (block
<< bufbits
) + (offset
& (bufsize
- 1));
155 de_len
= *(unsigned char *) de
;
157 printk("de_len = %d\n", de_len
);
161 /* If the length byte is zero, we should move on to the next
162 CDROM sector. If we are at the end of the directory, we
163 kick out of the while loop. */
167 filp
->f_pos
= ((filp
->f_pos
& ~(ISOFS_BLOCK_SIZE
- 1))
171 if (filp
->f_pos
>= inode
->i_size
)
174 block
= isofs_bmap(inode
, (filp
->f_pos
) >> bufbits
);
177 bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
);
184 if (offset
> bufsize
) {
186 * This would only normally happen if we had
187 * a buggy cdrom image. All directory
188 * entries should terminate with a null size
189 * or end exactly at the end of the sector.
191 printk("next_offset (%x) > bufsize (%lx)\n",
196 if(de
->flags
[-high_sierra
] & 0x80) {
198 filp
->f_pos
+= de_len
;
203 /* Handle the case of the '.' directory */
204 if (de
->name_len
[0] == 1 && de
->name
[0] == 0) {
205 if (filldir(dirent
, ".", 1, filp
->f_pos
, inode
->i_ino
) < 0)
207 filp
->f_pos
+= de_len
;
213 /* Handle the case of the '..' directory */
214 if (de
->name_len
[0] == 1 && de
->name
[0] == 1) {
215 inode_number
= filp
->f_dentry
->d_parent
->d_inode
->i_ino
;
216 if (filldir(dirent
, "..", 2, filp
->f_pos
, inode_number
) < 0)
218 filp
->f_pos
+= de_len
;
222 /* Handle everything else. Do name translation if there
223 is no Rock Ridge NM field. */
224 if (inode
->i_sb
->u
.isofs_sb
.s_unhide
== 'n') {
225 /* Do not report hidden or associated files */
226 if (de
->flags
[-high_sierra
] & 5) {
227 filp
->f_pos
+= de_len
;
233 if (inode
->i_sb
->u
.isofs_sb
.s_rock
) {
234 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
242 if (inode
->i_sb
->u
.isofs_sb
.s_joliet_level
) {
243 len
= get_joliet_filename(de
, inode
, tmpname
);
247 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'a') {
248 len
= get_acorn_filename(de
, tmpname
, inode
);
251 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'n') {
252 len
= isofs_name_translate(de
->name
,
253 de
->name_len
[0], tmpname
);
257 len
= de
->name_len
[0];
261 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
) < 0)
264 filp
->f_pos
+= de_len
;
273 * Handle allocation of temporary space for name translation and
274 * handling split directory entries.. The real work is done by
275 * "do_isofs_readdir()".
277 static int isofs_readdir(struct file
*filp
,
278 void *dirent
, filldir_t filldir
)
282 struct iso_directory_record
* tmpde
;
283 struct inode
*inode
= filp
->f_dentry
->d_inode
;
285 tmpname
= (char *) __get_free_page(GFP_KERNEL
);
288 tmpde
= (struct iso_directory_record
*) (tmpname
+1024);
290 result
= do_isofs_readdir(inode
, filp
, dirent
, filldir
, tmpname
, tmpde
);
292 free_page((unsigned long) tmpname
);