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 / dir.c next >
Encoding:
C/C++ Source or Header  |  1994-03-01  |  6.4 KB  |  242 lines

  1. /*
  2.  *  linux/fs/isofs/dir.c
  3.  *
  4.  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
  5.  *
  6.  *  (C) 1991  Linus Torvalds - minix filesystem
  7.  *
  8.  *  isofs directory handling functions
  9.  */
  10.  
  11. #include <linux/errno.h>
  12.  
  13. #include <asm/segment.h>
  14.  
  15. #include <linux/fs.h>
  16. #include <linux/iso_fs.h>
  17. #include <linux/kernel.h>
  18. #include <linux/stat.h>
  19. #include <linux/string.h>
  20. #include <linux/mm.h>
  21. #include <linux/malloc.h>
  22.  
  23. static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
  24.  
  25. static struct file_operations isofs_dir_operations = {
  26.     NULL,            /* lseek - default */
  27.     NULL,            /* read */
  28.     NULL,            /* write - bad */
  29.     isofs_readdir,        /* readdir */
  30.     NULL,            /* select - default */
  31.     NULL,            /* ioctl - default */
  32.     NULL,            /* no special open code */
  33.     NULL,            /* no special release code */
  34.     NULL            /* fsync */
  35. };
  36.  
  37. /*
  38.  * directories can handle most operations...
  39.  */
  40. struct inode_operations isofs_dir_inode_operations = {
  41.     &isofs_dir_operations,    /* default directory file-ops */
  42.     NULL,          /* create */
  43.     isofs_lookup,        /* lookup */
  44.     NULL,                /* link */
  45.     NULL,               /* unlink */
  46.     NULL,               /* symlink */
  47.     NULL,               /* mkdir */
  48.     NULL,            /* rmdir */
  49.     NULL,            /* mknod */
  50.     NULL,            /* rename */
  51.     NULL,            /* readlink */
  52.     NULL,            /* follow_link */
  53.     isofs_bmap,        /* bmap */
  54.     NULL,            /* truncate */
  55.     NULL            /* permission */
  56. };
  57.  
  58. /* This is used to speed up lookup.  Without this we would need to
  59. make a linear search of the directory to find the file that the
  60. directory read just returned.  This is a single element cache. */
  61.  
  62. struct lookup_cache cache = {0,};
  63.  
  64. static int isofs_readdir(struct inode * inode, struct file * filp,
  65.     struct dirent * dirent, int count)
  66. {
  67.     unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  68.     unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
  69.     unsigned int block,offset,i, j;
  70.     char c = 0;
  71.     int inode_number;
  72.     struct buffer_head * bh;
  73.     void * cpnt = NULL;
  74.     unsigned int old_offset;
  75.     int dlen, rrflag;
  76.     char * dpnt;
  77.     struct iso_directory_record * de;
  78.     
  79.     if (!inode || !S_ISDIR(inode->i_mode))
  80.         return -EBADF;
  81.     
  82.     offset = filp->f_pos & (bufsize - 1);
  83.     block = isofs_bmap(inode,filp->f_pos>>bufbits);
  84.     if (!block || !(bh = bread(inode->i_dev,block,bufsize)))
  85.         return 0;
  86.     
  87.     while (filp->f_pos < inode->i_size) {
  88. #ifdef DEBUG
  89.         printk("Block, offset: %x %x %x\n",
  90.                block, offset, filp->f_pos);
  91. #endif
  92.         de = (struct iso_directory_record *) (bh->b_data + offset);
  93.         inode_number = (block << bufbits) + (offset & (bufsize - 1));
  94.         
  95.         /* If the length byte is zero, we should move on to the next
  96.            CDROM sector.  If we are at the end of the directory, we
  97.            kick out of the while loop. */
  98.         
  99.         if (*((unsigned char *) de) == 0)  {
  100.             brelse(bh);
  101.             offset = 0;
  102.             filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
  103.                        + ISOFS_BLOCK_SIZE);
  104.             block = isofs_bmap(inode,(filp->f_pos)>>bufbits);
  105.             if (!block
  106.                 || !(bh = bread(inode->i_dev,block,bufsize)))
  107.                 return 0;
  108.             continue;
  109.         }
  110.  
  111.         /* Make sure that the entire directory record is in the
  112.            current bh block.
  113.            If not, we malloc a buffer, and put the two halves together,
  114.            so that we can cleanly read the block */
  115.  
  116.         old_offset = offset;
  117.         offset += *((unsigned char *) de);
  118.         filp->f_pos += *((unsigned char *) de);
  119.  
  120.         if (offset >=  bufsize) {
  121.             cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
  122.             memcpy(cpnt, bh->b_data, bufsize);
  123.             de = (struct iso_directory_record *)
  124.                 ((char *)cpnt + old_offset);
  125.             brelse(bh);
  126.             offset = filp->f_pos & (bufsize - 1);
  127.             block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
  128.             if (!block
  129.                 || !(bh = bread(inode->i_dev,block,bufsize))) {
  130.                     kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  131.                 return 0;
  132.             };
  133.             memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
  134.         }
  135.         
  136.         /* Handle the case of the '.' directory */
  137.  
  138.         rrflag = 0;
  139.         i = 1;
  140.         if (de->name_len[0] == 1 && de->name[0] == 0) {
  141.             put_fs_byte('.',dirent->d_name);
  142.             inode_number = inode->i_ino;
  143.             dpnt = ".";
  144.         }
  145.         
  146.         /* Handle the case of the '..' directory */
  147.         
  148.         else if (de->name_len[0] == 1 && de->name[0] == 1) {
  149.             put_fs_byte('.',dirent->d_name);
  150.             put_fs_byte('.',dirent->d_name+1);
  151.             i = 2;
  152.             dpnt = "..";
  153.             if((inode->i_sb->u.isofs_sb.s_firstdatazone
  154.                 << bufbits) != inode->i_ino)
  155.                 inode_number = inode->u.isofs_i.i_backlink;
  156.             else
  157.                 inode_number = inode->i_ino;
  158.             
  159.             /* This should never happen, but who knows.  Try to be forgiving */
  160.             if(inode_number == -1) {
  161.                 inode_number = 
  162.                     isofs_lookup_grandparent(inode,
  163.                          find_rock_ridge_relocation(de, inode));
  164.                 if(inode_number == -1){ /* Should never happen */
  165.                     printk("Backlink not properly set.\n");
  166.                     goto out;
  167.                 };
  168.             }
  169.         }
  170.         
  171.         /* Handle everything else.  Do name translation if there
  172.            is no Rock Ridge NM field. */
  173.         
  174.         else {
  175.             dlen = de->name_len[0];
  176.             dpnt = de->name;
  177.             i = dlen;
  178.             rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
  179.             if (rrflag) {
  180.               if (rrflag == -1) {  /* This is a rock ridge reloc dir */
  181.                 if (cpnt) {
  182.                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  183.                 cpnt = NULL;
  184.                 };
  185.                 continue;
  186.               };
  187.               i = dlen;
  188.             }
  189.             else
  190.               if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
  191.                 for (i = 0; i < dlen && i < NAME_MAX; i++) {
  192.                   if (!(c = dpnt[i])) break;
  193.                   if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
  194.                   if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
  195.                 break;  /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
  196.                   if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
  197.                 break;  /* Drop trailing ';1' */
  198.                   if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
  199.                   dpnt[i] = c;
  200.               };
  201.             
  202.             for(j=0; j<i; j++)
  203.               put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
  204.               };
  205. #if 0
  206.         printk("Nchar: %d\n",i);
  207. #endif
  208.  
  209.         if (i && i+1 < sizeof(cache.filename)) {
  210.             cache.ino = inode_number;
  211.             cache.dir = inode->i_ino;
  212.             cache.dev = inode->i_dev;
  213.             strncpy(cache.filename, dpnt, i);
  214.             cache.dlen = dlen;
  215.               };
  216.  
  217.         if (rrflag) kfree(dpnt);
  218.         if (cpnt) {
  219.             kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  220.             cpnt = NULL;
  221.         };
  222.         
  223.         if (i) {
  224.             put_fs_long(inode_number, &dirent->d_ino);
  225.             put_fs_byte(0,i+dirent->d_name);
  226.             put_fs_word(i,&dirent->d_reclen);
  227.             brelse(bh);
  228.             return i;
  229.         }
  230.           }
  231.     /* We go here for any condition we cannot handle.  We also drop through
  232.        to here at the end of the directory. */
  233.  out:
  234.     if (cpnt)
  235.         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
  236.     brelse(bh);
  237.     return 0;
  238. }
  239.  
  240.  
  241.  
  242.