root/fs/isofs/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. isofs_match
  2. isofs_find_entry
  3. isofs_lookup

   1 /*
   2  *  linux/fs/isofs/namei.c
   3  *
   4  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   5  *
   6  *  (C) 1991  Linus Torvalds - minix filesystem
   7  */
   8 
   9 #ifdef MODULE
  10 #include <linux/module.h>
  11 #endif
  12 
  13 #include <linux/sched.h>
  14 #include <linux/iso_fs.h>
  15 #include <linux/kernel.h>
  16 #include <linux/string.h>
  17 #include <linux/stat.h>
  18 #include <linux/fcntl.h>
  19 #include <asm/segment.h>
  20 #include <linux/malloc.h>
  21 
  22 #include <linux/errno.h>
  23 
  24 /*
  25  * ok, we cannot use strncmp, as the name is not in our data space.
  26  * Thus we'll have to use isofs_match. No big problem. Match also makes
  27  * some sanity tests.
  28  *
  29  * NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure.
  30  */
  31 static int isofs_match(int len,const char * name, char * compare, int dlen)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33         if (!compare)
  34                 return 0;
  35 
  36         /* check special "." and ".." files */
  37         if (dlen == 1) {
  38                 /* "." */
  39                 if (compare[0] == 0) {
  40                         if (!len)
  41                                 return 1;
  42                         compare = ".";
  43                 } else if (compare[0] == 1) {
  44                         compare = "..";
  45                         dlen = 2;
  46                 }
  47         }
  48 #if 0
  49         if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
  50 #endif
  51         
  52         if (dlen != len)
  53                 return 0;
  54         return !memcmp(name, compare, len);
  55 }
  56 
  57 /*
  58  *      isofs_find_entry()
  59  *
  60  * finds an entry in the specified directory with the wanted name. It
  61  * returns the cache buffer in which the entry was found, and the entry
  62  * itself (as an inode number). It does NOT read the inode of the
  63  * entry - you'll have to do that yourself if you want to.
  64  */
  65 static struct buffer_head * isofs_find_entry(struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
  66         const char * name, int namelen, unsigned long * ino, unsigned long * ino_back)
  67 {
  68         unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
  69         unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
  70         unsigned int block, i, f_pos, offset, inode_number;
  71         struct buffer_head * bh;
  72         void * cpnt = NULL;
  73         unsigned int old_offset;
  74         unsigned int backlink;
  75         int dlen, rrflag, match;
  76         char * dpnt;
  77         struct iso_directory_record * de;
  78         char c;
  79 
  80         *ino = 0;
  81         if (!dir) return NULL;
  82         
  83         if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
  84   
  85         f_pos = 0;
  86 
  87         offset = f_pos & (bufsize - 1);
  88         block = isofs_bmap(dir,f_pos >> bufbits);
  89 
  90         if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
  91   
  92         while (f_pos < dir->i_size) {
  93                 de = (struct iso_directory_record *) (bh->b_data + offset);
  94                 backlink = dir->i_ino;
  95                 inode_number = (block << bufbits) + (offset & (bufsize - 1));
  96 
  97                 /* If byte is zero, this is the end of file, or time to move to
  98                    the next sector. Usually 2048 byte boundaries. */
  99                 
 100                 if (*((unsigned char *) de) == 0) {
 101                         brelse(bh);
 102                         offset = 0;
 103                         f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
 104                                  + ISOFS_BLOCK_SIZE);
 105                         block = isofs_bmap(dir,f_pos>>bufbits);
 106                         if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
 107                                 return 0;
 108                         continue; /* Will kick out if past end of directory */
 109                 }
 110 
 111                 old_offset = offset;
 112                 offset += *((unsigned char *) de);
 113                 f_pos += *((unsigned char *) de);
 114 
 115                 /* Handle case where the directory entry spans two blocks.
 116                    Usually 1024 byte boundaries */
 117                 if (offset >= bufsize) {
 118                         unsigned int frag1;
 119                         frag1 = bufsize - old_offset;
 120                         cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
 121                         if (!cpnt) return 0;
 122                         memcpy(cpnt, bh->b_data + old_offset, frag1);
 123 
 124                         de = (struct iso_directory_record *) cpnt;
 125                         brelse(bh);
 126                         offset = f_pos & (bufsize - 1);
 127                         block = isofs_bmap(dir,f_pos>>bufbits);
 128                         if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
 129                                 kfree(cpnt);
 130                                 return 0;
 131                         };
 132                         memcpy((char *)cpnt+frag1, bh->b_data, offset);
 133                 }
 134                 
 135                 /* Handle the '.' case */
 136                 
 137                 if (de->name[0]==0 && de->name_len[0]==1) {
 138                         inode_number = dir->i_ino;
 139                         backlink = 0;
 140                 }
 141                 
 142                 /* Handle the '..' case */
 143 
 144                 if (de->name[0]==1 && de->name_len[0]==1) {
 145 #if 0
 146                         printk("Doing .. (%d %d)",
 147                                dir->i_sb->s_firstdatazone,
 148                                dir->i_ino);
 149 #endif
 150                         if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
 151                                 inode_number = dir->u.isofs_i.i_backlink;
 152                         else
 153                                 inode_number = dir->i_ino;
 154                         backlink = 0;
 155                 }
 156     
 157                 dlen = de->name_len[0];
 158                 dpnt = de->name;
 159                 /* Now convert the filename in the buffer to lower case */
 160                 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
 161                 if (rrflag) {
 162                   if (rrflag == -1) goto out; /* Relocated deep directory */
 163                 } else {
 164                   if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
 165                     for (i = 0; i < dlen; i++) {
 166                       c = dpnt[i];
 167                       if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 168                       if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
 169                         dlen -= 2;
 170                         break;
 171                       }
 172                       if (c == ';') c = '.';
 173                       de->name[i] = c;
 174                     }
 175                     /* This allows us to match with and without a trailing
 176                        period.  */
 177                     if(dpnt[dlen-1] == '.' && namelen == dlen-1)
 178                       dlen--;
 179                   }
 180                 }
 181                 match = isofs_match(namelen,name,dpnt,dlen);
 182                 if (cpnt) {
 183                         kfree(cpnt);
 184                         cpnt = NULL;
 185                 }
 186 
 187                 if(rrflag) kfree(dpnt);
 188                 if (match) {
 189                         if(inode_number == -1) {
 190                                 /* Should only happen for the '..' entry */
 191                                 inode_number = 
 192                                         isofs_lookup_grandparent(dir,
 193                                            find_rock_ridge_relocation(de,dir));
 194                                 if(inode_number == -1){
 195                                         /* Should never happen */
 196                                         printk("Backlink not properly set.\n");
 197                                         goto out;
 198                                 }
 199                         }
 200                         *ino = inode_number;
 201                         *ino_back = backlink;
 202                         return bh;
 203                 }
 204         }
 205  out:
 206         if (cpnt)
 207                 kfree(cpnt);
 208         brelse(bh);
 209         return NULL;
 210 }
 211 
 212 int isofs_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 213         struct inode ** result)
 214 {
 215         unsigned long ino, ino_back;
 216         struct buffer_head * bh;
 217 
 218 #ifdef DEBUG
 219         printk("lookup: %x %d\n",dir->i_ino, len);
 220 #endif
 221         *result = NULL;
 222         if (!dir)
 223                 return -ENOENT;
 224 
 225         if (!S_ISDIR(dir->i_mode)) {
 226                 iput(dir);
 227                 return -ENOENT;
 228         }
 229 
 230         ino = 0;
 231 
 232         if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
 233 
 234         if (!ino) {
 235           if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))) {
 236             iput(dir);
 237             return -ENOENT;
 238           }
 239           if (ino_back == dir->i_ino)
 240                 dcache_add(dir, name, len, ino);
 241           brelse(bh);
 242         };
 243 
 244         if (!(*result = iget(dir->i_sb,ino))) {
 245                 iput(dir);
 246                 return -EACCES;
 247         }
 248 
 249         /* We need this backlink for the ".." entry unless the name that we
 250            are looking up traversed a mount point (in which case the inode
 251            may not even be on an iso9660 filesystem, and writing to
 252            u.isofs_i would only cause memory corruption).
 253         */
 254         
 255         if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
 256           (*result)->u.isofs_i.i_backlink = ino_back; 
 257         }
 258         
 259         iput(dir);
 260         return 0;
 261 }

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