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 / rock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-06  |  13.5 KB  |  538 lines

  1. /*
  2.  *  linux/fs/isofs/rock.c
  3.  *
  4.  *  (C) 1992, 1993  Eric Youngdale
  5.  *
  6.  *  Rock Ridge Extensions to iso9660
  7.  */
  8. #ifdef MODULE
  9. #include <linux/module.h>
  10. #endif
  11.  
  12. #include <linux/stat.h>
  13. #include <linux/sched.h>
  14. #include <linux/iso_fs.h>
  15. #include <linux/string.h>
  16. #include <linux/mm.h>
  17. #include <linux/malloc.h>
  18.  
  19. #include "rock.h"
  20.  
  21. /* These functions are designed to read the system areas of a directory record
  22.  * and extract relevant information.  There are different functions provided
  23.  * depending upon what information we need at the time.  One function fills
  24.  * out an inode structure, a second one extracts a filename, a third one
  25.  * returns a symbolic link name, and a fourth one returns the extent number
  26.  * for the file. */
  27.  
  28. #define SIG(A,B) ((A << 8) | B)
  29.  
  30.  
  31. /* This is a way of ensuring that we have something in the system
  32.    use fields that is compatible with Rock Ridge */
  33. #define CHECK_SP(FAIL)                       \
  34.       if(rr->u.SP.magic[0] != 0xbe) FAIL;    \
  35.       if(rr->u.SP.magic[1] != 0xef) FAIL;
  36.  
  37. /* We define a series of macros because each function must do exactly the
  38.    same thing in certain places.  We use the macros to ensure that everything
  39.    is done correctly */
  40.  
  41. #define CONTINUE_DECLS \
  42.   int cont_extent = 0, cont_offset = 0, cont_size = 0;   \
  43.   void * buffer = 0
  44.  
  45. #define CHECK_CE                       \
  46.       {cont_extent = isonum_733(rr->u.CE.extent); \
  47.       cont_offset = isonum_733(rr->u.CE.offset); \
  48.       cont_size = isonum_733(rr->u.CE.size);}
  49.  
  50. #define SETUP_ROCK_RIDGE(DE,CHR,LEN)                            \
  51.   {LEN= sizeof(struct iso_directory_record) + DE->name_len[0];    \
  52.   if(LEN & 1) LEN++;                        \
  53.   CHR = ((unsigned char *) DE) + LEN;                \
  54.   LEN = *((unsigned char *) DE) - LEN;}
  55.  
  56. #define MAYBE_CONTINUE(LABEL,DEV) \
  57.   {if (buffer) kfree(buffer); \
  58.   if (cont_extent){ \
  59.     int block, offset, offset1; \
  60.     struct buffer_head * bh; \
  61.     buffer = kmalloc(cont_size,GFP_KERNEL); \
  62.     if (!buffer) goto out; \
  63.     block = cont_extent; \
  64.     offset = cont_offset; \
  65.     offset1 = 0; \
  66.     if(ISOFS_BUFFER_SIZE(DEV) == 1024) {     \
  67.       block <<= 1;    \
  68.       if (offset >= 1024) block++; \
  69.       offset &= 1023; \
  70.       if(offset + cont_size >= 1024) { \
  71.       bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \
  72.       if(!bh) {printk("Unable to read continuation Rock Ridge record\n"); \
  73.              kfree(buffer); \
  74.              buffer = NULL; } else { \
  75.         memcpy(buffer, bh->b_data + offset, 1024 - offset); \
  76.             brelse(bh); \
  77.         offset1 = 1024 - offset; \
  78.         offset = 0;} \
  79.       }  \
  80.     };     \
  81.     if(buffer) { \
  82.       bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
  83.       if(bh){       \
  84.         memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
  85.         brelse(bh); \
  86.         chr = (unsigned char *) buffer; \
  87.         len = cont_size; \
  88.         cont_extent = 0; \
  89.         cont_size = 0; \
  90.         cont_offset = 0; \
  91.         goto LABEL; \
  92.       };    \
  93.     } \
  94.     printk("Unable to read rock-ridge attributes\n");    \
  95.   }}
  96.  
  97. /* This is the inner layer of the get filename routine, and is called
  98.    for each system area and continuation record related to the file */
  99.  
  100. int find_rock_ridge_relocation(struct iso_directory_record * de, 
  101.                    struct inode * inode) {
  102.   int flag;
  103.   int len;
  104.   int retval;
  105.   unsigned char * chr;
  106.   CONTINUE_DECLS;
  107.   flag = 0;
  108.   
  109.   /* If this is a '..' then we are looking for the parent, otherwise we
  110.      are looking for the child */
  111.   
  112.   if (de->name[0]==1 && de->name_len[0]==1) flag = 1;
  113.   /* Return value if we do not find appropriate record. */
  114.   retval = isonum_733 (de->extent);
  115.   
  116.   if (!inode->i_sb->u.isofs_sb.s_rock) return retval;
  117.  
  118.   SETUP_ROCK_RIDGE(de, chr, len);
  119.  repeat:
  120.   {
  121.     int rrflag, sig;
  122.     struct rock_ridge * rr;
  123.     
  124.     while (len > 1){ /* There may be one byte for padding somewhere */
  125.       rr = (struct rock_ridge *) chr;
  126.       if (rr->len == 0) goto out; /* Something got screwed up here */
  127.       sig = (chr[0] << 8) + chr[1];
  128.       chr += rr->len; 
  129.       len -= rr->len;
  130.  
  131.       switch(sig){
  132.       case SIG('R','R'):
  133.     rrflag = rr->u.RR.flags[0];
  134.     if (flag && !(rrflag & RR_PL)) goto out;
  135.     if (!flag && !(rrflag & RR_CL)) goto out;
  136.     break;
  137.       case SIG('S','P'):
  138.     CHECK_SP(goto out);
  139.     break;
  140.       case SIG('C','L'):
  141. #ifdef DEBUG
  142.     printk("RR: CL\n");
  143. #endif
  144.     if (flag == 0) {
  145.       retval = isonum_733(rr->u.CL.location);
  146.       goto out;
  147.     };
  148.     break;
  149.       case SIG('P','L'):
  150. #ifdef DEBUG
  151.     printk("RR: PL\n");
  152. #endif
  153.     if (flag != 0) {
  154.       retval = isonum_733(rr->u.PL.location);
  155.       goto out;
  156.     };
  157.     break;
  158.       case SIG('C','E'):
  159.     CHECK_CE; /* This tells is if there is a continuation record */
  160.     break;
  161.       default:
  162.     break;
  163.       }
  164.     };
  165.   };
  166.   MAYBE_CONTINUE(repeat, inode);
  167.   return retval;
  168.  out:
  169.   if(buffer) kfree(buffer);
  170.   return retval;
  171. }
  172.  
  173. int get_rock_ridge_filename(struct iso_directory_record * de,
  174.                char ** name, int * namlen, struct inode * inode)
  175. {
  176.   int len;
  177.   unsigned char * chr;
  178.   CONTINUE_DECLS;
  179.   char * retname = NULL;
  180.   int retnamlen = 0, truncate=0;
  181.  
  182.   if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
  183.  
  184.   SETUP_ROCK_RIDGE(de, chr, len);
  185.  repeat:
  186.   {
  187.     struct rock_ridge * rr;
  188.     int sig;
  189.     
  190.     while (len > 1){ /* There may be one byte for padding somewhere */
  191.       rr = (struct rock_ridge *) chr;
  192.       if (rr->len == 0) goto out; /* Something got screwed up here */
  193.       sig = (chr[0] << 8) + chr[1];
  194.       chr += rr->len; 
  195.       len -= rr->len;
  196.  
  197.       switch(sig){
  198.       case SIG('R','R'):
  199.     if((rr->u.RR.flags[0] & RR_NM) == 0) goto out;
  200.     break;
  201.       case SIG('S','P'):
  202.     CHECK_SP(goto out);
  203.     break;
  204.       case SIG('C','E'):
  205.     CHECK_CE;
  206.     break;
  207.       case SIG('N','M'):
  208.     if (truncate) break;
  209.     if (rr->u.NM.flags & ~1) {
  210.       printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
  211.       break;
  212.     };
  213.     if (!retname){
  214.       retname = (char *) kmalloc (255,GFP_KERNEL);
  215.       /* This may be a waste, but we only
  216.          need this for a moment.  The layers
  217.          that call this function should
  218.          deallocate the mem fairly soon
  219.          after control is returned */
  220.  
  221.       if (!retname) goto out;
  222.       *retname = 0; /* Zero length string */
  223.       retnamlen = 0;
  224.     };
  225.     if((strlen(retname) + rr->len - 5) >= 254) {
  226.       truncate = 1;
  227.       break;
  228.     };
  229.     strncat(retname, rr->u.NM.name, rr->len - 5);
  230.     retnamlen += rr->len - 5;
  231.     break;
  232.       case SIG('R','E'):
  233. #ifdef DEBUG
  234.     printk("RR: RE (%x)\n", inode->i_ino);
  235. #endif
  236.     if (buffer) kfree(buffer);
  237.     if (retname) kfree(retname);
  238.     return -1;
  239.       default:
  240.     break;
  241.       }
  242.     };
  243.   }
  244.   MAYBE_CONTINUE(repeat,inode);
  245.   if(retname){
  246.     *name = retname;
  247.     *namlen = retnamlen;
  248.     return 1;
  249.   };
  250.   return 0;  /* This file did not have a NM field */
  251.  out:
  252.   if(buffer) kfree(buffer);
  253.   if (retname) kfree(retname);
  254.   return 0;
  255. }
  256.  
  257. int parse_rock_ridge_inode(struct iso_directory_record * de,
  258.                struct inode * inode){
  259.   int len;
  260.   unsigned char * chr;
  261.   CONTINUE_DECLS;
  262.  
  263.   if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
  264.  
  265.   SETUP_ROCK_RIDGE(de, chr, len);
  266.  repeat:
  267.   {
  268.     int cnt, sig;
  269.     struct inode * reloc;
  270.     struct rock_ridge * rr;
  271.     int rootflag;
  272.     
  273.     while (len > 1){ /* There may be one byte for padding somewhere */
  274.       rr = (struct rock_ridge *) chr;
  275.       if (rr->len == 0) goto out; /* Something got screwed up here */
  276.       sig = (chr[0] << 8) + chr[1];
  277.       chr += rr->len; 
  278.       len -= rr->len;
  279.       
  280.       switch(sig){
  281.       case SIG('R','R'):
  282.     if((rr->u.RR.flags[0] & 
  283.          (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out;
  284.     break;
  285.       case SIG('S','P'):
  286.     CHECK_SP(goto out);
  287.     break;
  288.       case SIG('C','E'):
  289.     CHECK_CE;
  290.     break;
  291.       case SIG('E','R'):
  292.     printk("ISO9660 Extensions: ");
  293.     { int p;
  294.       for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
  295.     };
  296.       printk("\n");
  297.     break;
  298.       case SIG('P','X'):
  299.     inode->i_mode  = isonum_733(rr->u.PX.mode);
  300.     inode->i_nlink = isonum_733(rr->u.PX.n_links);
  301.     inode->i_uid   = isonum_733(rr->u.PX.uid);
  302.     inode->i_gid   = isonum_733(rr->u.PX.gid);
  303.     break;
  304.       case SIG('P','N'):
  305.     { int high, low;
  306.       high = isonum_733(rr->u.PN.dev_high);
  307.       low = isonum_733(rr->u.PN.dev_low);
  308.       /*
  309.        * The Rock Ridge standard specifies that if sizeof(dev_t) <=4,
  310.        * then the high field is unused, and the device number is completely
  311.        * stored in the low field.  Some writers may ignore this subtlety,
  312.        * and as a result we test to see if the entire device number is
  313.        * stored in the low field, and use that.
  314.        */
  315.       if(MINOR(low) != low && high == 0) {
  316.         inode->i_rdev = low;
  317.       } else {
  318.         inode->i_rdev = MKDEV(high, low);
  319.       }
  320.     };
  321.     break;
  322.       case SIG('T','F'):
  323.     /* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
  324.        Try and handle this correctly for either case. */
  325.     cnt = 0; /* Rock ridge never appears on a High Sierra disk */
  326.     if(rr->u.TF.flags & TF_CREATE) 
  327.       inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
  328.     if(rr->u.TF.flags & TF_MODIFY) 
  329.       inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
  330.     if(rr->u.TF.flags & TF_ACCESS) 
  331.       inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0);
  332.     if(rr->u.TF.flags & TF_ATTRIBUTES) 
  333.       inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
  334.     break;
  335.       case SIG('S','L'):
  336.     {int slen;
  337.      struct SL_component * slp;
  338.      slen = rr->len - 5;
  339.      slp = &rr->u.SL.link;
  340.      inode->i_size = 0;
  341.      while (slen > 1){
  342.        rootflag = 0;
  343.        switch(slp->flags &~1){
  344.        case 0:
  345.          inode->i_size += slp->len;
  346.          break;
  347.        case 2:
  348.          inode->i_size += 1;
  349.          break;
  350.        case 4:
  351.          inode->i_size += 2;
  352.          break;
  353.        case 8:
  354.          rootflag = 1;
  355.          inode->i_size += 1;
  356.          break;
  357.        default:
  358.          printk("Symlink component flag not implemented\n");
  359.        };
  360.        slen -= slp->len + 2;
  361.        slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
  362.  
  363.        if(slen < 2) break;
  364.        if(!rootflag) inode->i_size += 1;
  365.      };
  366.        };
  367.     break;
  368.       case SIG('R','E'):
  369.     printk("Attempt to read inode for relocated directory\n");
  370.     goto out;
  371.       case SIG('C','L'):
  372. #ifdef DEBUG
  373.     printk("RR CL (%x)\n",inode->i_ino);
  374. #endif
  375.     inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
  376.         inode -> i_sb -> u.isofs_sb.s_log_zone_size;
  377.     reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
  378.     inode->i_mode = reloc->i_mode;
  379.     inode->i_nlink = reloc->i_nlink;
  380.     inode->i_uid = reloc->i_uid;
  381.     inode->i_gid = reloc->i_gid;
  382.     inode->i_rdev = reloc->i_rdev;
  383.     inode->i_size = reloc->i_size;
  384.     inode->i_atime = reloc->i_atime;
  385.     inode->i_ctime = reloc->i_ctime;
  386.     inode->i_mtime = reloc->i_mtime;
  387.     iput(reloc);
  388.     break;
  389.       default:
  390.     break;
  391.       }
  392.     };
  393.   }
  394.   MAYBE_CONTINUE(repeat,inode);
  395.   return 0;
  396.  out:
  397.   if(buffer) kfree(buffer);
  398.   return 0;
  399. }
  400.  
  401.  
  402. /* Returns the name of the file that this inode is symlinked to.  This is
  403.    in malloc'd memory, so it needs to be freed, once we are through with it */
  404.  
  405. char * get_rock_ridge_symlink(struct inode * inode)
  406. {
  407.   unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  408.   unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
  409.   struct buffer_head * bh;
  410.   unsigned char * pnt;
  411.   void * cpnt = NULL;
  412.   char * rpnt;
  413.   struct iso_directory_record * raw_inode;
  414.   CONTINUE_DECLS;
  415.   int block;
  416.   int sig;
  417.   int rootflag;
  418.   int len;
  419.   unsigned char * chr;
  420.   struct rock_ridge * rr;
  421.   
  422.   if (!inode->i_sb->u.isofs_sb.s_rock)
  423.     panic("Cannot have symlink with high sierra variant of iso filesystem\n");
  424.  
  425.   rpnt = 0;
  426.   
  427.   block = inode->i_ino >> bufbits;
  428.   if (!(bh=bread(inode->i_dev,block, bufsize))) {
  429.     printk("unable to read i-node block");
  430.     return NULL;
  431.   };
  432.   
  433.   pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1));
  434.   
  435.   raw_inode = ((struct iso_directory_record *) pnt);
  436.   
  437.   if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
  438.     int frag1, offset;
  439.     
  440.     offset = (inode->i_ino & (bufsize - 1));
  441.     frag1 = bufsize - offset;
  442.     cpnt = kmalloc(*pnt,GFP_KERNEL);
  443.     if(!cpnt) return NULL;
  444.     memcpy(cpnt, bh->b_data + offset, frag1);
  445.     brelse(bh);
  446.     if (!(bh = bread(inode->i_dev,++block, bufsize))) {
  447.       kfree(cpnt);
  448.       printk("unable to read i-node block");
  449.       return NULL;
  450.     };
  451.     offset += *pnt - bufsize;
  452.     memcpy((char *)cpnt+frag1, bh->b_data, offset);
  453.     pnt = ((unsigned char *) cpnt);
  454.     raw_inode = ((struct iso_directory_record *) pnt);
  455.   };
  456.   
  457.   /* Now test for possible Rock Ridge extensions which will override some of
  458.      these numbers in the inode structure. */
  459.   
  460.   SETUP_ROCK_RIDGE(raw_inode, chr, len);
  461.   
  462.  repeat:
  463.   while (len > 1){ /* There may be one byte for padding somewhere */
  464.     if (rpnt) break;
  465.     rr = (struct rock_ridge *) chr;
  466.     if (rr->len == 0) goto out; /* Something got screwed up here */
  467.     sig = (chr[0] << 8) + chr[1];
  468.     chr += rr->len; 
  469.     len -= rr->len;
  470.     
  471.     switch(sig){
  472.     case SIG('R','R'):
  473.       if((rr->u.RR.flags[0] & RR_SL) == 0) goto out;
  474.       break;
  475.     case SIG('S','P'):
  476.       CHECK_SP(goto out);
  477.       break;
  478.     case SIG('S','L'):
  479.       {int slen;
  480.        struct SL_component * slp;
  481.        slen = rr->len - 5;
  482.        slp = &rr->u.SL.link;
  483.        while (slen > 1){
  484.      if (!rpnt){
  485.        rpnt = (char *) kmalloc (inode->i_size +1, GFP_KERNEL);
  486.        if (!rpnt) goto out;
  487.        *rpnt = 0;
  488.      };
  489.      rootflag = 0;
  490.      switch(slp->flags &~1){
  491.      case 0:
  492.        strncat(rpnt,slp->text, slp->len);
  493.        break;
  494.      case 2:
  495.        strcat(rpnt,".");
  496.        break;
  497.      case 4:
  498.        strcat(rpnt,"..");
  499.        break;
  500.      case 8:
  501.        rootflag = 1;
  502.        strcat(rpnt,"/");
  503.        break;
  504.      default:
  505.        printk("Symlink component flag not implemented (%d)\n",slen);
  506.      };
  507.      slen -= slp->len + 2;
  508.      slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
  509.  
  510.      if(slen < 2) break;
  511.      if(!rootflag) strcat(rpnt,"/");
  512.        };
  513.        break;
  514.      default:
  515.        break;
  516.      }
  517.     };
  518.   };
  519.   MAYBE_CONTINUE(repeat,inode);
  520.   brelse(bh);
  521.   
  522.   if (cpnt) {
  523.     kfree(cpnt);
  524.     cpnt = NULL;
  525.   };
  526.  
  527.   return rpnt;
  528.  out:
  529.   if(buffer) kfree(buffer);
  530.   return 0;
  531. }
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.