root/fs/isofs/rock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_rock_ridge_relocation
  2. get_rock_ridge_filename
  3. parse_rock_ridge_inode
  4. get_rock_ridge_symlink

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

/* [previous][next][first][last][top][bottom][index][help] */