Home | History | Annotate | Line # | Download | only in dist
rock.c revision 1.1.4.2
      1 /*
      2  * File rock.c - generate RRIP  records for iso9660 filesystems.
      3 
      4    Written by Eric Youngdale (1993).
      5 
      6    Copyright 1993 Yggdrasil Computing, Incorporated
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 2, or (at your option)
     11    any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
     21 
     22 #include <stdlib.h>
     23 
     24 #include "config.h"
     25 
     26 #ifndef VMS
     27 #if defined(MAJOR_IN_SYSMACROS)
     28 #include <sys/sysmacros.h>
     29 #endif
     30 
     31 #ifdef HAVE_UNISTD_H
     32 #include <unistd.h>
     33 #endif
     34 
     35 #endif
     36 #if defined(MAJOR_IN_MKDEV)
     37 #include <sys/types.h>
     38 #include <sys/mkdev.h>
     39 #endif
     40 
     41 #include "mkisofs.h"
     42 #include "iso9660.h"
     43 #include <string.h>
     44 
     45 #ifdef	DOESNT_WORK
     46 
     47 #ifdef NON_UNIXFS
     48 #define S_ISLNK(m)	(0)
     49 #else
     50 #ifndef S_ISLNK
     51 #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
     52 #endif
     53 #endif
     54 
     55 #else
     56 #include <statdefs.h>
     57 #endif
     58 
     59 #define SU_VERSION 1
     60 
     61 #define SL_ROOT    8
     62 #define SL_PARENT  4
     63 #define SL_CURRENT 2
     64 #define SL_CONTINUE 1
     65 
     66 #define CE_SIZE 28
     67 #define CL_SIZE 12
     68 #define ER_SIZE 8
     69 #define NM_SIZE 5
     70 #define PL_SIZE 12
     71 #define PN_SIZE 20
     72 #define PX_SIZE 36
     73 #define RE_SIZE 4
     74 #define SL_SIZE 20
     75 #define ZZ_SIZE 15
     76 #ifdef APPLE_HYB
     77 #define AA_SIZE 14		/* size of Apple extension */
     78 #endif /* APPLE_HYB */
     79 #ifdef __QNX__
     80 #define TF_SIZE (5 + 4 * 7)
     81 #else
     82 #define TF_SIZE (5 + 3 * 7)
     83 #endif
     84 
     85 /* If we need to store this number of bytes, make sure we
     86    do not box ourselves in so that we do not have room for
     87    a CE entry for the continuation record */
     88 
     89 #define MAYBE_ADD_CE_ENTRY(BYTES) \
     90     (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
     91 
     92 /*
     93  * Buffer to build RR attributes
     94  */
     95 
     96 static unsigned char Rock[16384];
     97 static unsigned char symlink_buff[256];
     98 static int ipnt = 0;
     99 static int recstart = 0;
    100 static int currlen = 0;
    101 static int mainrec = 0;
    102 static int reclimit;
    103 
    104 #ifdef APPLE_HYB
    105 /* if we are using the HFS name, we don't want the '/' character */
    106 static void
    107 rstrncpy(char *t, char *f, int c)
    108 {
    109 	while (c-- && *f) {
    110 	    switch (*f) {
    111 		case '/':
    112 		    *t = '_';
    113 		    break;
    114 		default:
    115 		    *t = *f;
    116 		    break;
    117 	    }
    118 	    t++; f++;
    119 	}
    120 }
    121 #endif /* APPLE HYB */
    122 
    123 static void add_CE_entry	__PR((void));
    124 
    125 static void add_CE_entry(){
    126           if(recstart)
    127 	    set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
    128 	  Rock[ipnt++] ='C';
    129 	  Rock[ipnt++] ='E';
    130 	  Rock[ipnt++] = CE_SIZE;
    131 	  Rock[ipnt++] = SU_VERSION;
    132 	  set_733((char*)Rock + ipnt, 0);
    133 	  ipnt += 8;
    134 	  set_733((char*)Rock + ipnt, 0);
    135 	  ipnt += 8;
    136 	  set_733((char*)Rock + ipnt, 0);
    137 	  ipnt += 8;
    138 	  recstart = ipnt;
    139 	  currlen = 0;
    140 	  if(!mainrec) mainrec = ipnt;
    141 	  reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
    142 }
    143 
    144 #ifdef __STDC__
    145 int generate_rock_ridge_attributes (char * whole_name, char * name,
    146 				    struct directory_entry * s_entry,
    147 				    struct stat * statbuf,
    148 				    struct stat * lstatbuf,
    149 				    int deep_opt)
    150 #else
    151 int generate_rock_ridge_attributes (whole_name, name,
    152 				    s_entry,
    153 				    statbuf,
    154 				    lstatbuf,
    155 				    deep_opt)
    156 char * whole_name; char * name; struct directory_entry * s_entry;
    157 struct stat * statbuf, *lstatbuf;
    158 int deep_opt;
    159 #endif
    160 {
    161   int flagpos, flagval;
    162   int need_ce;
    163 
    164   statbuf = statbuf;        /* this shuts up unreferenced compiler warnings */
    165   mainrec = recstart = ipnt = 0;
    166   reclimit = 0xf8;
    167 
    168   /* no need to fill in the RR stuff if we won't see the file */
    169   if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
    170     return 0;
    171 
    172   /* Obtain the amount of space that is currently used for the directory
    173      record.  Assume max for name, since name conflicts may cause us
    174      to rename the file later on */
    175   currlen = sizeof(s_entry->isorec);
    176 
    177 #ifdef APPLE_HYB
    178   /* if we have regular file, then add Apple extensions */
    179   if (S_ISREG(lstatbuf->st_mode) && apple_ext && s_entry->hfs_ent) {
    180     Rock[ipnt++] ='A';		/* AppleSignature */
    181     Rock[ipnt++] ='A';
    182     Rock[ipnt++] = AA_SIZE;	/* includes AppleSignature bytes */
    183     Rock[ipnt++] = 0x02;	/* SystemUseID */
    184     Rock[ipnt++] = s_entry->hfs_ent->type[0];
    185     Rock[ipnt++] = s_entry->hfs_ent->type[1];
    186     Rock[ipnt++] = s_entry->hfs_ent->type[2];
    187     Rock[ipnt++] = s_entry->hfs_ent->type[3];
    188     Rock[ipnt++] = s_entry->hfs_ent->creator[0];
    189     Rock[ipnt++] = s_entry->hfs_ent->creator[1];
    190     Rock[ipnt++] = s_entry->hfs_ent->creator[2];
    191     Rock[ipnt++] = s_entry->hfs_ent->creator[3];
    192     Rock[ipnt++] = (s_entry->hfs_ent->fdflags >> 8) & 0xff;
    193     Rock[ipnt++] = s_entry->hfs_ent->fdflags & 0xff;
    194   }
    195 #endif /* APPLE_HYB */
    196 
    197   /* Identify that we are using the SUSP protocol */
    198   if(deep_opt & NEED_SP){
    199 	  Rock[ipnt++] ='S';
    200 	  Rock[ipnt++] ='P';
    201 	  Rock[ipnt++] = 7;
    202 	  Rock[ipnt++] = SU_VERSION;
    203 	  Rock[ipnt++] = 0xbe;
    204 	  Rock[ipnt++] = 0xef;
    205 	  Rock[ipnt++] = 0;
    206   };
    207 
    208   /* First build the posix name field */
    209   Rock[ipnt++] ='R';
    210   Rock[ipnt++] ='R';
    211   Rock[ipnt++] = 5;
    212   Rock[ipnt++] = SU_VERSION;
    213   flagpos = ipnt;
    214   flagval = 0;
    215   Rock[ipnt++] = 0;   /* We go back and fix this later */
    216 
    217   if(strcmp(name,".")  && strcmp(name,"..")){
    218     char * npnt;
    219     int remain, use;
    220 
    221 #ifdef APPLE_HYB
    222     /* use the HFS name if it exists */
    223     if (USE_MAC_NAME(mac_name, s_entry)) {
    224 	remain = strlen(s_entry->hfs_ent->name);
    225 	npnt = s_entry->hfs_ent->name;
    226     }
    227     else {
    228 #endif
    229 
    230 	remain = strlen(name);
    231 	npnt = name;
    232 #ifdef APPLE_HYB
    233     }
    234 #endif /* APPLE_HYB */
    235 
    236     while(remain){
    237           use = remain;
    238 	  need_ce = 0;
    239 	  /* Can we fit this SUSP and a CE entry? */
    240 	  if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
    241 	    use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
    242 	    need_ce++;
    243 	  }
    244 
    245 	  /* Only room for 256 per SUSP field */
    246 	  if(use > 0xf8) use = 0xf8;
    247 
    248 	  /* First build the posix name field */
    249 	  Rock[ipnt++] ='N';
    250 	  Rock[ipnt++] ='M';
    251 	  Rock[ipnt++] = NM_SIZE + use;
    252 	  Rock[ipnt++] = SU_VERSION;
    253 	  Rock[ipnt++] = (remain != use ? 1 : 0);
    254 	  flagval |= (1<<3);
    255 #ifdef APPLE_HYB
    256 	  /* filter out any '/' character in HFS filename */
    257 	  if (USE_MAC_NAME(mac_name, s_entry))
    258 	    rstrncpy((char *)&Rock[ipnt], npnt, use);
    259 	  else
    260 #endif /* APPLE_HYB */
    261 	    strncpy((char *)&Rock[ipnt], npnt, use);
    262 	  npnt += use;
    263 	  ipnt += use;
    264 	  remain -= use;
    265 	  if(remain && need_ce) add_CE_entry();
    266 	};
    267   };
    268 
    269   /*
    270    * Add the posix modes
    271    */
    272   if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
    273   Rock[ipnt++] ='P';
    274   Rock[ipnt++] ='X';
    275   Rock[ipnt++] = PX_SIZE;
    276   Rock[ipnt++] = SU_VERSION;
    277   flagval |= (1<<0);
    278   set_733((char*)Rock + ipnt, lstatbuf->st_mode);
    279   ipnt += 8;
    280   set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
    281   ipnt += 8;
    282   set_733((char*)Rock + ipnt, lstatbuf->st_uid);
    283   ipnt += 8;
    284   set_733((char*)Rock + ipnt, lstatbuf->st_gid);
    285   ipnt += 8;
    286 
    287   /*
    288    * Check for special devices
    289    */
    290 #ifndef NON_UNIXFS
    291   if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
    292     if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
    293     Rock[ipnt++] ='P';
    294     Rock[ipnt++] ='N';
    295     Rock[ipnt++] = PN_SIZE;
    296     Rock[ipnt++] = SU_VERSION;
    297     flagval |= (1<<1);
    298 #if defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV)
    299     set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev ));
    300     ipnt += 8;
    301     set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev));
    302     ipnt += 8;
    303 #else
    304     /*
    305      * If we don't have sysmacros.h, then we have to guess as to how
    306      * best to pick apart the device number for major/minor.
    307      * Note: this may very well be wrong for many systems, so
    308      * it is always best to use the major/minor macros if the
    309      * system supports it.
    310      */
    311     if(sizeof(dev_t) <= 2) {
    312         set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8));
    313         ipnt += 8;
    314         set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff);
    315         ipnt += 8;
    316     }
    317     else if(sizeof(dev_t) <= 4) {
    318         set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8);
    319         ipnt += 8;
    320         set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff);
    321         ipnt += 8;
    322     }
    323     else {
    324         set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
    325         ipnt += 8;
    326         set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
    327         ipnt += 8;
    328     }
    329 #endif
    330   };
    331 #endif
    332   /*
    333    * Check for and symbolic links.  VMS does not have these.
    334    */
    335   if (S_ISLNK(lstatbuf->st_mode)){
    336     int lenpos, lenval, j0, j1;
    337     int nchar;
    338     unsigned char * cpnt, *cpnt1;
    339     nchar = readlink(whole_name, (char *)symlink_buff, sizeof(symlink_buff)-1);
    340     symlink_buff[nchar < 0 ? 0 : nchar] = 0;
    341     nchar = strlen((char *) symlink_buff);
    342     set_733(s_entry->isorec.size, 0);
    343     cpnt = &symlink_buff[0];
    344     flagval |= (1<<2);
    345 
    346     if (! split_SL_field)
    347       {
    348 	int sl_bytes = 0;
    349 	for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++)
    350 	  {
    351 	    if (*cpnt1 == '/')
    352 	      {
    353 		sl_bytes += 4;
    354 	      }
    355 	    else
    356 	      {
    357 		sl_bytes += 1;
    358 	      }
    359 	  }
    360 	if (sl_bytes > 250)
    361 	  {
    362 	    /*
    363 	     * the symbolic link won't fit into one SL System Use Field
    364 	     * print an error message and continue with splited one
    365 	     */
    366 	    fprintf(stderr,"symbolic link ``%s'' to long for one SL System Use Field, splitting", cpnt);
    367 	  }
    368        if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry();
    369      }
    370 
    371     while(nchar){
    372       if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
    373       Rock[ipnt++] ='S';
    374       Rock[ipnt++] ='L';
    375       lenpos = ipnt;
    376       Rock[ipnt++] = SL_SIZE;
    377       Rock[ipnt++] = SU_VERSION;
    378       Rock[ipnt++] = 0; /* Flags */
    379       lenval = 5;
    380       while(*cpnt){
    381 	cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
    382 	if(cpnt1) {
    383 	  nchar--;
    384 	  *cpnt1 = 0;
    385 	};
    386 
    387 	/* We treat certain components in a special way.  */
    388 	if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
    389 	  if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
    390 	  Rock[ipnt++] = SL_PARENT;
    391 	  Rock[ipnt++] = 0;  /* length is zero */
    392 	  lenval += 2;
    393 	  nchar -= 2;
    394 	} else if(cpnt[0] == '.' && cpnt[1] == 0){
    395 	  if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
    396 	  Rock[ipnt++] = SL_CURRENT;
    397 	  Rock[ipnt++] = 0;  /* length is zero */
    398 	  lenval += 2;
    399 	  nchar -= 1;
    400 	} else if(cpnt[0] == 0){
    401 	  if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
    402 	  Rock[ipnt++] = SL_ROOT;
    403 	  Rock[ipnt++] = 0;  /* length is zero */
    404 	  lenval += 2;
    405 	} else {
    406 	  /* If we do not have enough room for a component, start
    407 	     a new continuations segment now */
    408          if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) :
    409                                  MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt)))
    410 	   {
    411 	     add_CE_entry();
    412 	     if(cpnt1)
    413 	       {
    414 		 *cpnt1 = '/';
    415 		 nchar++;
    416 		 cpnt1 = NULL; /* A kluge so that we can restart properly */
    417 	       }
    418 	     break;
    419 	   }
    420 	  j0 = strlen((char *) cpnt);
    421 	  while(j0) {
    422 	    j1 = j0;
    423 	    if(j1 > 0xf8) j1 = 0xf8;
    424 	    need_ce = 0;
    425 	    if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
    426 	      j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
    427 	      need_ce++;
    428 	    }
    429 	    Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
    430 	    Rock[ipnt++] = j1;
    431 	    strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
    432 	    ipnt += j1;
    433 	    lenval += j1 + 2;
    434 	    cpnt += j1;
    435 	    nchar -= j1;  /* Number we processed this time */
    436 	    j0 -= j1;
    437 	    if(need_ce) {
    438 	      add_CE_entry();
    439 	      if(cpnt1) {
    440 		*cpnt1 = '/';
    441                 nchar++;
    442 		cpnt1 = NULL; /* A kluge so that we can restart properly */
    443 	      }
    444 	      break;
    445 	    }
    446 	  }
    447 	};
    448 	if(cpnt1) {
    449 	  cpnt = cpnt1 + 1;
    450 	} else
    451 	  break;
    452       }
    453       Rock[lenpos] = lenval;
    454       if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
    455     } /* while nchar */
    456   } /* Is a symbolic link */
    457   /*
    458    * Add in the Rock Ridge TF time field
    459    */
    460   if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
    461   Rock[ipnt++] ='T';
    462   Rock[ipnt++] ='F';
    463   Rock[ipnt++] = TF_SIZE;
    464   Rock[ipnt++] = SU_VERSION;
    465 #ifdef __QNX__
    466   Rock[ipnt++] = 0x0f;
    467 #else
    468   Rock[ipnt++] = 0x0e;
    469 #endif
    470   flagval |= (1<<7);
    471 #ifdef __QNX__
    472   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
    473   ipnt += 7;
    474 #endif
    475   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
    476   ipnt += 7;
    477   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
    478   ipnt += 7;
    479   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
    480   ipnt += 7;
    481 
    482   /*
    483    * Add in the Rock Ridge RE time field
    484    */
    485   if(deep_opt & NEED_RE){
    486           if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
    487 	  Rock[ipnt++] ='R';
    488 	  Rock[ipnt++] ='E';
    489 	  Rock[ipnt++] = RE_SIZE;
    490 	  Rock[ipnt++] = SU_VERSION;
    491 	  flagval |= (1<<6);
    492   };
    493   /*
    494    * Add in the Rock Ridge PL record, if required.
    495    */
    496   if(deep_opt & NEED_PL){
    497           if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
    498 	  Rock[ipnt++] ='P';
    499 	  Rock[ipnt++] ='L';
    500 	  Rock[ipnt++] = PL_SIZE;
    501 	  Rock[ipnt++] = SU_VERSION;
    502 	  set_733((char*)Rock + ipnt, 0);
    503 	  ipnt += 8;
    504 	  flagval |= (1<<5);
    505   };
    506 
    507   /*
    508    * Add in the Rock Ridge CL field, if required.
    509    */
    510   if(deep_opt & NEED_CL){
    511           if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
    512 	  Rock[ipnt++] ='C';
    513 	  Rock[ipnt++] ='L';
    514 	  Rock[ipnt++] = CL_SIZE;
    515 	  Rock[ipnt++] = SU_VERSION;
    516 	  set_733((char*)Rock + ipnt, 0);
    517 	  ipnt += 8;
    518 	  flagval |= (1<<4);
    519   };
    520 
    521 #ifndef VMS
    522   /* If transparent compression was requested, fill in the correct
    523      field for this file */
    524   if(transparent_compression &&
    525      S_ISREG(lstatbuf->st_mode) &&
    526      strlen(name) > 3 &&
    527      strcmp(name + strlen(name) - 3,".gZ") == 0){
    528     FILE * zipfile;
    529     char * checkname;
    530     unsigned int file_size;
    531     unsigned char header[8];
    532     int OK_flag;
    533 
    534     /* First open file and verify that the correct algorithm was used */
    535     file_size = 0;
    536     OK_flag = 1;
    537 
    538     zipfile = fopen(whole_name, "rb");
    539     fread(header, 1, sizeof(header), zipfile);
    540 
    541     /* Check some magic numbers from gzip. */
    542     if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
    543     /* Make sure file was blocksized. */
    544     if(((header[3] & 0x40) == 0)) OK_flag = 0;
    545     /* OK, now go to the end of the file and get some more info */
    546     if(OK_flag){
    547       int status;
    548       status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
    549       if(status == -1) OK_flag = 0;
    550     }
    551     if(OK_flag){
    552       if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
    553 	OK_flag = 0;
    554       else {
    555 	int blocksize;
    556 	blocksize = (header[3] << 8) | header[2];
    557 	file_size = ((unsigned int)header[7] << 24) |
    558 		    ((unsigned int)header[6] << 16) |
    559 		    ((unsigned int)header[5] << 8)  | header[4];
    560 #if 0
    561 	fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size);
    562 #endif
    563 	if(blocksize != SECTOR_SIZE) OK_flag = 0;
    564       }
    565     }
    566     fclose(zipfile);
    567 
    568     checkname = strdup(whole_name);
    569     checkname[strlen(whole_name)-3] = 0;
    570     zipfile = fopen(checkname, "rb");
    571     if(zipfile) {
    572       OK_flag = 0;
    573       fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n");
    574       fclose(zipfile);
    575     }
    576 
    577     free(checkname);
    578 
    579     if(OK_flag){
    580       if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
    581       Rock[ipnt++] ='Z';
    582       Rock[ipnt++] ='Z';
    583       Rock[ipnt++] = ZZ_SIZE;
    584       Rock[ipnt++] = SU_VERSION;
    585       Rock[ipnt++] = 'g'; /* Identify compression technique used */
    586       Rock[ipnt++] = 'z';
    587       Rock[ipnt++] = 3;
    588       set_733((char*)Rock + ipnt, file_size); /* Real file size */
    589       ipnt += 8;
    590     };
    591   }
    592 #endif
    593   /*
    594    * Add in the Rock Ridge CE field, if required.  We use  this for the
    595    * extension record that is stored in the root directory.
    596    */
    597   if(deep_opt & NEED_CE) add_CE_entry();
    598   /*
    599    * Done filling in all of the fields.  Now copy it back to a buffer for the
    600    * file in question.
    601    */
    602 
    603   /* Now copy this back to the buffer for the file */
    604   Rock[flagpos] = flagval;
    605 
    606   /* If there was a CE, fill in the size field */
    607   if(recstart)
    608     set_733((char*)Rock + recstart - 8, ipnt - recstart);
    609 
    610   s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
    611   s_entry->total_rr_attr_size = ipnt;
    612   s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
    613   memcpy(s_entry->rr_attributes, Rock, ipnt);
    614   return ipnt;
    615 }
    616 
    617 /* Guaranteed to  return a single sector with the relevant info */
    618 
    619 char * FDECL4(generate_rr_extension_record, char *, id,  char  *, descriptor,
    620 				    char *, source, int  *, size){
    621   int lipnt = 0;
    622   char * pnt;
    623   int len_id, len_des, len_src;
    624 
    625   len_id = strlen(id);
    626   len_des =  strlen(descriptor);
    627   len_src = strlen(source);
    628   Rock[lipnt++] ='E';
    629   Rock[lipnt++] ='R';
    630   Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
    631   Rock[lipnt++] = 1;
    632   Rock[lipnt++] = len_id;
    633   Rock[lipnt++] = len_des;
    634   Rock[lipnt++] = len_src;
    635   Rock[lipnt++] = 1;
    636 
    637   memcpy(Rock  + lipnt, id, len_id);
    638   lipnt += len_id;
    639 
    640   memcpy(Rock  + lipnt, descriptor, len_des);
    641   lipnt += len_des;
    642 
    643   memcpy(Rock  + lipnt, source, len_src);
    644   lipnt += len_src;
    645 
    646   if(lipnt  > SECTOR_SIZE) {
    647 	  fprintf(stderr,"Extension record too  long\n");
    648 	  exit(1);
    649   };
    650   pnt = (char *) e_malloc(SECTOR_SIZE);
    651   memset(pnt, 0,  SECTOR_SIZE);
    652   memcpy(pnt, Rock, lipnt);
    653   *size = lipnt;
    654   return pnt;
    655 }
    656