RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / fs / isofs / dir.c
blob0e94c31cad9bca5879cda7784c57a33a0a55f4ae
1 /*
2 * linux/fs/isofs/dir.c
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>
14 #include "isofs.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];
36 int i;
38 for (i = 0; i < len; i++) {
39 unsigned char c = old[i];
40 if (!c)
41 break;
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')
48 break;
50 /* Drop trailing ';1' */
51 if (c == ';' && i == len - 2 && old[i + 1] == '1')
52 break;
54 /* Convert remaining ';' to '.' */
55 /* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
56 if (c == ';' || c == '/')
57 c = '.';
59 new[i] = c;
61 return i;
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)
68 int std;
69 unsigned char * chr;
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];
73 if (std & 1) std++;
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]);
84 retnamlen += 4;
86 return retnamlen;
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;
101 int len;
102 int map;
103 int first_de = 1;
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) {
112 int de_len;
114 if (!bh) {
115 bh = isofs_bread(inode, block);
116 if (!bh)
117 return 0;
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. */
128 if (de_len == 0) {
129 brelse(bh);
130 bh = NULL;
131 filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
132 block = filp->f_pos >> bufbits;
133 offset = 0;
134 continue;
137 block_saved = block;
138 offset_saved = offset;
139 offset += de_len;
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;
146 block++;
147 brelse(bh);
148 bh = NULL;
149 if (offset) {
150 bh = isofs_bread(inode, block);
151 if (!bh)
152 return 0;
153 memcpy((void *) tmpde + slop, bh->b_data, offset);
155 de = tmpde;
158 if (first_de) {
159 isofs_normalize_block_and_offset(de,
160 &block_saved,
161 &offset_saved);
162 inode_number = isofs_get_ino(block_saved,
163 offset_saved,
164 bufbits);
167 if (de->flags[-sbi->s_high_sierra] & 0x80) {
168 first_de = 0;
169 filp->f_pos += de_len;
170 continue;
172 first_de = 1;
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)
177 break;
178 filp->f_pos += de_len;
179 continue;
182 len = 0;
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)
188 break;
189 filp->f_pos += de_len;
190 continue;
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;
205 continue;
208 map = 1;
209 if (sbi->s_rock) {
210 len = get_rock_ridge_filename(de, tmpname, inode);
211 if (len != 0) { /* may be -1 */
212 p = tmpname;
213 map = 0;
216 if (map) {
217 #ifdef CONFIG_JOLIET
218 if (sbi->s_joliet_level) {
219 len = get_joliet_filename(de, tmpname, inode);
220 p = tmpname;
221 } else
222 #endif
223 if (sbi->s_mapping == 'a') {
224 len = get_acorn_filename(de, tmpname, inode);
225 p = tmpname;
226 } else
227 if (sbi->s_mapping == 'n') {
228 len = isofs_name_translate(de, tmpname, inode);
229 p = tmpname;
230 } else {
231 p = de->name;
232 len = de->name_len[0];
235 if (len > 0) {
236 if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
237 break;
239 filp->f_pos += de_len;
241 continue;
243 if (bh) brelse(bh);
244 return 0;
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)
255 int result;
256 char * tmpname;
257 struct iso_directory_record * tmpde;
258 struct inode *inode = filp->f_path.dentry->d_inode;
260 tmpname = (char *)__get_free_page(GFP_KERNEL);
261 if (tmpname == NULL)
262 return -ENOMEM;
264 lock_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);
270 unlock_kernel();
271 return result;