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, 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, 
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 

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