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                 de = (struct iso_directory_record *) (bh->b_data + offset);
 141                 inode_number = (block << bufbits) + (offset & (bufsize - 1));
 142 
 143                 de_len = *(unsigned char *) de;
 144 
 145                 /* If the length byte is zero, we should move on to the next
 146                    CDROM sector.  If we are at the end of the directory, we
 147                    kick out of the while loop. */
 148 
 149                 if (de_len == 0) {
 150                         brelse(bh);
 151                         filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
 152                                        + ISOFS_BLOCK_SIZE);
 153                         offset = 0;
 154                         block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
 155                         if (!block)
 156                                 return 0;
 157                         bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
 158                         if (!bh)
 159                                 return 0;
 160                         continue;
 161                 }
 162 
 163                 /* Make sure that the entire directory record is in the
 164                    current bh block.
 165                    If not, put the two halves together in "tmpde" */
 166                 next_offset = offset + de_len;
 167                 if (next_offset > bufsize) {
 168                         next_offset &= (bufsize - 1);
 169                         memcpy(tmpde, de, bufsize - offset);
 170                         brelse(bh);
 171                         block = isofs_bmap(inode, (filp->f_pos + de_len) >> bufbits);
 172                         if (!block)
 173                                 return 0;
 174                         bh = breada(inode->i_dev, block, bufsize, filp->f_pos+de_len, inode->i_size);
 175                         if (!bh)
 176                                 return 0;
 177                         memcpy(bufsize - offset + (char *) tmpde, bh->b_data, next_offset);
 178                         de = tmpde;
 179                 }
 180                 offset = next_offset;
 181 
 182                 /* Handle the case of the '.' directory */
 183                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 184                         if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
 185                                 break;
 186                         filp->f_pos += de_len;
 187                         continue;
 188                 }
 189 
 190                 /* Handle the case of the '..' directory */
 191                 if (de->name_len[0] == 1 && de->name[0] == 1) {
 192                         inode_number = parent_inode_number(inode, de);
 193                         if (inode_number == -1)
 194                                 break;
 195                         if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
 196                                 break;
 197                         filp->f_pos += de_len;
 198                         continue;
 199                 }
 200 
 201                 /* Handle everything else.  Do name translation if there
 202                    is no Rock Ridge NM field. */
 203 
 204                 if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
 205                         /* Do not report hidden or associated files */
 206                         high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 207                         if (de->flags[-high_sierra] & 5) {
 208                                 filp->f_pos += de_len;
 209                                 continue;
 210                         }
 211                 }
 212 
 213                 /* Check Rock Ridge name translation.. */
 214                 len = de->name_len[0];
 215                 name = de->name;
 216                 rrflag = get_rock_ridge_filename(de, &name, &len, inode);
 217                 if (rrflag) {
 218                         /* rrflag == 1 means that we have a new name (kmalloced) */
 219                         if (rrflag == 1) {
 220                                 rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
 221                                 kfree(name); /* this was allocated in get_r_r_filename.. */
 222                                 if (rrflag < 0)
 223                                         break;
 224                         }
 225                         filp->f_pos += de_len;
 226                         continue;
 227                 }
 228 
 229                 if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
 230                         len = isofs_name_translate(name, len, tmpname);
 231                         if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
 232                                 break;
 233                         filp->f_pos += de_len;
 234                         continue;
 235                 }
 236 
 237                 if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
 238                         break;
 239 
 240                 filp->f_pos += de_len;
 241                 continue;
 242         }
 243         brelse(bh);
 244         return 0;
 245 }
 246 
 247 /*
 248  * Handle allocation of temporary space for name translation and
 249  * handling split directory entries.. The real work is done by
 250  * "do_isofs_readdir()".
 251  */
 252 static int isofs_readdir(struct inode *inode, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 253                 void *dirent, filldir_t filldir)
 254 {
 255         int result;
 256         char * tmpname;
 257         struct iso_directory_record * tmpde;
 258 
 259         if (!inode || !S_ISDIR(inode->i_mode))
 260                 return -EBADF;
 261 
 262         tmpname = (char *) __get_free_page(GFP_KERNEL);
 263         if (!tmpname)
 264                 return -ENOMEM;
 265         tmpde = (struct iso_directory_record *) (tmpname+256);
 266 
 267         result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
 268 
 269         free_page((unsigned long) tmpname);
 270         return result;
 271 }

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