home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / isofs / namei.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-12  |  6.8 KB  |  269 lines

  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)
  28. {
  29.     register int same __asm__("ax");
  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__("cld\n\t"
  49.         "repe ; cmpsb\n\t"
  50.         "setz %%al"
  51.         :"=a" (same)
  52.         :"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len)
  53.         :"cx","di","si");
  54.     return same;
  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,
  66.     const char * name, int namelen, int * ino, int * 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.             cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
  119.             memcpy(cpnt, bh->b_data, bufsize);
  120.             de = (struct iso_directory_record *)
  121.               ((char *)cpnt + old_offset);
  122.             brelse(bh);
  123.             offset = f_pos & (bufsize - 1);
  124.             block = isofs_bmap(dir,f_pos>>bufbits);
  125.             if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
  126.                     kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  127.                 return 0;
  128.             };
  129.             memcpy((char *)cpnt+bufsize,bh->b_data,bufsize);
  130.         }
  131.         
  132.         /* Handle the '.' case */
  133.         
  134.         if (de->name[0]==0 && de->name_len[0]==1) {
  135.             inode_number = dir->i_ino;
  136.             backlink = 0;
  137.         }
  138.         
  139.         /* Handle the '..' case */
  140.  
  141.         if (de->name[0]==1 && de->name_len[0]==1) {
  142. #if 0
  143.             printk("Doing .. (%d %d)",
  144.                    dir->i_sb->s_firstdatazone << bufbits,
  145.                    dir->i_ino);
  146. #endif
  147.             if((dir->i_sb->u.isofs_sb.s_firstdatazone
  148.                 << bufbits) != dir->i_ino)
  149.                 inode_number = dir->u.isofs_i.i_backlink;
  150.             else
  151.                 inode_number = dir->i_ino;
  152.             backlink = 0;
  153.         }
  154.     
  155.         dlen = de->name_len[0];
  156.         dpnt = de->name;
  157.         /* Now convert the filename in the buffer to lower case */
  158.         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
  159.         if (rrflag) {
  160.           if (rrflag == -1) goto out; /* Relocated deep directory */
  161.         } else {
  162.           if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
  163.             for (i = 0; i < dlen; i++) {
  164.               c = dpnt[i];
  165.               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
  166.               if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
  167.             dlen -= 2;
  168.             break;
  169.               }
  170.               if (c == ';') c = '.';
  171.               de->name[i] = c;
  172.             }
  173.             /* This allows us to match with and without a trailing
  174.                period.  */
  175.             if(dpnt[dlen-1] == '.' && namelen == dlen-1)
  176.               dlen--;
  177.           }
  178.         }
  179.         match = isofs_match(namelen,name,dpnt,dlen);
  180.         if (cpnt) {
  181.             kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  182.             cpnt = NULL;
  183.         }
  184.  
  185.         if(rrflag) kfree(dpnt);
  186.         if (match) {
  187.             if(inode_number == -1) {
  188.                 /* Should only happen for the '..' entry */
  189.                 inode_number = 
  190.                     isofs_lookup_grandparent(dir,
  191.                        find_rock_ridge_relocation(de,dir));
  192.                 if(inode_number == -1){
  193.                     /* Should never happen */
  194.                     printk("Backlink not properly set.\n");
  195.                     goto out;
  196.                 }
  197.             }
  198.             *ino = inode_number;
  199.             *ino_back = backlink;
  200.             return bh;
  201.         }
  202.     }
  203.  out:
  204.     if (cpnt)
  205.         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  206.     brelse(bh);
  207.     return NULL;
  208. }
  209.  
  210. int isofs_lookup(struct inode * dir,const char * name, int len,
  211.     struct inode ** result)
  212. {
  213.     int ino, ino_back;
  214.     struct buffer_head * bh;
  215.  
  216. #ifdef DEBUG
  217.     printk("lookup: %x %d\n",dir->i_ino, len);
  218. #endif
  219.     *result = NULL;
  220.     if (!dir)
  221.         return -ENOENT;
  222.  
  223.     if (!S_ISDIR(dir->i_mode)) {
  224.         iput(dir);
  225.         return -ENOENT;
  226.     }
  227.  
  228.     ino = 0;
  229.     if (dir->i_dev == cache.dev && 
  230.         dir->i_ino == cache.dir &&
  231.         len == cache.dlen && 
  232.         isofs_match(len, name, cache.filename, cache.dlen))
  233.       {
  234.         ino = cache.ino;
  235.         ino_back = dir->i_ino;
  236.         /* These two cases are special, but since they are at the start
  237.            of the directory, we can just as easily search there */
  238.         if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
  239.         if (cache.dlen == 2 && cache.filename[0] == '.' && 
  240.         cache.filename[1] == '.') ino = 0;
  241.       };
  242.  
  243.     if (!ino) {
  244.       if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))) {
  245.         iput(dir);
  246.         return -ENOENT;
  247.       }
  248.       brelse(bh);
  249.     };
  250.  
  251.     if (!(*result = iget(dir->i_sb,ino))) {
  252.         iput(dir);
  253.         return -EACCES;
  254.     }
  255.  
  256.     /* We need this backlink for the ".." entry unless the name that we
  257.        are looking up traversed a mount point (in which case the inode
  258.        may not even be on an iso9660 filesystem, and writing to
  259.        u.isofs_i would only cause memory corruption).
  260.     */
  261.     
  262.     if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
  263.       (*result)->u.isofs_i.i_backlink = ino_back; 
  264.     }
  265.     
  266.     iput(dir);
  267.     return 0;
  268. }
  269.