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

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