~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/isofs/dir.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/isofs/dir.c
  3  *
  4  *  (C) 1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
  5  *
  6  *  (C) 1991  Linus Torvalds - minix filesystem
  7  *
  8  *  Steve Beynon                       : Missing last directory entries fixed
  9  *  (stephen@askone.demon.co.uk)      : 21st June 1996
 10  * 
 11  *  isofs directory handling functions
 12  */
 13 #include <linux/errno.h>
 14 #include <linux/fs.h>
 15 #include <linux/iso_fs.h>
 16 #include <linux/kernel.h>
 17 #include <linux/stat.h>
 18 #include <linux/string.h>
 19 #include <linux/mm.h>
 20 #include <linux/malloc.h>
 21 #include <linux/sched.h>
 22 #include <linux/locks.h>
 23 #include <linux/config.h>
 24 
 25 #include <asm/uaccess.h>
 26 
 27 static int isofs_readdir(struct file *, void *, filldir_t);
 28 
 29 struct file_operations isofs_dir_operations =
 30 {
 31         read:           generic_read_dir,
 32         readdir:        isofs_readdir,
 33 };
 34 
 35 /*
 36  * directories can handle most operations...
 37  */
 38 struct inode_operations isofs_dir_inode_operations =
 39 {
 40         lookup:         isofs_lookup,
 41 };
 42 
 43 int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
 44 {
 45         char * old = de->name;
 46         int len = de->name_len[0];
 47         int i;
 48                         
 49         for (i = 0; i < len; i++) {
 50                 unsigned char c = old[i];
 51                 if (!c)
 52                         break;
 53 
 54                 if (c >= 'A' && c <= 'Z')
 55                         c |= 0x20;      /* lower case */
 56 
 57                 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
 58                 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
 59                         break;
 60 
 61                 /* Drop trailing ';1' */
 62                 if (c == ';' && i == len - 2 && old[i + 1] == '1')
 63                         break;
 64 
 65                 /* Convert remaining ';' to '.' */
 66                 if (c == ';')
 67                         c = '.';
 68 
 69                 new[i] = c;
 70         }
 71         return i;
 72 }
 73 
 74 /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
 75 int get_acorn_filename(struct iso_directory_record * de,
 76                             char * retname, struct inode * inode)
 77 {
 78         int std;
 79         unsigned char * chr;
 80         int retnamlen = isofs_name_translate(de, retname, inode);
 81         if (retnamlen == 0) return 0;
 82         std = sizeof(struct iso_directory_record) + de->name_len[0];
 83         if (std & 1) std++;
 84         if ((*((unsigned char *) de) - std) != 32) return retnamlen;
 85         chr = ((unsigned char *) de) + std;
 86         if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
 87         if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
 88         if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
 89                 && ((chr[12] & 0xf0) == 0xf0))
 90         {
 91                 retname[retnamlen] = ',';
 92                 sprintf(retname+retnamlen+1, "%3.3x",
 93                         ((chr[12] & 0xf) << 8) | chr[11]);
 94                 retnamlen += 4;
 95         }
 96         return retnamlen;
 97 }
 98 
 99 /*
100  * This should _really_ be cleaned up some day..
101  */
102 static int do_isofs_readdir(struct inode *inode, struct file *filp,
103                 void *dirent, filldir_t filldir,
104                 char * tmpname, struct iso_directory_record * tmpde)
105 {
106         unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
107         unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
108         unsigned int block, offset;
109         int inode_number = 0;   /* Quiet GCC */
110         struct buffer_head *bh = NULL;
111         int len;
112         int map;
113         int high_sierra;
114         int first_de = 1;
115         char *p = NULL;         /* Quiet GCC */
116         struct iso_directory_record *de;
117 
118         offset = filp->f_pos & (bufsize - 1);
119         block = filp->f_pos >> bufbits;
120         high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
121 
122         while (filp->f_pos < inode->i_size) {
123                 int de_len;
124 
125                 if (!bh) {
126                         bh = isofs_bread(inode, bufsize, block);
127                         if (!bh)
128                                 return 0;
129                 }
130 
131                 de = (struct iso_directory_record *) (bh->b_data + offset);
132                 if (first_de)
133                         inode_number = (bh->b_blocknr << bufbits) + offset;
134 
135                 de_len = *(unsigned char *) de;
136 
137                 /* If the length byte is zero, we should move on to the next
138                    CDROM sector.  If we are at the end of the directory, we
139                    kick out of the while loop. */
140 
141                 if (de_len == 0) {
142                         brelse(bh);
143                         bh = NULL;
144                         filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
145                         block = filp->f_pos >> bufbits;
146                         offset = 0;
147                         continue;
148                 }
149 
150                 offset += de_len;
151 
152                 /* Make sure we have a full directory entry */
153                 if (offset >= bufsize) {
154                         int slop = bufsize - offset + de_len;
155                         memcpy(tmpde, de, slop);
156                         offset &= bufsize - 1;
157                         block++;
158                         brelse(bh);
159                         bh = NULL;
160                         if (offset) {
161                                 bh = isofs_bread(inode, bufsize, block);
162                                 if (!bh)
163                                         return 0;
164                                 memcpy((void *) tmpde + slop, bh->b_data, offset);
165                         }
166                         de = tmpde;
167                 }
168 
169                 if (de->flags[-high_sierra] & 0x80) {
170                         first_de = 0;
171                         filp->f_pos += de_len;
172                         continue;
173                 }
174                 first_de = 1;
175 
176                 /* Handle the case of the '.' directory */
177                 if (de->name_len[0] == 1 && de->name[0] == 0) {
178                         if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
179                                 break;
180                         filp->f_pos += de_len;
181                         continue;
182                 }
183 
184                 len = 0;
185 
186                 /* Handle the case of the '..' directory */
187                 if (de->name_len[0] == 1 && de->name[0] == 1) {
188                         inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
189                         if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
190                                 break;
191                         filp->f_pos += de_len;
192                         continue;
193                 }
194 
195                 /* Handle everything else.  Do name translation if there
196                    is no Rock Ridge NM field. */
197                 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
198                         /* Do not report hidden or associated files */
199                         if (de->flags[-high_sierra] & 5) {
200                                 filp->f_pos += de_len;
201                                 continue;
202                         }
203                 }
204 
205                 map = 1;
206                 if (inode->i_sb->u.isofs_sb.s_rock) {
207                         len = get_rock_ridge_filename(de, tmpname, inode);
208                         if (len != 0) {         /* may be -1 */
209                                 p = tmpname;
210                                 map = 0;
211                         }
212                 }
213                 if (map) {
214 #ifdef CONFIG_JOLIET
215                         if (inode->i_sb->u.isofs_sb.s_joliet_level) {
216                                 len = get_joliet_filename(de, tmpname, inode);
217                                 p = tmpname;
218                         } else
219 #endif
220                         if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
221                                 len = get_acorn_filename(de, tmpname, inode);
222                                 p = tmpname;
223                         } else
224                         if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
225                                 len = isofs_name_translate(de, tmpname, inode);
226                                 p = tmpname;
227                         } else {
228                                 p = de->name;
229                                 len = de->name_len[0];
230                         }
231                 }
232                 if (len > 0) {
233                         if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
234                                 break;
235                 }
236                 filp->f_pos += de_len;
237 
238                 continue;
239         }
240         if (bh) brelse(bh);
241         return 0;
242 }
243 
244 /*
245  * Handle allocation of temporary space for name translation and
246  * handling split directory entries.. The real work is done by
247  * "do_isofs_readdir()".
248  */
249 static int isofs_readdir(struct file *filp,
250                 void *dirent, filldir_t filldir)
251 {
252         int result;
253         char * tmpname;
254         struct iso_directory_record * tmpde;
255         struct inode *inode = filp->f_dentry->d_inode;
256 
257         tmpname = (char *) __get_free_page(GFP_KERNEL);
258         if (!tmpname)
259                 return -ENOMEM;
260         tmpde = (struct iso_directory_record *) (tmpname+1024);
261 
262         result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
263 
264         free_page((unsigned long) tmpname);
265         return result;
266 }
267 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.