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 /* This is used to speed up lookup. Without this we would need to
61 make a linear search of the directory to find the file that the
62 directory read just returned. This is a single element cache. */
63
64 struct lookup_cache cache = {0,};
65
66 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)
*/
67 struct dirent * dirent, int count)
68 {
69 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
70 unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
71 unsigned int block,offset,i, j;
72 char c = 0;
73 int inode_number;
74 struct buffer_head * bh;
75 void * cpnt = NULL;
76 unsigned int old_offset;
77 int dlen, rrflag;
78 char * dpnt;
79 struct iso_directory_record * de;
80
81 if (!inode || !S_ISDIR(inode->i_mode))
82 return -EBADF;
83
84 offset = filp->f_pos & (bufsize - 1);
85 block = isofs_bmap(inode,filp->f_pos>>bufbits);
86
87 if(!block) return 0;
88
89 if(!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
90 return 0;
91
92 while (filp->f_pos < inode->i_size) {
93 #ifdef DEBUG
94 printk("Block, offset: %x %x %x\n",
95 block, offset, filp->f_pos);
96 #endif
97 de = (struct iso_directory_record *) (bh->b_data + offset);
98 inode_number = (block << bufbits) + (offset & (bufsize - 1));
99
100 /* If the length byte is zero, we should move on to the next
101 CDROM sector. If we are at the end of the directory, we
102 kick out of the while loop. */
103
104 if (*((unsigned char *) de) == 0) {
105 brelse(bh);
106 offset = 0;
107 filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
108 + ISOFS_BLOCK_SIZE);
109 block = isofs_bmap(inode,(filp->f_pos)>>bufbits);
110 if (!block
111 || !(bh = breada(inode->i_dev, block, bufsize, filp->f_pos,
112 inode->i_size)))
113 return 0;
114 continue;
115 }
116
117 /* Make sure that the entire directory record is in the
118 current bh block.
119 If not, we malloc a buffer, and put the two halves together,
120 so that we can cleanly read the block */
121
122 old_offset = offset;
123 offset += *((unsigned char *) de);
124 filp->f_pos += *((unsigned char *) de);
125
126 if (offset >= bufsize) {
127 cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
128 memcpy(cpnt, bh->b_data, bufsize);
129 de = (struct iso_directory_record *)
130 ((char *)cpnt + old_offset);
131 brelse(bh);
132 offset = filp->f_pos & (bufsize - 1);
133 block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
134 if (!block
135 || !(bh = breada(inode->i_dev, block, bufsize,
136 filp->f_pos, inode->i_size))) {
137 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
138 return 0;
139 };
140 memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
141 }
142
143 /* Handle the case of the '.' directory */
144
145 rrflag = 0;
146 i = 1;
147 if (de->name_len[0] == 1 && de->name[0] == 0) {
148 put_fs_byte('.',dirent->d_name);
149 inode_number = inode->i_ino;
150 dpnt = ".";
151 }
152
153 /* Handle the case of the '..' directory */
154
155 else if (de->name_len[0] == 1 && de->name[0] == 1) {
156 put_fs_byte('.',dirent->d_name);
157 put_fs_byte('.',dirent->d_name+1);
158 i = 2;
159 dpnt = "..";
160 if((inode->i_sb->u.isofs_sb.s_firstdatazone
161 << bufbits) != inode->i_ino)
162 inode_number = inode->u.isofs_i.i_backlink;
163 else
164 inode_number = inode->i_ino;
165
166 /* This should never happen, but who knows. Try to be forgiving */
167 if(inode_number == -1) {
168 inode_number =
169 isofs_lookup_grandparent(inode,
170 find_rock_ridge_relocation(de, inode));
171 if(inode_number == -1){ /* Should never happen */
172 printk("Backlink not properly set.\n");
173 goto out;
174 };
175 }
176 }
177
178 /* Handle everything else. Do name translation if there
179 is no Rock Ridge NM field. */
180
181 else {
182 dlen = de->name_len[0];
183 dpnt = de->name;
184 i = dlen;
185 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
186 if (rrflag) {
187 if (rrflag == -1) { /* This is a rock ridge reloc dir */
188 if (cpnt) {
189 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
190 cpnt = NULL;
191 };
192 continue;
193 };
194 i = dlen;
195 }
196 else
197 if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
198 for (i = 0; i < dlen && i < NAME_MAX; i++) {
199 if (!(c = dpnt[i])) break;
200 if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
201 if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
202 break; /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
203 if (c == ';' && i == dlen-2 && de->name[i+1] == '1')
204 break; /* Drop trailing ';1' */
205 if (c == ';') c = '.'; /* Convert remaining ';' to '.' */
206 dpnt[i] = c;
207 };
208
209 for(j=0; j<i; j++)
210 put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
211 };
212 #if 0
213 printk("Nchar: %d\n",i);
214 #endif
215
216 if (i && i+1 < sizeof(cache.filename)) {
217 cache.ino = inode_number;
218 cache.dir = inode->i_ino;
219 cache.dev = inode->i_dev;
220 strncpy(cache.filename, dpnt, i);
221 cache.dlen = dlen;
222 };
223
224 if (rrflag) kfree(dpnt);
225 if (cpnt) {
226 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
227 cpnt = NULL;
228 };
229
230 if (i) {
231 put_fs_long(inode_number, &dirent->d_ino);
232 put_fs_byte(0,i+dirent->d_name);
233 put_fs_word(i,&dirent->d_reclen);
234 brelse(bh);
235 return i;
236 }
237 }
238 /* We go here for any condition we cannot handle. We also drop through
239 to here at the end of the directory. */
240 out:
241 if (cpnt)
242 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
243 brelse(bh);
244 return 0;
245 }
246
247
248