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