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

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