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]);
97 static struct buffer_head
*isofs_bread(struct inode
*inode
, unsigned int bufsize
, unsigned int block
)
99 unsigned int blknr
= isofs_bmap(inode
, block
);
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
;
121 char *p
= NULL
; /* Quiet GCC */
122 struct iso_directory_record
*de
;
124 if (filp
->f_pos
>= inode
->i_size
)
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
) {
135 bh
= isofs_bread(inode
, bufsize
, block
);
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
;
145 printk("de_len = %d\n", de_len
);
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. */
155 filp
->f_pos
= ((filp
->f_pos
& ~(ISOFS_BLOCK_SIZE
- 1)) + ISOFS_BLOCK_SIZE
);
156 block
= filp
->f_pos
>> bufbits
;
162 if (offset
== bufsize
) {
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;
176 bh
= isofs_bread(inode
, bufsize
, block
);
179 memcpy((void *) tmpde
+ slop
, bh
->b_data
, de_len
- slop
);
183 if (de
->flags
[-high_sierra
] & 0x80) {
185 filp
->f_pos
+= de_len
;
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)
194 filp
->f_pos
+= de_len
;
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)
205 filp
->f_pos
+= de_len
;
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
;
220 if (inode
->i_sb
->u
.isofs_sb
.s_rock
) {
221 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
229 if (inode
->i_sb
->u
.isofs_sb
.s_joliet_level
) {
230 len
= get_joliet_filename(de
, inode
, tmpname
);
234 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'a') {
235 len
= get_acorn_filename(de
, tmpname
, inode
);
238 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'n') {
239 len
= isofs_name_translate(de
->name
,
240 de
->name_len
[0], tmpname
);
244 len
= de
->name_len
[0];
248 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
, DT_UNKNOWN
) < 0)
251 filp
->f_pos
+= de_len
;
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
)
269 struct iso_directory_record
* tmpde
;
270 struct inode
*inode
= filp
->f_dentry
->d_inode
;
272 tmpname
= (char *) __get_free_page(GFP_KERNEL
);
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
);