root/fs/isofs/dir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parent_inode_number
  2. isofs_name_translate
  3. do_isofs_readdir
  4. isofs_readdir

   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 #include <linux/fs.h>
  13 #include <linux/iso_fs.h>
  14 #include <linux/kernel.h>
  15 #include <linux/stat.h>
  16 #include <linux/string.h>
  17 #include <linux/mm.h>
  18 #include <linux/malloc.h>
  19 #include <linux/sched.h>
  20 #include <linux/locks.h>
  21 
  22 #include <asm/segment.h>
  23 
  24 static int isofs_readdir(struct inode *, struct file *, void *, filldir_t);
  25 
  26 static struct file_operations isofs_dir_operations =
  27 {
  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 {
  44         &isofs_dir_operations,  /* default directory file-ops */
  45         NULL,                   /* create */
  46         isofs_lookup,           /* lookup */
  47         NULL,                   /* link */
  48         NULL,                   /* unlink */
  49         NULL,                   /* symlink */
  50         NULL,                   /* mkdir */
  51         NULL,                   /* rmdir */
  52         NULL,                   /* mknod */
  53         NULL,                   /* rename */
  54         NULL,                   /* readlink */
  55         NULL,                   /* follow_link */
  56         isofs_bmap,             /* bmap */
  57         NULL,                   /* truncate */
  58         NULL                    /* permission */
  59 };
  60 
  61 static int parent_inode_number(struct inode * inode, struct iso_directory_record * de)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         int inode_number = inode->i_ino;
  64 
  65         if ((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
  66                 inode_number = inode->u.isofs_i.i_backlink;
  67 
  68         if (inode_number != -1)
  69                 return inode_number;
  70 
  71         /* This should never happen, but who knows.  Try to be forgiving */
  72         return isofs_lookup_grandparent(inode, find_rock_ridge_relocation(de, inode));
  73 }
  74 
  75 static int isofs_name_translate(char * old, int len, char * new)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         int i, c;
  78                         
  79         for (i = 0; i < len; i++) {
  80                 c = old[i];
  81                 if (!c)
  82                         break;
  83                 if (c >= 'A' && c <= 'Z')
  84                         c |= 0x20;      /* lower case */
  85 
  86                 /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
  87                 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
  88                         break;
  89 
  90                 /* Drop trailing ';1' */
  91                 if (c == ';' && i == len - 2 && old[i + 1] == '1')
  92                         break;
  93 
  94                 /* Convert remaining ';' to '.' */
  95                 if (c == ';')
  96                         c = '.';
  97 
  98                 new[i] = c;
  99         }
 100         return i;
 101 }
 102 
 103 /*
 104  * This should _really_ be cleaned up some day..
 105  */
 106 static int do_isofs_readdir(struct inode *inode, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 107                 void *dirent, filldir_t filldir,
 108                 char * tmpname, struct iso_directory_record * tmpde)
 109 {
 110         unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 111         unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
 112         unsigned int block, offset;
 113         int inode_number;
 114         struct buffer_head *bh;
 115         int len, rrflag;
 116         int high_sierra = 0;
 117         char *name;
 118         struct iso_directory_record *de;
 119 
 120         offset = filp->f_pos & (bufsize - 1);
 121         block = isofs_bmap(inode, filp->f_pos >> bufbits);
 122 
 123         if (!block)
 124                 return 0;
 125 
 126         if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
 127                 return 0;
 128 
 129         while (filp->f_pos < inode->i_size) {
 130                 int de_len, next_offset;
 131 #ifdef DEBUG
 132                 printk("Block, offset, f_pos: %x %x %x\n",
 133                        block, offset, filp->f_pos);
 134 #endif
 135                 /* Next directory_record on next CDROM sector */
 136                 if (offset >= bufsize) {
 137                         brelse(bh);
 138                         offset = 0;
 139                         block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
 140                         if (!block)
 141                                 return 0;
 142                         bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
 143                         if (!bh)
 144                                 return 0;
 145                         continue;
 146                 }
 147 
 148                 de = (struct iso_directory_record *) (bh->b_data + offset);
 149                 inode_number = (block << bufbits) + (offset & (bufsize - 1));
 150 
 151                 de_len = *(unsigned char *) de;
 152 
 153                 /* If the length byte is zero, we should move on to the next
 154                    CDROM sector.  If we are at the end of the directory, we
 155                    kick out of the while loop. */
 156 
 157                 if (de_len == 0) {
 158                         brelse(bh);
 159                         filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
 160                                        + ISOFS_BLOCK_SIZE);
 161                         offset = 0;
 162                         block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
 163                         if (!block)
 164                                 return 0;
 165                         bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
 166                         if (!bh)
 167                                 return 0;
 168                         continue;
 169                 }
 170 
 171                 /* Make sure that the entire directory record is in the
 172                    current bh block.
 173                    If not, put the two halves together in "tmpde" */
 174                 next_offset = offset + de_len;
 175                 if (next_offset > bufsize) {
 176                         next_offset &= (bufsize - 1);
 177                         memcpy(tmpde, de, bufsize - offset);
 178                         brelse(bh);
 179                         block = isofs_bmap(inode, (filp->f_pos + de_len) >> bufbits);
 180                         if (!block)
 181                                 return 0;
 182                         bh = breada(inode->i_dev, block, bufsize, filp->f_pos+de_len, inode->i_size);
 183                         if (!bh)
 184                                 return 0;
 185                         memcpy(bufsize - offset + (char *) tmpde, bh->b_data, next_offset);
 186                         de = tmpde;
 187                 }
 188                 offset = next_offset;
 189 
 190                 /* Handle the case of the '.' directory */
 191                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 192                         if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
 193                                 break;
 194                         filp->f_pos += de_len;
 195                         continue;
 196                 }
 197 
 198                 /* Handle the case of the '..' directory */
 199                 if (de->name_len[0] == 1 && de->name[0] == 1) {
 200                         inode_number = parent_inode_number(inode, de);
 201                         if (inode_number == -1)
 202                                 break;
 203                         if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
 204                                 break;
 205                         filp->f_pos += de_len;
 206                         continue;
 207                 }
 208 
 209                 /* Handle everything else.  Do name translation if there
 210                    is no Rock Ridge NM field. */
 211 
 212                 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
 213                         /* Do not report hidden or associated files */
 214                         high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 215                         if (de->flags[-high_sierra] & 5) {
 216                                 filp->f_pos += de_len;
 217                                 continue;
 218                         }
 219                 }
 220 
 221                 /* Check Rock Ridge name translation.. */
 222                 len = de->name_len[0];
 223                 name = de->name;
 224                 rrflag = get_rock_ridge_filename(de, &name, &len, inode);
 225                 if (rrflag) {
 226                         /* rrflag == 1 means that we have a new name (kmalloced) */
 227                         if (rrflag == 1) {
 228                                 rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
 229                                 dcache_add(inode, name, len, inode_number);
 230                                 kfree(name); /* this was allocated in get_r_r_filename.. */
 231                                 if (rrflag < 0)
 232                                         break;
 233                         }
 234                         filp->f_pos += de_len;
 235                         continue;
 236                 }
 237 
 238                 if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
 239                         len = isofs_name_translate(name, len, tmpname);
 240                         if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
 241                                 break;
 242                         dcache_add(inode, tmpname, len, inode_number);
 243                         filp->f_pos += de_len;
 244                         continue;
 245                 }
 246 
 247                 if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
 248                         break;
 249 
 250                 dcache_add(inode, name, len, inode_number);
 251                 filp->f_pos += de_len;
 252                 continue;
 253         }
 254         brelse(bh);
 255         return 0;
 256 }
 257 
 258 /*
 259  * Handle allocation of temporary space for name translation and
 260  * handling split directory entries.. The real work is done by
 261  * "do_isofs_readdir()".
 262  */
 263 static int isofs_readdir(struct inode *inode, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 264                 void *dirent, filldir_t filldir)
 265 {
 266         int result;
 267         char * tmpname;
 268         struct iso_directory_record * tmpde;
 269 
 270         if (!inode || !S_ISDIR(inode->i_mode))
 271                 return -EBADF;
 272 
 273         tmpname = (char *) __get_free_page(GFP_KERNEL);
 274         if (!tmpname)
 275                 return -ENOMEM;
 276         tmpde = (struct iso_directory_record *) (tmpname+256);
 277 
 278         result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
 279 
 280         free_page((unsigned long) tmpname);
 281         return result;
 282 }

/* [previous][next][first][last][top][bottom][index][help] */