rock.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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