1 /*
2 * linux/fs/isofs/dir.c
3 *
4 * (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem.
5 *
6 * (C) 1991 Linus Torvalds - minix filesystem
7 *
8 * isofs directory handling functions
9 */
10
11 #ifdef MODULE
12 #include <linux/module.h>
13 #endif
14
15 #include <linux/errno.h>
16
17 #include <asm/segment.h>
18
19 #include <linux/fs.h>
20 #include <linux/iso_fs.h>
21 #include <linux/kernel.h>
22 #include <linux/stat.h>
23 #include <linux/string.h>
24 #include <linux/mm.h>
25 #include <linux/malloc.h>
26 #include <linux/sched.h>
27 #include <linux/locks.h>
28
29 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
30 #define ROUND_UP(x) (((x)+3) & ~3)
31
32 static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
33
34 static struct file_operations isofs_dir_operations = {
35 NULL, /* lseek - default */
36 NULL, /* read */
37 NULL, /* write - bad */
38 isofs_readdir, /* readdir */
39 NULL, /* select - default */
40 NULL, /* ioctl - default */
41 NULL, /* no special open code */
42 NULL, /* no special release code */
43 NULL /* fsync */
44 };
45
46 /*
47 * directories can handle most operations...
48 */
49 struct inode_operations isofs_dir_inode_operations = {
50 &isofs_dir_operations, /* default directory file-ops */
51 NULL, /* create */
52 isofs_lookup, /* lookup */
53 NULL, /* link */
54 NULL, /* unlink */
55 NULL, /* symlink */
56 NULL, /* mkdir */
57 NULL, /* rmdir */
58 NULL, /* mknod */
59 NULL, /* rename */
60 NULL, /* readlink */
61 NULL, /* follow_link */
62 isofs_bmap, /* bmap */
63 NULL, /* truncate */
64 NULL /* permission */
65 };
66
67 static int isofs_readdir(struct inode * inode, struct file * filp,
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
68 struct dirent * dirent, int count)
69 {
70 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
71 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
72 unsigned int block,offset,i, j;
73 char c = 0;
74 int inode_number;
75 struct buffer_head * bh;
76 void * cpnt = NULL;
77 unsigned int old_offset;
78 int dlen, rrflag;
79 int high_sierra = 0;
80 char * dpnt, *dpnt1;
81 struct iso_directory_record * de;
82
83 dpnt1 = NULL;
84 if (!inode || !S_ISDIR(inode->i_mode))
85 return -EBADF;
86
87 offset = filp->f_pos & (bufsize - 1);
88 block = isofs_bmap(inode,filp->f_pos>>bufbits);
89
90 if(!block) return 0;
91
92 if(!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
93 return 0;
94
95 while (filp->f_pos < inode->i_size) {
96 #ifdef DEBUG
97 printk("Block, offset, f_pos: %x %x %x\n",
98 block, offset, filp->f_pos);
99 #endif
100 de = (struct iso_directory_record *) (bh->b_data + offset);
101 inode_number = (block << bufbits) + (offset & (bufsize - 1));
102
103 /* If the length byte is zero, we should move on to the next
104 CDROM sector. If we are at the end of the directory, we
105 kick out of the while loop. */
106
107 if (*((unsigned char *) de) == 0) {
108 brelse(bh);
109 offset = 0;
110 filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
111 + ISOFS_BLOCK_SIZE);
112 block = isofs_bmap(inode,(filp->f_pos)>>bufbits);
113 if (!block
114 || !(bh = breada(inode->i_dev, block, bufsize, filp->f_pos,
115 inode->i_size)))
116 return 0;
117 continue;
118 }
119
120 /* Make sure that the entire directory record is in the
121 current bh block.
122 If not, we malloc a buffer, and put the two halves together,
123 so that we can cleanly read the block */
124
125 old_offset = offset;
126 offset += *((unsigned char *) de);
127 filp->f_pos += *((unsigned char *) de);
128
129 if (offset > bufsize) {
130 unsigned int frag1;
131 frag1 = bufsize - old_offset;
132 cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
133 if (!cpnt) return 0;
134 memcpy(cpnt, bh->b_data + old_offset, frag1);
135 de = (struct iso_directory_record *) ((char *)cpnt);
136 brelse(bh);
137 offset = filp->f_pos & (bufsize - 1);
138 block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
139 if (!block
140 || !(bh = breada(inode->i_dev, block, bufsize,
141 filp->f_pos, inode->i_size))) {
142 kfree(cpnt);
143 return 0;
144 };
145 memcpy((char *)cpnt+frag1, bh->b_data, offset);
146 }
147
148 /* Handle the case of the '.' directory */
149
150 rrflag = 0;
151 i = 1;
152 if (de->name_len[0] == 1 && de->name[0] == 0) {
153 put_fs_byte('.',dirent->d_name);
154 inode_number = inode->i_ino;
155 dpnt = ".";
156 }
157
158 /* Handle the case of the '..' directory */
159
160 else if (de->name_len[0] == 1 && de->name[0] == 1) {
161 put_fs_byte('.',dirent->d_name);
162 put_fs_byte('.',dirent->d_name+1);
163 i = 2;
164 dpnt = "..";
165 if((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
166 inode_number = inode->u.isofs_i.i_backlink;
167 else
168 inode_number = inode->i_ino;
169
170 /* This should never happen, but who knows. Try to be forgiving */
171 if(inode_number == -1) {
172 inode_number =
173 isofs_lookup_grandparent(inode,
174 find_rock_ridge_relocation(de, inode));
175 if(inode_number == -1){ /* Should never happen */
176 printk("Backlink not properly set.\n");
177 goto out;
178 };
179 }
180 }
181
182 /* Handle everything else. Do name translation if there
183 is no Rock Ridge NM field. */
184
185 else {
186 /* Do not report hidden or associated files */
187 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
188 if (de->flags[-high_sierra] & 5) {
189 if (cpnt) {
190 kfree(cpnt);
191 cpnt = NULL;
192 };
193 continue;
194 }
195 dlen = de->name_len[0];
196 dpnt = de->name;
197 i = dlen;
198 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
199 if (rrflag) {
200 if (rrflag == -1) { /* This is a rock ridge reloc dir */
201 if (cpnt) {
202 kfree(cpnt);
203 cpnt = NULL;
204 };
205 continue;
206 };
207 i = dlen;
208 }
209 else
210 if(inode->i_sb->u.isofs_sb.s_mapping == 'n') {
211 dpnt1 = dpnt;
212 dpnt = kmalloc(dlen, GFP_KERNEL);
213 if (!dpnt) goto out;
214 for (i = 0; i < dlen && i < NAME_MAX; i++) {
215 if (!(c = dpnt1[i])) break;
216 if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
217 if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
218 break; /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
219 if (c == ';' && i == dlen-2 && de->name[i+1] == '1')
220 break; /* Drop trailing ';1' */
221 if (c == ';') c = '.'; /* Convert remaining ';' to '.' */
222 dpnt[i] = c;
223 }
224 }
225 for(j=0; j<i; j++)
226 put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
227 if(dpnt1) {
228 kfree(dpnt);
229 dpnt = dpnt1;
230 }
231
232 dcache_add(inode, dpnt, i, inode_number);
233 };
234 #if 0
235 printk("Nchar: %d\n",i);
236 #endif
237
238 if (rrflag) kfree(dpnt);
239 if (cpnt) {
240 kfree(cpnt);
241 cpnt = NULL;
242 };
243
244 if (i) {
245 put_fs_long(inode_number, &dirent->d_ino);
246 put_fs_byte(0,i+dirent->d_name);
247 put_fs_word(i,&dirent->d_reclen);
248 brelse(bh);
249 return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
250 }
251 }
252 /* We go here for any condition we cannot handle. We also drop through
253 to here at the end of the directory. */
254 out:
255 if (cpnt)
256 kfree(cpnt);
257 brelse(bh);
258 return 0;
259 }
260
261
262