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 static struct file_operations isofs_dir_operations
=
31 NULL
, /* lseek - default */
33 NULL
, /* write - bad */
34 isofs_readdir
, /* readdir */
35 NULL
, /* poll - default */
36 NULL
, /* ioctl - default */
37 NULL
, /* no special open code */
39 NULL
, /* no special release code */
44 * directories can handle most operations...
46 struct inode_operations isofs_dir_inode_operations
=
48 &isofs_dir_operations
, /* default directory file-ops */
50 isofs_lookup
, /* lookup */
59 NULL
, /* follow_link */
67 static int isofs_name_translate(char * old
, int len
, char * new)
71 for (i
= 0; i
< len
; i
++) {
75 if (c
>= 'A' && c
<= 'Z')
76 c
|= 0x20; /* lower case */
78 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
79 if (c
== '.' && i
== len
- 3 && old
[i
+ 1] == ';' && old
[i
+ 2] == '1')
82 /* Drop trailing ';1' */
83 if (c
== ';' && i
== len
- 2 && old
[i
+ 1] == '1')
86 /* Convert remaining ';' to '.' */
95 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
96 int get_acorn_filename(struct iso_directory_record
* de
,
97 char * retname
, struct inode
* inode
)
101 int retnamlen
= isofs_name_translate(de
->name
,
102 de
->name_len
[0], retname
);
103 if (retnamlen
== 0) return 0;
104 std
= sizeof(struct iso_directory_record
) + de
->name_len
[0];
106 if ((*((unsigned char *) de
) - std
) != 32) return retnamlen
;
107 chr
= ((unsigned char *) de
) + std
;
108 if (strncmp(chr
, "ARCHIMEDES", 10)) return retnamlen
;
109 if ((*retname
== '_') && ((chr
[19] & 1) == 1)) *retname
= '!';
110 if (((de
->flags
[0] & 2) == 0) && (chr
[13] == 0xff)
111 && ((chr
[12] & 0xf0) == 0xf0))
113 retname
[retnamlen
] = ',';
114 sprintf(retname
+retnamlen
+1, "%3.3x",
115 ((chr
[12] & 0xf) << 8) | chr
[11]);
122 * This should _really_ be cleaned up some day..
124 static int do_isofs_readdir(struct inode
*inode
, struct file
*filp
,
125 void *dirent
, filldir_t filldir
,
126 char * tmpname
, struct iso_directory_record
* tmpde
)
128 unsigned long bufsize
= ISOFS_BUFFER_SIZE(inode
);
129 unsigned char bufbits
= ISOFS_BUFFER_BITS(inode
);
130 unsigned int block
, offset
;
131 int inode_number
= 0; /* Quiet GCC */
132 struct buffer_head
*bh
;
137 char *p
= NULL
; /* Quiet GCC */
138 struct iso_directory_record
*de
;
140 if (filp
->f_pos
>= inode
->i_size
)
143 offset
= filp
->f_pos
& (bufsize
- 1);
144 block
= isofs_bmap(inode
, filp
->f_pos
>> bufbits
);
145 high_sierra
= inode
->i_sb
->u
.isofs_sb
.s_high_sierra
;
150 if (!(bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
)))
153 while (filp
->f_pos
< inode
->i_size
) {
156 printk("Block, offset, f_pos: %x %x %x\n",
157 block
, offset
, filp
->f_pos
);
158 printk("inode->i_size = %x\n",inode
->i_size
);
160 de
= (struct iso_directory_record
*) (bh
->b_data
+ offset
);
161 if(first_de
) inode_number
= (block
<< bufbits
) + (offset
& (bufsize
- 1));
163 de_len
= *(unsigned char *) de
;
165 printk("de_len = %ld\n", de_len
);
169 /* If the length byte is zero, we should move on to the next
170 CDROM sector. If we are at the end of the directory, we
171 kick out of the while loop. */
173 if ((de_len
== 0) || (offset
>= bufsize
) ) {
176 filp
->f_pos
= ((filp
->f_pos
& ~(ISOFS_BLOCK_SIZE
- 1))
181 filp
->f_pos
+= offset
;
184 if (filp
->f_pos
>= inode
->i_size
)
187 block
= isofs_bmap(inode
, (filp
->f_pos
) >> bufbits
);
190 bh
= breada(inode
->i_dev
, block
, bufsize
, filp
->f_pos
, inode
->i_size
);
197 if (offset
> bufsize
) {
199 * This would only normally happen if we had
200 * a buggy cdrom image. All directory
201 * entries should terminate with a null size
202 * or end exactly at the end of the sector.
204 printk("next_offset (%x) > bufsize (%lx)\n",
209 if(de
->flags
[-high_sierra
] & 0x80) {
211 filp
->f_pos
+= de_len
;
216 /* Handle the case of the '.' directory */
217 if (de
->name_len
[0] == 1 && de
->name
[0] == 0) {
218 if (filldir(dirent
, ".", 1, filp
->f_pos
, inode
->i_ino
) < 0)
220 filp
->f_pos
+= de_len
;
226 /* Handle the case of the '..' directory */
227 if (de
->name_len
[0] == 1 && de
->name
[0] == 1) {
228 inode_number
= filp
->f_dentry
->d_parent
->d_inode
->i_ino
;
229 if (filldir(dirent
, "..", 2, filp
->f_pos
, inode_number
) < 0)
231 filp
->f_pos
+= de_len
;
235 /* Handle everything else. Do name translation if there
236 is no Rock Ridge NM field. */
237 if (inode
->i_sb
->u
.isofs_sb
.s_unhide
== 'n') {
238 /* Do not report hidden or associated files */
239 if (de
->flags
[-high_sierra
] & 5) {
240 filp
->f_pos
+= de_len
;
246 if (inode
->i_sb
->u
.isofs_sb
.s_rock
) {
247 len
= get_rock_ridge_filename(de
, tmpname
, inode
);
255 if (inode
->i_sb
->u
.isofs_sb
.s_joliet_level
) {
256 len
= get_joliet_filename(de
, inode
, tmpname
);
260 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'a') {
261 len
= get_acorn_filename(de
, tmpname
, inode
);
264 if (inode
->i_sb
->u
.isofs_sb
.s_mapping
== 'n') {
265 len
= isofs_name_translate(de
->name
,
266 de
->name_len
[0], tmpname
);
270 len
= de
->name_len
[0];
274 if (filldir(dirent
, p
, len
, filp
->f_pos
, inode_number
) < 0)
277 filp
->f_pos
+= de_len
;
286 * Handle allocation of temporary space for name translation and
287 * handling split directory entries.. The real work is done by
288 * "do_isofs_readdir()".
290 static int isofs_readdir(struct file
*filp
,
291 void *dirent
, filldir_t filldir
)
295 struct iso_directory_record
* tmpde
;
296 struct inode
*inode
= filp
->f_dentry
->d_inode
;
298 tmpname
= (char *) __get_free_page(GFP_KERNEL
);
301 tmpde
= (struct iso_directory_record
*) (tmpname
+1024);
303 result
= do_isofs_readdir(inode
, filp
, dirent
, filldir
, tmpname
, tmpde
);
305 free_page((unsigned long) tmpname
);