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

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