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