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/slab.h>
21 #include <linux/time.h>
22 #include <linux/config.h>
23 #include <linux/smp_lock.h>
24 #include <linux/buffer_head.h>
26 #include <asm/uaccess.h>
28 static int isofs_readdir(struct file
*, void *, filldir_t
);
30 struct file_operations isofs_dir_operations
=
32 .read
= generic_read_dir
,
33 .readdir
= isofs_readdir
,
37 * directories can handle most operations...
39 struct inode_operations isofs_dir_inode_operations
=
41 .lookup
= isofs_lookup
,
44 int isofs_name_translate(struct iso_directory_record
*de
, char *new, struct inode
*inode
)
46 char * old
= de
->name
;
47 int len
= de
->name_len
[0];
50 for (i
= 0; i
< len
; i
++) {
51 unsigned char c
= old
[i
];
55 if (c
>= 'A' && c
<= 'Z')
56 c
|= 0x20; /* lower case */
58 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
59 if (c
== '.' && i
== len
- 3 && old
[i
+ 1] == ';' && old
[i
+ 2] == '1')
62 /* Drop trailing ';1' */
63 if (c
== ';' && i
== len
- 2 && old
[i
+ 1] == '1')
66 /* Convert remaining ';' to '.' */
67 /* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
68 if (c
== ';' || c
== '/')
76 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
77 int get_acorn_filename(struct iso_directory_record
* de
,
78 char * retname
, struct inode
* inode
)
82 int retnamlen
= isofs_name_translate(de
, retname
, inode
);
83 if (retnamlen
== 0) return 0;
84 std
= sizeof(struct iso_directory_record
) + de
->name_len
[0];
86 if ((*((unsigned char *) de
) - std
) != 32) return retnamlen
;
87 chr
= ((unsigned char *) de
) + std
;
88 if (strncmp(chr
, "ARCHIMEDES", 10)) return retnamlen
;
89 if ((*retname
== '_') && ((chr
[19] & 1) == 1)) *retname
= '!';
90 if (((de
->flags
[0] & 2) == 0) && (chr
[13] == 0xff)
91 && ((chr
[12] & 0xf0) == 0xf0))
93 retname
[retnamlen
] = ',';
94 sprintf(retname
+retnamlen
+1, "%3.3x",
95 ((chr
[12] & 0xf) << 8) | chr
[11]);
102 * This should _really_ be cleaned up some day..
104 static int do_isofs_readdir(struct inode
*inode
, struct file
*filp
,
105 void *dirent
, filldir_t filldir
,
106 char * tmpname
, struct iso_directory_record
* tmpde
)
108 unsigned long bufsize
= ISOFS_BUFFER_SIZE(inode
);
109 unsigned char bufbits
= ISOFS_BUFFER_BITS(inode
);
110 unsigned long block
, offset
, block_saved
, offset_saved
;
111 unsigned long inode_number
= 0; /* Quiet GCC */
112 struct buffer_head
*bh
= NULL
;
116 char *p
= NULL
; /* Quiet GCC */
117 struct iso_directory_record
*de
;
118 struct isofs_sb_info
*sbi
= ISOFS_SB(inode
->i_sb
);
120 offset
= filp
->f_pos
& (bufsize
- 1);
121 block
= filp
->f_pos
>> bufbits
;
123 while (filp
->f_pos
< inode
->i_size
) {
127 bh
= isofs_bread(inode
, block
);
132 de
= (struct iso_directory_record
*) (bh
->b_data
+ offset
);
134 de_len
= *(unsigned char *) de
;
136 /* If the length byte is zero, we should move on to the next
137 CDROM sector. If we are at the end of the directory, we
138 kick out of the while loop. */
143 filp
->f_pos
= (filp
->f_pos
+ ISOFS_BLOCK_SIZE
) & ~(ISOFS_BLOCK_SIZE
- 1);
144 block
= filp
->f_pos
>> bufbits
;
150 offset_saved
= offset
;
153 /* Make sure we have a full directory entry */
154 if (offset
>= bufsize
) {
155 int slop
= bufsize
- offset
+ de_len
;
156 memcpy(tmpde
, de
, slop
);
157 offset
&= bufsize
- 1;
162 bh
= isofs_bread(inode
, block
);
165 memcpy((void *) tmpde
+ slop
, bh
->b_data
, offset
);
171 isofs_normalize_block_and_offset(de
,
174 inode_number
= isofs_get_ino(block_saved
,
179 if (de
->flags
[-sbi
->s_high_sierra
] & 0x80) {
181 filp
->f_pos
+= de_len
;
186 /* Handle the case of the '.' directory */
187 if (de
->name_len
[0] == 1 && de
->name
[0] == 0) {
188 if (filldir(dirent
, ".", 1, filp
->f_pos
, inode
->i_ino
, DT_DIR
) < 0)
190 filp
->f_pos
+= de_len
;
196 /* Handle the case of the '..' directory */
197 if (de
->name_len
[0] == 1 && de
->name
[0] == 1) {
198 inode_number
= parent_ino(filp
->f_dentry
);
199 if (filldir(dirent
, "..", 2, filp
->f_pos
, inode_number
, DT_DIR
) < 0)
201 filp
->f_pos
+= de_len
;
205 /* Handle everything else. Do name translation if there
206 is no Rock Ridge NM field. */
207 if (sbi
->s_unhide
== 'n') {
208 /* Do not report hidden or associated files */
209 if (de
->flags
[-sbi
->s_high_sierra
] & 5) {
210 filp
->f_pos
+= de_len
;
217 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
218 if (len
!= 0) { /* may be -1 */
225 if (sbi
->s_joliet_level
) {
226 len
= get_joliet_filename(de
, tmpname
, inode
);
230 if (sbi
->s_mapping
== 'a') {
231 len
= get_acorn_filename(de
, tmpname
, inode
);
234 if (sbi
->s_mapping
== 'n') {
235 len
= isofs_name_translate(de
, tmpname
, inode
);
239 len
= de
->name_len
[0];
243 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
, DT_UNKNOWN
) < 0)
246 filp
->f_pos
+= de_len
;
255 * Handle allocation of temporary space for name translation and
256 * handling split directory entries.. The real work is done by
257 * "do_isofs_readdir()".
259 static int isofs_readdir(struct file
*filp
,
260 void *dirent
, filldir_t filldir
)
264 struct iso_directory_record
* tmpde
;
265 struct inode
*inode
= filp
->f_dentry
->d_inode
;
268 tmpname
= (char *)__get_free_page(GFP_KERNEL
);
273 tmpde
= (struct iso_directory_record
*) (tmpname
+1024);
275 result
= do_isofs_readdir(inode
, filp
, dirent
, filldir
, tmpname
, tmpde
);
277 free_page((unsigned long) tmpname
);