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, char * compare, int dlen)
     /* [previous][next][first][last][top][bottom][index][help] */
  28 {
  29         register int same;
  30         
  31         if (!compare) return 0;
  32         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
  33         if (!len && (compare[0]==0) && (dlen==1))
  34                 return 1;
  35         
  36         if (compare[0]==0 && dlen==1 && len == 1)
  37                 compare = ".";
  38         if (compare[0]==1 && dlen==1 && len == 2) {
  39                 compare = "..";
  40                 dlen = 2;
  41         };
  42 #if 0
  43         if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
  44 #endif
  45         
  46         if (dlen != len)
  47                 return 0;
  48         __asm__ __volatile__(
  49                 "cld\n\t"
  50                 "repe ; cmpsb\n\t"
  51                 "setz %%al"
  52                 :"=a" (same)
  53                 :"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len)
  54                 :"cx","di","si");
  55         return same;
  56 }
  57 
  58 /*
  59  *      isofs_find_entry()
  60  *
  61  * finds an entry in the specified directory with the wanted name. It
  62  * returns the cache buffer in which the entry was found, and the entry
  63  * itself (as an inode number). It does NOT read the inode of the
  64  * entry - you'll have to do that yourself if you want to.
  65  */
  66 static struct buffer_head * isofs_find_entry(struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
  67         const char * name, int namelen, int * ino, int * ino_back)
  68 {
  69         unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
  70         unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
  71         unsigned int block, i, f_pos, offset, inode_number;
  72         struct buffer_head * bh;
  73         void * cpnt = NULL;
  74         unsigned int old_offset;
  75         unsigned int backlink;
  76         int dlen, rrflag, match;
  77         char * dpnt;
  78         struct iso_directory_record * de;
  79         char c;
  80 
  81         *ino = 0;
  82         if (!dir) return NULL;
  83         
  84         if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
  85   
  86         f_pos = 0;
  87 
  88         offset = f_pos & (bufsize - 1);
  89         block = isofs_bmap(dir,f_pos >> bufbits);
  90 
  91         if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
  92   
  93         while (f_pos < dir->i_size) {
  94                 de = (struct iso_directory_record *) (bh->b_data + offset);
  95                 backlink = dir->i_ino;
  96                 inode_number = (block << bufbits) + (offset & (bufsize - 1));
  97 
  98                 /* If byte is zero, this is the end of file, or time to move to
  99                    the next sector. Usually 2048 byte boundaries. */
 100                 
 101                 if (*((unsigned char *) de) == 0) {
 102                         brelse(bh);
 103                         offset = 0;
 104                         f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
 105                                  + ISOFS_BLOCK_SIZE);
 106                         block = isofs_bmap(dir,f_pos>>bufbits);
 107                         if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
 108                                 return 0;
 109                         continue; /* Will kick out if past end of directory */
 110                 }
 111 
 112                 old_offset = offset;
 113                 offset += *((unsigned char *) de);
 114                 f_pos += *((unsigned char *) de);
 115 
 116                 /* Handle case where the directory entry spans two blocks.
 117                    Usually 1024 byte boundaries */
 118                 if (offset >= bufsize) {
 119                         cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
 120                         memcpy(cpnt, bh->b_data, bufsize);
 121                         de = (struct iso_directory_record *)
 122                           ((char *)cpnt + old_offset);
 123                         brelse(bh);
 124                         offset = f_pos & (bufsize - 1);
 125                         block = isofs_bmap(dir,f_pos>>bufbits);
 126                         if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
 127                                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 128                                 return 0;
 129                         };
 130                         memcpy((char *)cpnt+bufsize,bh->b_data,bufsize);
 131                 }
 132                 
 133                 /* Handle the '.' case */
 134                 
 135                 if (de->name[0]==0 && de->name_len[0]==1) {
 136                         inode_number = dir->i_ino;
 137                         backlink = 0;
 138                 }
 139                 
 140                 /* Handle the '..' case */
 141 
 142                 if (de->name[0]==1 && de->name_len[0]==1) {
 143 #if 0
 144                         printk("Doing .. (%d %d)",
 145                                dir->i_sb->s_firstdatazone << bufbits,
 146                                dir->i_ino);
 147 #endif
 148                         if((dir->i_sb->u.isofs_sb.s_firstdatazone
 149                             << bufbits) != dir->i_ino)
 150                                 inode_number = dir->u.isofs_i.i_backlink;
 151                         else
 152                                 inode_number = dir->i_ino;
 153                         backlink = 0;
 154                 }
 155     
 156                 dlen = de->name_len[0];
 157                 dpnt = de->name;
 158                 /* Now convert the filename in the buffer to lower case */
 159                 rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
 160                 if (rrflag) {
 161                   if (rrflag == -1) goto out; /* Relocated deep directory */
 162                 } else {
 163                   if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
 164                     for (i = 0; i < dlen; i++) {
 165                       c = dpnt[i];
 166                       if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 167                       if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
 168                         dlen -= 2;
 169                         break;
 170                       }
 171                       if (c == ';') c = '.';
 172                       de->name[i] = c;
 173                     }
 174                     /* This allows us to match with and without a trailing
 175                        period.  */
 176                     if(dpnt[dlen-1] == '.' && namelen == dlen-1)
 177                       dlen--;
 178                   }
 179                 }
 180                 match = isofs_match(namelen,name,dpnt,dlen);
 181                 if (cpnt) {
 182                         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 183                         cpnt = NULL;
 184                 }
 185 
 186                 if(rrflag) kfree(dpnt);
 187                 if (match) {
 188                         if(inode_number == -1) {
 189                                 /* Should only happen for the '..' entry */
 190                                 inode_number = 
 191                                         isofs_lookup_grandparent(dir,
 192                                            find_rock_ridge_relocation(de,dir));
 193                                 if(inode_number == -1){
 194                                         /* Should never happen */
 195                                         printk("Backlink not properly set.\n");
 196                                         goto out;
 197                                 }
 198                         }
 199                         *ino = inode_number;
 200                         *ino_back = backlink;
 201                         return bh;
 202                 }
 203         }
 204  out:
 205         if (cpnt)
 206                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 207         brelse(bh);
 208         return NULL;
 209 }
 210 
 211 int isofs_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 212         struct inode ** result)
 213 {
 214         int ino, ino_back;
 215         struct buffer_head * bh;
 216 
 217 #ifdef DEBUG
 218         printk("lookup: %x %d\n",dir->i_ino, len);
 219 #endif
 220         *result = NULL;
 221         if (!dir)
 222                 return -ENOENT;
 223 
 224         if (!S_ISDIR(dir->i_mode)) {
 225                 iput(dir);
 226                 return -ENOENT;
 227         }
 228 
 229         ino = 0;
 230         if (dir->i_dev == cache.dev && 
 231             dir->i_ino == cache.dir &&
 232             len == cache.dlen && 
 233             isofs_match(len, name, cache.filename, cache.dlen))
 234           {
 235             ino = cache.ino;
 236             ino_back = dir->i_ino;
 237             /* These two cases are special, but since they are at the start
 238                of the directory, we can just as easily search there */
 239             if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
 240             if (cache.dlen == 2 && cache.filename[0] == '.' && 
 241                 cache.filename[1] == '.') ino = 0;
 242           };
 243 
 244         if (!ino) {
 245           if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))) {
 246             iput(dir);
 247             return -ENOENT;
 248           }
 249           brelse(bh);
 250         };
 251 
 252         if (!(*result = iget(dir->i_sb,ino))) {
 253                 iput(dir);
 254                 return -EACCES;
 255         }
 256 
 257         /* We need this backlink for the ".." entry unless the name that we
 258            are looking up traversed a mount point (in which case the inode
 259            may not even be on an iso9660 filesystem, and writing to
 260            u.isofs_i would only cause memory corruption).
 261         */
 262         
 263         if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
 264           (*result)->u.isofs_i.i_backlink = ino_back; 
 265         }
 266         
 267         iput(dir);
 268         return 0;
 269 }

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