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

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