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

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