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/smp_lock.h>
16 static int isofs_readdir(struct file *, void *, filldir_t);
18 const struct file_operations isofs_dir_operations =
20 .read = generic_read_dir,
21 .readdir = isofs_readdir,
25 * directories can handle most operations...
27 const struct inode_operations isofs_dir_inode_operations =
29 .lookup = isofs_lookup,
32 int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
34 char * old = de->name;
35 int len = de->name_len[0];
38 for (i = 0; i < len; i++) {
39 unsigned char c = old[i];
43 if (c >= 'A' && c <= 'Z')
44 c |= 0x20; /* lower case */
46 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
47 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
50 /* Drop trailing ';1' */
51 if (c == ';' && i == len - 2 && old[i + 1] == '1')
54 /* Convert remaining ';' to '.' */
55 /* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
56 if (c == ';' || c == '/')
64 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
65 int get_acorn_filename(struct iso_directory_record * de,
66 char * retname, struct inode * inode)
70 int retnamlen = isofs_name_translate(de, retname, inode);
71 if (retnamlen == 0) return 0;
72 std = sizeof(struct iso_directory_record) + de->name_len[0];
74 if ((*((unsigned char *) de) - std) != 32) return retnamlen;
75 chr = ((unsigned char *) de) + std;
76 if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
77 if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
78 if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
79 && ((chr[12] & 0xf0) == 0xf0))
81 retname[retnamlen] = ',';
82 sprintf(retname+retnamlen+1, "%3.3x",
83 ((chr[12] & 0xf) << 8) | chr[11]);
90 * This should _really_ be cleaned up some day..
92 static int do_isofs_readdir(struct inode *inode, struct file *filp,
93 void *dirent, filldir_t filldir,
94 char * tmpname, struct iso_directory_record * tmpde)
96 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
97 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
98 unsigned long block, offset, block_saved, offset_saved;
99 unsigned long inode_number = 0; /* Quiet GCC */
100 struct buffer_head *bh = NULL;
104 char *p = NULL; /* Quiet GCC */
105 struct iso_directory_record *de;
106 struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
108 offset = filp->f_pos & (bufsize - 1);
109 block = filp->f_pos >> bufbits;
111 while (filp->f_pos < inode->i_size) {
115 bh = isofs_bread(inode, block);
120 de = (struct iso_directory_record *) (bh->b_data + offset);
122 de_len = *(unsigned char *) de;
124 /* If the length byte is zero, we should move on to the next
125 CDROM sector. If we are at the end of the directory, we
126 kick out of the while loop. */
131 filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
132 block = filp->f_pos >> bufbits;
138 offset_saved = offset;
141 /* Make sure we have a full directory entry */
142 if (offset >= bufsize) {
143 int slop = bufsize - offset + de_len;
144 memcpy(tmpde, de, slop);
145 offset &= bufsize - 1;
150 bh = isofs_bread(inode, block);
153 memcpy((void *) tmpde + slop, bh->b_data, offset);
159 isofs_normalize_block_and_offset(de,
162 inode_number = isofs_get_ino(block_saved,
167 if (de->flags[-sbi->s_high_sierra] & 0x80) {
169 filp->f_pos += de_len;
174 /* Handle the case of the '.' directory */
175 if (de->name_len[0] == 1 && de->name[0] == 0) {
176 if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
178 filp->f_pos += de_len;
184 /* Handle the case of the '..' directory */
185 if (de->name_len[0] == 1 && de->name[0] == 1) {
186 inode_number = parent_ino(filp->f_path.dentry);
187 if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
189 filp->f_pos += de_len;
193 /* Handle everything else. Do name translation if there
194 is no Rock Ridge NM field. */
197 * Do not report hidden files if so instructed, or associated
198 * files unless instructed to do so
200 if ((sbi->s_hide == 'y' &&
201 (de->flags[-sbi->s_high_sierra] & 1)) ||
202 (sbi->s_showassoc =='n' &&
203 (de->flags[-sbi->s_high_sierra] & 4))) {
204 filp->f_pos += de_len;
210 len = get_rock_ridge_filename(de, tmpname, inode);
211 if (len != 0) { /* may be -1 */
218 if (sbi->s_joliet_level) {
219 len = get_joliet_filename(de, tmpname, inode);
223 if (sbi->s_mapping == 'a') {
224 len = get_acorn_filename(de, tmpname, inode);
227 if (sbi->s_mapping == 'n') {
228 len = isofs_name_translate(de, tmpname, inode);
232 len = de->name_len[0];
236 if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
239 filp->f_pos += de_len;
248 * Handle allocation of temporary space for name translation and
249 * handling split directory entries.. The real work is done by
250 * "do_isofs_readdir()".
252 static int isofs_readdir(struct file *filp,
253 void *dirent, filldir_t filldir)
257 struct iso_directory_record * tmpde;
258 struct inode *inode = filp->f_path.dentry->d_inode;
260 tmpname = (char *)__get_free_page(GFP_KERNEL);
265 tmpde = (struct iso_directory_record *) (tmpname+1024);
267 result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
269 free_page((unsigned long) tmpname);