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 / dir.c next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  6.8 KB  |  266 lines

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