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 int isofs_name_translate(struct iso_directory_record
*de
, char *new, struct inode
*inode
)
45 char * old
= de
->name
;
46 int len
= de
->name_len
[0];
49 for (i
= 0; i
< len
; i
++) {
50 unsigned char c
= old
[i
];
54 if (c
>= 'A' && c
<= 'Z')
55 c
|= 0x20; /* lower case */
57 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
58 if (c
== '.' && i
== len
- 3 && old
[i
+ 1] == ';' && old
[i
+ 2] == '1')
61 /* Drop trailing ';1' */
62 if (c
== ';' && i
== len
- 2 && old
[i
+ 1] == '1')
65 /* Convert remaining ';' to '.' */
74 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
75 int get_acorn_filename(struct iso_directory_record
* de
,
76 char * retname
, struct inode
* inode
)
80 int retnamlen
= isofs_name_translate(de
, retname
, inode
);
81 if (retnamlen
== 0) return 0;
82 std
= sizeof(struct iso_directory_record
) + de
->name_len
[0];
84 if ((*((unsigned char *) de
) - std
) != 32) return retnamlen
;
85 chr
= ((unsigned char *) de
) + std
;
86 if (strncmp(chr
, "ARCHIMEDES", 10)) return retnamlen
;
87 if ((*retname
== '_') && ((chr
[19] & 1) == 1)) *retname
= '!';
88 if (((de
->flags
[0] & 2) == 0) && (chr
[13] == 0xff)
89 && ((chr
[12] & 0xf0) == 0xf0))
91 retname
[retnamlen
] = ',';
92 sprintf(retname
+retnamlen
+1, "%3.3x",
93 ((chr
[12] & 0xf) << 8) | chr
[11]);
100 * This should _really_ be cleaned up some day..
102 static int do_isofs_readdir(struct inode
*inode
, struct file
*filp
,
103 void *dirent
, filldir_t filldir
,
104 char * tmpname
, struct iso_directory_record
* tmpde
)
106 unsigned long bufsize
= ISOFS_BUFFER_SIZE(inode
);
107 unsigned char bufbits
= ISOFS_BUFFER_BITS(inode
);
108 unsigned int block
, offset
;
109 int inode_number
= 0; /* Quiet GCC */
110 struct buffer_head
*bh
= NULL
;
115 char *p
= NULL
; /* Quiet GCC */
116 struct iso_directory_record
*de
;
118 offset
= filp
->f_pos
& (bufsize
- 1);
119 block
= filp
->f_pos
>> bufbits
;
120 high_sierra
= inode
->i_sb
->u
.isofs_sb
.s_high_sierra
;
122 while (filp
->f_pos
< inode
->i_size
) {
126 bh
= isofs_bread(inode
, bufsize
, block
);
131 de
= (struct iso_directory_record
*) (bh
->b_data
+ offset
);
133 inode_number
= (bh
->b_blocknr
<< bufbits
) + offset
;
135 de_len
= *(unsigned char *) de
;
137 /* If the length byte is zero, we should move on to the next
138 CDROM sector. If we are at the end of the directory, we
139 kick out of the while loop. */
144 filp
->f_pos
= (filp
->f_pos
+ ISOFS_BLOCK_SIZE
) & ~(ISOFS_BLOCK_SIZE
- 1);
145 block
= filp
->f_pos
>> bufbits
;
152 /* Make sure we have a full directory entry */
153 if (offset
>= bufsize
) {
154 int slop
= bufsize
- offset
+ de_len
;
155 memcpy(tmpde
, de
, slop
);
156 offset
&= bufsize
- 1;
161 bh
= isofs_bread(inode
, bufsize
, block
);
164 memcpy((void *) tmpde
+ slop
, bh
->b_data
, offset
);
169 if (de
->flags
[-high_sierra
] & 0x80) {
171 filp
->f_pos
+= de_len
;
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
, DT_DIR
) < 0)
180 filp
->f_pos
+= de_len
;
186 /* Handle the case of the '..' directory */
187 if (de
->name_len
[0] == 1 && de
->name
[0] == 1) {
188 inode_number
= filp
->f_dentry
->d_parent
->d_inode
->i_ino
;
189 if (filldir(dirent
, "..", 2, filp
->f_pos
, inode_number
, DT_DIR
) < 0)
191 filp
->f_pos
+= de_len
;
195 /* Handle everything else. Do name translation if there
196 is no Rock Ridge NM field. */
197 if (inode
->i_sb
->u
.isofs_sb
.s_unhide
== 'n') {
198 /* Do not report hidden or associated files */
199 if (de
->flags
[-high_sierra
] & 5) {
200 filp
->f_pos
+= de_len
;
206 if (inode
->i_sb
->u
.isofs_sb
.s_rock
) {
207 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
208 if (len
!= 0) { /* may be -1 */
215 if (inode
->i_sb
->u
.isofs_sb
.s_joliet_level
) {
216 len
= get_joliet_filename(de
, tmpname
, inode
);
220 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'a') {
221 len
= get_acorn_filename(de
, tmpname
, inode
);
224 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'n') {
225 len
= isofs_name_translate(de
, tmpname
, inode
);
229 len
= de
->name_len
[0];
233 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
, DT_UNKNOWN
) < 0)
236 filp
->f_pos
+= de_len
;
245 * Handle allocation of temporary space for name translation and
246 * handling split directory entries.. The real work is done by
247 * "do_isofs_readdir()".
249 static int isofs_readdir(struct file
*filp
,
250 void *dirent
, filldir_t filldir
)
254 struct iso_directory_record
* tmpde
;
255 struct inode
*inode
= filp
->f_dentry
->d_inode
;
257 tmpname
= (char *) __get_free_page(GFP_KERNEL
);
260 tmpde
= (struct iso_directory_record
*) (tmpname
+1024);
262 result
= do_isofs_readdir(inode
, filp
, dirent
, filldir
, tmpname
, tmpde
);
264 free_page((unsigned long) tmpname
);