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