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 return 0;
131 memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
132 }
133
134 /* Handle the case of the '.' directory */
135
136 rrflag = 0;
137 i = 1;
138 if (de->name_len[0] == 1 && de->name[0] == 0) {
139 put_fs_byte('.',dirent->d_name);
140 inode_number = inode->i_ino;
141 dpnt = ".";
142 }
143
144 /* Handle the case of the '..' directory */
145
146 else if (de->name_len[0] == 1 && de->name[0] == 1) {
147 put_fs_byte('.',dirent->d_name);
148 put_fs_byte('.',dirent->d_name+1);
149 i = 2;
150 dpnt = "..";
151 if((inode->i_sb->u.isofs_sb.s_firstdatazone
152 << bufbits) != inode->i_ino)
153 inode_number = inode->u.isofs_i.i_backlink;
154 else
155 inode_number = inode->i_ino;
156
157 /* This should never happen, but who knows. Try to be forgiving */
158 if(inode_number == -1) {
159 inode_number =
160 isofs_lookup_grandparent(inode,
161 find_rock_ridge_relocation(de, inode));
162 if(inode_number == -1){ /* Should never happen */
163 printk("Backlink not properly set.\n");
164 goto out;
165 };
166 }
167 }
168
169 /* Handle everything else. Do name translation if there
170 is no Rock Ridge NM field. */
171
172 else {
173 dlen = de->name_len[0];
174 dpnt = de->name;
175 i = dlen;
176 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
177 if (rrflag) {
178 if (rrflag == -1) { /* This is a rock ridge reloc dir */
179 if (cpnt) {
180 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
181 cpnt = NULL;
182 };
183 continue;
184 };
185 i = dlen;
186 }
187 else
188 if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
189 for (i = 0; i < dlen && i < NAME_MAX; i++) {
190 if (!(c = dpnt[i])) break;
191 if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
192 if (c == ';' && i == dlen-2 && de->name[i+1] == '1')
193 break; /* Drop trailing ';1' */
194 if (c == ';') c = '.'; /* Convert remaining ';' to '.' */
195 dpnt[i] = c;
196 };
197
198 for(j=0; j<i; j++)
199 put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
200 };
201 #if 0
202 printk("Nchar: %d\n",i);
203 #endif
204
205 if (i && i+1 < sizeof(cache.filename)) {
206 cache.ino = inode_number;
207 cache.dir = inode->i_ino;
208 cache.dev = inode->i_dev;
209 strncpy(cache.filename, dpnt, i);
210 cache.dlen = dlen;
211 };
212
213 if (rrflag) kfree(dpnt);
214 if (cpnt) {
215 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
216 cpnt = NULL;
217 };
218
219 if (i) {
220 put_fs_long(inode_number, &dirent->d_ino);
221 put_fs_byte(0,i+dirent->d_name);
222 put_fs_word(i,&dirent->d_reclen);
223 brelse(bh);
224 return i;
225 }
226 }
227 /* We go here for any condition we cannot handle. We also drop through
228 to here at the end of the directory. */
229 out:
230 if (cpnt)
231 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
232 brelse(bh);
233 return 0;
234 }
235
236
237