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

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