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

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