home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / isofs / namei.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  6.3 KB  |  262 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. #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)
  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,
  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,
  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. }
  262.