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/config.h>
14 #include <linux/smp_lock.h>
17 static int isofs_readdir(struct file
*, void *, filldir_t
);
19 struct file_operations isofs_dir_operations
=
21 .read
= generic_read_dir
,
22 .readdir
= isofs_readdir
,
26 * directories can handle most operations...
28 struct inode_operations isofs_dir_inode_operations
=
30 .lookup
= isofs_lookup
,
33 int isofs_name_translate(struct iso_directory_record
*de
, char *new, struct inode
*inode
)
35 char * old
= de
->name
;
36 int len
= de
->name_len
[0];
39 for (i
= 0; i
< len
; i
++) {
40 unsigned char c
= old
[i
];
44 if (c
>= 'A' && c
<= 'Z')
45 c
|= 0x20; /* lower case */
47 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
48 if (c
== '.' && i
== len
- 3 && old
[i
+ 1] == ';' && old
[i
+ 2] == '1')
51 /* Drop trailing ';1' */
52 if (c
== ';' && i
== len
- 2 && old
[i
+ 1] == '1')
55 /* Convert remaining ';' to '.' */
56 /* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
57 if (c
== ';' || c
== '/')
65 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
66 int get_acorn_filename(struct iso_directory_record
* de
,
67 char * retname
, struct inode
* inode
)
71 int retnamlen
= isofs_name_translate(de
, retname
, inode
);
72 if (retnamlen
== 0) return 0;
73 std
= sizeof(struct iso_directory_record
) + de
->name_len
[0];
75 if ((*((unsigned char *) de
) - std
) != 32) return retnamlen
;
76 chr
= ((unsigned char *) de
) + std
;
77 if (strncmp(chr
, "ARCHIMEDES", 10)) return retnamlen
;
78 if ((*retname
== '_') && ((chr
[19] & 1) == 1)) *retname
= '!';
79 if (((de
->flags
[0] & 2) == 0) && (chr
[13] == 0xff)
80 && ((chr
[12] & 0xf0) == 0xf0))
82 retname
[retnamlen
] = ',';
83 sprintf(retname
+retnamlen
+1, "%3.3x",
84 ((chr
[12] & 0xf) << 8) | chr
[11]);
91 * This should _really_ be cleaned up some day..
93 static int do_isofs_readdir(struct inode
*inode
, struct file
*filp
,
94 void *dirent
, filldir_t filldir
,
95 char * tmpname
, struct iso_directory_record
* tmpde
)
97 unsigned long bufsize
= ISOFS_BUFFER_SIZE(inode
);
98 unsigned char bufbits
= ISOFS_BUFFER_BITS(inode
);
99 unsigned long block
, offset
, block_saved
, offset_saved
;
100 unsigned long inode_number
= 0; /* Quiet GCC */
101 struct buffer_head
*bh
= NULL
;
105 char *p
= NULL
; /* Quiet GCC */
106 struct iso_directory_record
*de
;
107 struct isofs_sb_info
*sbi
= ISOFS_SB(inode
->i_sb
);
109 offset
= filp
->f_pos
& (bufsize
- 1);
110 block
= filp
->f_pos
>> bufbits
;
112 while (filp
->f_pos
< inode
->i_size
) {
116 bh
= isofs_bread(inode
, block
);
121 de
= (struct iso_directory_record
*) (bh
->b_data
+ offset
);
123 de_len
= *(unsigned char *) de
;
125 /* If the length byte is zero, we should move on to the next
126 CDROM sector. If we are at the end of the directory, we
127 kick out of the while loop. */
132 filp
->f_pos
= (filp
->f_pos
+ ISOFS_BLOCK_SIZE
) & ~(ISOFS_BLOCK_SIZE
- 1);
133 block
= filp
->f_pos
>> bufbits
;
139 offset_saved
= offset
;
142 /* Make sure we have a full directory entry */
143 if (offset
>= bufsize
) {
144 int slop
= bufsize
- offset
+ de_len
;
145 memcpy(tmpde
, de
, slop
);
146 offset
&= bufsize
- 1;
151 bh
= isofs_bread(inode
, block
);
154 memcpy((void *) tmpde
+ slop
, bh
->b_data
, offset
);
160 isofs_normalize_block_and_offset(de
,
163 inode_number
= isofs_get_ino(block_saved
,
168 if (de
->flags
[-sbi
->s_high_sierra
] & 0x80) {
170 filp
->f_pos
+= de_len
;
175 /* Handle the case of the '.' directory */
176 if (de
->name_len
[0] == 1 && de
->name
[0] == 0) {
177 if (filldir(dirent
, ".", 1, filp
->f_pos
, inode
->i_ino
, DT_DIR
) < 0)
179 filp
->f_pos
+= de_len
;
185 /* Handle the case of the '..' directory */
186 if (de
->name_len
[0] == 1 && de
->name
[0] == 1) {
187 inode_number
= parent_ino(filp
->f_dentry
);
188 if (filldir(dirent
, "..", 2, filp
->f_pos
, inode_number
, DT_DIR
) < 0)
190 filp
->f_pos
+= de_len
;
194 /* Handle everything else. Do name translation if there
195 is no Rock Ridge NM field. */
196 if (sbi
->s_unhide
== 'n') {
197 /* Do not report hidden or associated files */
198 if (de
->flags
[-sbi
->s_high_sierra
] & 5) {
199 filp
->f_pos
+= de_len
;
206 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
207 if (len
!= 0) { /* may be -1 */
214 if (sbi
->s_joliet_level
) {
215 len
= get_joliet_filename(de
, tmpname
, inode
);
219 if (sbi
->s_mapping
== 'a') {
220 len
= get_acorn_filename(de
, tmpname
, inode
);
223 if (sbi
->s_mapping
== 'n') {
224 len
= isofs_name_translate(de
, tmpname
, inode
);
228 len
= de
->name_len
[0];
232 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
, DT_UNKNOWN
) < 0)
235 filp
->f_pos
+= de_len
;
244 * Handle allocation of temporary space for name translation and
245 * handling split directory entries.. The real work is done by
246 * "do_isofs_readdir()".
248 static int isofs_readdir(struct file
*filp
,
249 void *dirent
, filldir_t filldir
)
253 struct iso_directory_record
* tmpde
;
254 struct inode
*inode
= filp
->f_dentry
->d_inode
;
257 tmpname
= (char *)__get_free_page(GFP_KERNEL
);
262 tmpde
= (struct iso_directory_record
*) (tmpname
+1024);
264 result
= do_isofs_readdir(inode
, filp
, dirent
, filldir
, tmpname
, tmpde
);
266 free_page((unsigned long) tmpname
);