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

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