Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * File multi.c - scan existing iso9660 image and merge into
      3  * iso9660 filesystem.  Used for multisession support.
      4  *
      5  * Written by Eric Youngdale (1996).
      6  *
      7  * This program is free software; you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License as published by
      9  * the Free Software Foundation; either version 2, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License
     18  * along with this program; if not, write to the Free Software
     19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     20  */
     21 
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <time.h>
     25 #include <errno.h>
     26 #include <sys/types.h>
     27 #include <sys/stat.h>
     28 
     29 #include "config.h"
     30 
     31 #ifndef VMS
     32 
     33 #ifdef HAVE_UNISTD_H
     34 #include <unistd.h>
     35 #endif
     36 
     37 #else
     38 #include <sys/file.h>
     39 #include <vms/fabdef.h>
     40 #include "vms.h"
     41 extern char * strdup(const char *);
     42 #endif
     43 
     44 #include "mkisofs.h"
     45 #include "iso9660.h"
     46 
     47 #define TF_CREATE 1
     48 #define TF_MODIFY 2
     49 #define TF_ACCESS 4
     50 #define TF_ATTRIBUTES 8
     51 
     52 static int  isonum_711 __PR((unsigned char * p));
     53 static int  isonum_721 __PR((unsigned char * p));
     54 static int  isonum_723 __PR((unsigned char * p));
     55 static int  isonum_731 __PR((unsigned char * p));
     56 
     57 static int  DECL(merge_old_directory_into_tree, (struct directory_entry *,
     58 						 struct directory *));
     59 
     60 #ifdef	__STDC__
     61 static int
     62 isonum_711 (unsigned char * p)
     63 #else
     64 static int
     65 isonum_711 (p)
     66 	unsigned char * p;
     67 #endif
     68 {
     69 	return (*p & 0xff);
     70 }
     71 
     72 #ifdef	__STDC__
     73 static int
     74 isonum_721 (unsigned char * p)
     75 #else
     76 static int
     77 isonum_721 (p)
     78 	unsigned char * p;
     79 #endif
     80 {
     81 	return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
     82 }
     83 
     84 #ifdef	__STDC__
     85 static int
     86 isonum_723 (unsigned char * p)
     87 #else
     88 static int
     89 isonum_723 (p)
     90 	unsigned char * p;
     91 #endif
     92 {
     93 #if 0
     94 	if (p[0] != p[3] || p[1] != p[2]) {
     95 		fprintf (stderr, "invalid format 7.2.3 number\n");
     96 		exit (1);
     97 	}
     98 #endif
     99 	return (isonum_721 (p));
    100 }
    101 
    102 #ifdef	__STDC__
    103 static int
    104 isonum_731 (unsigned char * p)
    105 #else
    106 static int
    107 isonum_731 (p)
    108 	unsigned char * p;
    109 #endif
    110 {
    111 	return ((p[0] & 0xff)
    112 		| ((p[1] & 0xff) << 8)
    113 		| ((p[2] & 0xff) << 16)
    114 		| ((p[3] & 0xff) << 24));
    115 }
    116 
    117 #ifdef	__STDC__
    118 int
    119 isonum_733 (unsigned char * p)
    120 #else
    121 int
    122 isonum_733 (p)
    123 	unsigned char * p;
    124 #endif
    125 {
    126 	return (isonum_731 (p));
    127 }
    128 
    129 FILE * in_image = NULL;
    130 
    131 #ifndef	USE_SCG
    132 /*
    133  * Don't define readsecs if mkisofs is linked with
    134  * the SCSI library.
    135  * readsecs() will be implemented as SCSI command in this case.
    136  *
    137  * Use global var in_image directly in readsecs()
    138  * the SCSI equivalent will not use a FILE* for I/O.
    139  *
    140  * The main point of this pointless abstraction is that Solaris won't let
    141  * you read 2K sectors from the cdrom driver.  The fact that 99.9% of the
    142  * discs out there have a 2K sectorsize doesn't seem to matter that much.
    143  * Anyways, this allows the use of a scsi-generics type of interface on
    144  * Solaris.
    145  */
    146 #ifdef	__STDC__
    147 static int
    148 readsecs(int startsecno, void *buffer, int sectorcount)
    149 #else
    150 static int
    151 readsecs(startsecno, buffer, sectorcount)
    152 	int	startsecno;
    153 	void	*buffer;
    154 	int	sectorcount;
    155 #endif
    156 {
    157 	int	f = fileno(in_image);
    158 
    159 	if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) {
    160 		fprintf(stderr," Seek error on old image\n");
    161 		exit(10);
    162 	}
    163 	return (read(f, buffer, sectorcount * SECTOR_SIZE));
    164 }
    165 #endif
    166 
    167 /*
    168  * Parse the RR attributes so we can find the file name.
    169  */
    170 static int
    171 FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)
    172 {
    173 	int cont_extent, cont_offset, cont_size;
    174 	char name_buf[256];
    175 
    176 	cont_extent = cont_offset = cont_size = 0;
    177 
    178 	while(len >= 4){
    179 		if(pnt[3] != 1) {
    180 		  fprintf(stderr,"**BAD RRVERSION");
    181 		  return -1;
    182 		};
    183 		if(strncmp((char *) pnt, "NM", 2) == 0) {
    184 		  strncpy(name_buf, (char *) pnt+5, pnt[2] - 5);
    185 		  name_buf[pnt[2] - 5] = 0;
    186 		  dpnt->name = strdup(name_buf);
    187 		  dpnt->got_rr_name = 1;
    188 		  return 0;
    189 		}
    190 
    191 		if(strncmp((char *) pnt, "CE", 2) == 0) {
    192 			cont_extent = isonum_733(pnt+4);
    193 			cont_offset = isonum_733(pnt+12);
    194 			cont_size = isonum_733(pnt+20);
    195 		};
    196 
    197 		len -= pnt[2];
    198 		pnt += pnt[2];
    199 		if(len <= 3 && cont_extent) {
    200 		  unsigned char sector[SECTOR_SIZE];
    201 		  readsecs(cont_extent, sector, 1);
    202 		  parse_rr(&sector[cont_offset], cont_size, dpnt);
    203 		};
    204 	};
    205 
    206 	/* Fall back to the iso name if no RR name found */
    207 	if (dpnt->name == NULL) {
    208 	  char *cp;
    209 
    210 	  strcpy(name_buf, dpnt->isorec.name);
    211 	  cp = strchr(name_buf, ';');
    212 	  if (cp != NULL) {
    213 	    *cp = '\0';
    214 	  }
    215 
    216 	  dpnt->name = strdup(name_buf);
    217 	}
    218 
    219 	return 0;
    220 } /* parse_rr */
    221 
    222 
    223 static int
    224 FDECL4(check_rr_dates, struct directory_entry *, dpnt,
    225        struct directory_entry *, current,
    226        struct stat *, statbuf,
    227        struct stat *,lstatbuf)
    228 {
    229 	int cont_extent, cont_offset, cont_size;
    230 	int offset;
    231 	unsigned char * pnt;
    232 	int len;
    233 	int same_file;
    234 	int same_file_type;
    235 	mode_t mode;
    236 	char time_buf[7];
    237 
    238 
    239 	cont_extent = cont_offset = cont_size = 0;
    240 	same_file = 1;
    241 	same_file_type = 1;
    242 
    243 	pnt = dpnt->rr_attributes;
    244 	len = dpnt->rr_attr_size;
    245 	/*
    246 	 * We basically need to parse the rr attributes again, and
    247 	 * dig out the dates and file types.
    248 	 */
    249 	while(len >= 4){
    250 		if(pnt[3] != 1) {
    251 		  fprintf(stderr,"**BAD RRVERSION");
    252 		  return -1;
    253 		};
    254 
    255 		/*
    256 		 * If we have POSIX file modes, make sure that the file type
    257 		 * is the same.  If it isn't, then we must always
    258 		 * write the new file.
    259 		 */
    260 		if(strncmp((char *) pnt, "PX", 2) == 0) {
    261 		  mode = isonum_733(pnt + 4);
    262 		  if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) )
    263 		    {
    264 		      same_file_type = 0;
    265 		      same_file = 0;
    266 		    }
    267 		}
    268 
    269 		if(strncmp((char *) pnt, "TF", 2) == 0) {
    270 		  offset = 5;
    271 		  if( pnt[4] & TF_CREATE )
    272 		    {
    273 		      iso9660_date((char *) time_buf, lstatbuf->st_ctime);
    274 		      if(memcmp(time_buf, pnt+offset, 7) == 0)
    275 			same_file = 0;
    276 		      offset += 7;
    277 		    }
    278 		  if( pnt[4] & TF_MODIFY )
    279 		    {
    280 		      iso9660_date((char *) time_buf, lstatbuf->st_mtime);
    281 		      if(memcmp(time_buf, pnt+offset, 7) == 0)
    282 			same_file = 0;
    283 		      offset += 7;
    284 		    }
    285 		}
    286 
    287 		if(strncmp((char *) pnt, "CE", 2) == 0) {
    288 			cont_extent = isonum_733(pnt+4);
    289 			cont_offset = isonum_733(pnt+12);
    290 			cont_size = isonum_733(pnt+20);
    291 		};
    292 
    293 		len -= pnt[2];
    294 		pnt += pnt[2];
    295 		if(len <= 3 && cont_extent) {
    296 		  unsigned char sector[SECTOR_SIZE];
    297 
    298 		  readsecs(cont_extent, sector, 1);
    299 		  parse_rr(&sector[cont_offset], cont_size, dpnt);
    300 		};
    301 	};
    302 
    303 	/*
    304 	 * If we have the same fundamental file type, then it is clearly
    305 	 * safe to reuse the TRANS.TBL entry.
    306 	 */
    307 	if( same_file_type )
    308 	  {
    309 	    current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
    310 	  }
    311 
    312 	return same_file;
    313 }
    314 
    315 struct directory_entry **
    316 FDECL2(read_merging_directory, struct iso_directory_record *, mrootp,
    317        int *, nent)
    318 {
    319   unsigned char			* cpnt;
    320   unsigned char			* cpnt1;
    321   char				* dirbuff;
    322   int				  i;
    323   struct iso_directory_record	* idr;
    324   int				  len;
    325   struct directory_entry	**pnt;
    326   int				  rlen;
    327   struct directory_entry	**rtn;
    328   int				  seen_rockridge;
    329   unsigned char			* tt_buf;
    330   int				  tt_extent;
    331   int				  tt_size;
    332 
    333   static int warning_given = 0;
    334 
    335   /*
    336    * First, allocate a buffer large enough to read in the entire
    337    * directory.
    338    */
    339   dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size));
    340 
    341   readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff,
    342 	   isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE);
    343 
    344   /*
    345    * Next look over the directory, and count up how many entries we
    346    * have.
    347    */
    348   len = isonum_733((unsigned char *)mrootp->size);
    349   i = 0;
    350   *nent = 0;
    351   while(i < len )
    352     {
    353       idr = (struct iso_directory_record *) &dirbuff[i];
    354       if(idr->length[0] == 0)
    355 	{
    356 	  i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
    357 	  continue;
    358 	}
    359       (*nent)++;
    360       i += idr->length[0];
    361     }
    362 
    363   /*
    364    * Now allocate the buffer which will hold the array we are
    365    * about to return.
    366    */
    367   rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn));
    368 
    369   /*
    370    * Finally, scan the directory one last time, and pick out the
    371    * relevant bits of information, and store it in the relevant
    372    * bits of the structure.
    373    */
    374   i = 0;
    375   pnt = rtn;
    376   tt_extent = 0;
    377   seen_rockridge = 0;
    378   tt_size = 0;
    379   while(i < len )
    380     {
    381       idr = (struct iso_directory_record *) &dirbuff[i];
    382       if(idr->length[0] == 0)
    383 	{
    384 	  i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
    385 	  continue;
    386 	}
    387       *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn));
    388       (*pnt)->next = NULL;
    389       (*pnt)->isorec = *idr;
    390       (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent);
    391       (*pnt)->size = isonum_733((unsigned char *)idr->size);
    392       (*pnt)->priority = 0;
    393       (*pnt)->name = NULL;
    394       (*pnt)->got_rr_name = 0;
    395       (*pnt)->table = NULL;
    396       (*pnt)->whole_name = NULL;
    397       (*pnt)->filedir = NULL;
    398       (*pnt)->parent_rec = NULL;
    399       /*
    400        * Set this information so that we correctly cache previous
    401        * session bits of information.
    402        */
    403       (*pnt)->inode = (*pnt)->starting_block;
    404       (*pnt)->dev = PREV_SESS_DEV;
    405       (*pnt)->rr_attributes = NULL;
    406       (*pnt)->rr_attr_size = 0;
    407       (*pnt)->total_rr_attr_size = 0;
    408       (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY;
    409 
    410       /*
    411        * Check for and parse any RR attributes for the file.
    412        * All we are really looking for here is the original name
    413        * of the file.
    414        */
    415       rlen = idr->length[0] & 0xff;
    416       cpnt = (unsigned char *) idr;
    417 
    418       rlen -= sizeof(struct iso_directory_record);
    419       cpnt += sizeof(struct iso_directory_record);
    420 
    421       rlen += sizeof(idr->name);
    422       cpnt -= sizeof(idr->name);
    423 
    424       rlen -= idr->name_len[0];
    425       cpnt += idr->name_len[0];
    426 
    427       if((idr->name_len[0] & 1) == 0){
    428 	cpnt++;
    429 	rlen--;
    430       };
    431 
    432       if( rlen != 0 )
    433 	{
    434 	  (*pnt)->total_rr_attr_size =  (*pnt)->rr_attr_size = rlen;
    435 	  (*pnt)->rr_attributes = e_malloc(rlen);
    436 	  memcpy((*pnt)->rr_attributes,  cpnt, rlen);
    437 	  seen_rockridge = 1;
    438 	}
    439 
    440       /*
    441        * Now zero out the remainder of the name field.
    442        */
    443       cpnt = (unsigned char *) &(*pnt)->isorec.name;
    444       cpnt += idr->name_len[0];
    445       memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]);
    446 
    447       parse_rr((*pnt)->rr_attributes, rlen, *pnt);
    448 
    449       if(    ((*pnt)->isorec.name_len[0] == 1)
    450 	  && (    ((*pnt)->isorec.name[0] == 0)
    451 	       || ((*pnt)->isorec.name[0] == 1)) )
    452 	{
    453 	  if( (*pnt)->name != NULL )
    454 	    {
    455 	      free((*pnt)->name);
    456 	    }
    457 	  if( (*pnt)->whole_name != NULL )
    458 	    {
    459 	      free((*pnt)->whole_name);
    460 	    }
    461 	  if( (*pnt)->isorec.name[0] == 0 )
    462 	    {
    463 	      (*pnt)->name = strdup(".");
    464 	    }
    465 	  else
    466 	    {
    467 	      (*pnt)->name = strdup("..");
    468 	    }
    469 	}
    470 
    471 #ifdef DEBUG
    472       fprintf(stderr, "got DE name: %s\n", (*pnt)->name);
    473 #endif
    474 
    475 #ifdef APPLE_HYB
    476       if( strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0)
    477 #else
    478       if( strncmp(idr->name, "TRANS.TBL", 9) == 0)
    479 #endif /* APPLE_HYB */
    480 	{
    481 	  if( (*pnt)->name != NULL )
    482 	    {
    483 	      free((*pnt)->name);
    484 	    }
    485 	  if( (*pnt)->whole_name != NULL )
    486 	    {
    487 	      free((*pnt)->whole_name);
    488 	    }
    489 	  (*pnt)->name = strdup("<translation table>");
    490 	  tt_extent = isonum_733((unsigned char *)idr->extent);
    491 	  tt_size = isonum_733((unsigned char *)idr->size);
    492 	}
    493 
    494       pnt++;
    495       i += idr->length[0];
    496     }
    497 
    498   /*
    499    * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
    500    * to get the filenames of the files.  Also, save the table info, just
    501    * in case we need to use it.
    502    */
    503   if( tt_extent != 0 && tt_size != 0 )
    504     {
    505       tt_buf = (unsigned char *) e_malloc(tt_size);
    506       readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE);
    507 
    508       /*
    509        * Loop through the file, examine each entry, and attempt to
    510        * attach it to the correct entry.
    511        */
    512       cpnt = tt_buf;
    513       cpnt1 = tt_buf;
    514       while( cpnt - tt_buf < tt_size )
    515 	{
    516 	  while(*cpnt1 != '\n' && *cpnt1 != '\0')  cpnt1++;
    517 	  *cpnt1 = '\0';
    518 
    519 	  for(pnt = rtn, i = 0; i <*nent; i++, pnt++)
    520 	    {
    521 	      rlen = isonum_711((*pnt)->isorec.name_len);
    522 	      if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name,
    523 			  rlen) == 0
    524 		  && cpnt[2+rlen] == ' ')
    525 		{
    526 		  (*pnt)->table = e_malloc(strlen((char*)cpnt) - 33);
    527 		  sprintf((*pnt)->table, "%c\t%s\n",
    528 			  *cpnt, cpnt+37);
    529 		  if( !(*pnt)->got_rr_name )
    530 		    {
    531 		      if ((*pnt)->name != NULL) {
    532 			free((*pnt)->name);
    533 		      }
    534 		      (*pnt)->name = strdup((char *) cpnt+37);
    535 		    }
    536 		  break;
    537 		}
    538 	    }
    539 	  cpnt = cpnt1 + 1;
    540 	  cpnt1 = cpnt;
    541 	}
    542 
    543       free(tt_buf);
    544     }
    545   else if( !seen_rockridge && !warning_given )
    546     {
    547       /*
    548        * Warn the user that iso (8.3) names were used because neither
    549        * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were found.
    550        */
    551       fprintf(stderr,"Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n");
    552       fprintf(stderr,"name translations were found on previous session.\n");
    553       fprintf(stderr,"ISO (8.3) file names have been used instead.\n");
    554       warning_given = 1;
    555     }
    556 
    557   if( dirbuff != NULL )
    558     {
    559       free(dirbuff);
    560     }
    561 
    562   return rtn;
    563 } /* read_merging_directory */
    564 
    565 /*
    566  * Free any associated data related to the structures.
    567  */
    568 int
    569 FDECL2(free_mdinfo, struct directory_entry **  , ptr, int, len )
    570 {
    571   int		i;
    572   struct directory_entry **p;
    573 
    574   p = ptr;
    575   for(i=0; i<len; i++, p++)
    576     {
    577       /*
    578        * If the tree-handling code decided that it needed an entry,
    579        * it will have removed it from the list.  Thus we must allow
    580        * for null pointers here.
    581        */
    582       if( *p == NULL )
    583 	{
    584 	  continue;
    585 	}
    586 
    587       if( (*p)->name != NULL )
    588 	{
    589 	  free((*p)->name);
    590 	}
    591 
    592       if( (*p)->whole_name != NULL )
    593 	{
    594 	  free((*p)->whole_name);
    595 	}
    596 
    597       if( (*p)->rr_attributes != NULL )
    598 	{
    599 	  free((*p)->rr_attributes);
    600 	}
    601 
    602       if( (*p)->table != NULL )
    603 	{
    604 	  free((*p)->table);
    605 	}
    606 
    607       free(*p);
    608 
    609     }
    610 
    611   free(ptr);
    612   return 0;
    613 }
    614 
    615 /*
    616  * Search the list to see if we have any entries from the previous
    617  * session that match this entry.  If so, copy the extent number
    618  * over so we don't bother to write it out to the new session.
    619  */
    620 
    621 int
    622 FDECL6(check_prev_session, struct directory_entry **  , ptr, int, len,
    623        struct directory_entry *, curr_entry,
    624        struct stat *, statbuf, struct stat *, lstatbuf,
    625        struct directory_entry **, odpnt)
    626 {
    627   int		i;
    628 
    629   for( i=0; i < len; i++ )
    630     {
    631       if( ptr[i] == NULL )
    632 	{
    633 	  continue;
    634 	}
    635 
    636 #if 0
    637       if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
    638 	  && ptr[i]->name[0] == '\0' )
    639 	{
    640 	  continue;
    641 	}
    642       if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
    643 	  && ptr[i]->name[0] == 1)
    644 	{
    645 	  continue;
    646 	}
    647 #else
    648       if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 )
    649 	{
    650 	  continue;
    651 	}
    652       if( ptr[i]->name != NULL  && strcmp(ptr[i]->name, "..") == 0 )
    653 	{
    654 	  continue;
    655 	}
    656 #endif
    657 
    658       if(    ptr[i]->name != NULL
    659 	  && strcmp(ptr[i]->name, curr_entry->name) != 0 )
    660 	{
    661 	  continue;
    662 	}
    663 
    664       /*
    665        * We know that the files have the same name.  If they also have
    666        * the same file type (i.e. file, dir, block, etc), then we
    667        * can safely reuse the TRANS.TBL entry for this file.
    668        * The check_rr_dates function will do this for us.
    669        *
    670        * Verify that the file type and dates are consistent.
    671        * If not, we probably have a different file, and we need
    672        * to write it out again.
    673        */
    674       if(    (ptr[i]->rr_attributes != NULL)
    675 	  && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) )
    676 	{
    677 	  goto found_it;
    678 	}
    679 
    680 
    681       /*
    682        * Verify size and timestamp.  If rock ridge is in use, we need
    683        * to compare dates from RR too.  Directories are special, we
    684        * calculate their size later.
    685        */
    686       if(     (curr_entry->isorec.flags[0] & 2) == 0
    687 	  &&  ptr[i]->size != curr_entry->size )
    688 	{
    689 	  goto found_it;
    690 	}
    691 
    692       if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 )
    693 	{
    694 	  goto found_it;
    695 	}
    696 
    697       /*
    698        * Never ever reuse directory extents.  See comments in
    699        * tree.c for an explaination of why this must be the case.
    700        */
    701       if( (curr_entry->isorec.flags[0] & 2) != 0 )
    702 	{
    703 	  goto found_it;
    704 	}
    705 
    706       memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
    707       curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
    708       goto found_it;
    709     }
    710   return 0;
    711 
    712 found_it:
    713   if( odpnt != NULL )
    714     {
    715       *odpnt = ptr[i];
    716     }
    717   else
    718     {
    719       free(ptr[i]);
    720     }
    721   ptr[i] = NULL;
    722   return 0;
    723 }
    724 
    725 /*
    726  * merge_isofs:  Scan an existing image, and return a pointer
    727  * to the root directory for this image.
    728  */
    729 struct iso_directory_record * FDECL1(merge_isofs, char *, path)
    730 {
    731   char				  buffer[SECTOR_SIZE];
    732   int				  file_addr;
    733   int				  i;
    734   struct iso_primary_descriptor * pri = NULL;
    735   struct iso_directory_record   * rootp;
    736   struct iso_volume_descriptor  * vdp;
    737 
    738   /*
    739    * Start by opening up the image and searching for the volume header.
    740    * Ultimately, we need to search for volume headers in multiple places
    741    * because we might be starting with a multisession image.
    742    * FIXME(eric).
    743    */
    744 
    745 #ifndef	USE_SCG
    746   in_image = fopen(path, "rb");
    747   if( in_image == NULL )
    748     {
    749       return NULL;
    750     }
    751 #else
    752   if (strchr(path, '/')) {
    753 	in_image = fopen(path, "rb");
    754 	if( in_image == NULL ) {
    755 		return NULL;
    756 	}
    757   } else {
    758 	if (scsidev_open(path) < 0)
    759 		return NULL;
    760   }
    761 #endif
    762 
    763   get_session_start(&file_addr);
    764 
    765   for(i = 0; i< 100; i++)
    766     {
    767       if (readsecs(file_addr/SECTOR_SIZE, &buffer,
    768 		   sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer))
    769 	{
    770 	  fprintf(stderr," Read error on old image %s\n", path);
    771 	  exit(10);
    772 	}
    773 
    774       vdp = (struct iso_volume_descriptor *)buffer;
    775 
    776       if(    (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0)
    777 	  && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) )
    778 	{
    779 	  break;
    780 	}
    781       file_addr += SECTOR_SIZE;
    782     }
    783 
    784   if( i == 100 )
    785     {
    786       return NULL;
    787     }
    788 
    789   pri = (struct iso_primary_descriptor *)vdp;
    790 
    791   /*
    792    * Check the blocksize of the image to make sure it is compatible.
    793    */
    794   if(    (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE)
    795       || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) )
    796     {
    797       return NULL;
    798     }
    799 
    800   /*
    801    * Get the location and size of the root directory.
    802    */
    803   rootp = calloc(1, sizeof(struct iso_directory_record));
    804 
    805   memcpy(rootp, pri->root_directory_record, sizeof(pri->root_directory_record));
    806 
    807   return rootp;
    808 }
    809 
    810 void FDECL3(merge_remaining_entries, struct directory *, this_dir,
    811 	    struct directory_entry **, pnt,
    812 	    int, n_orig)
    813 {
    814   int i;
    815   struct directory_entry * s_entry;
    816   unsigned int ttbl_extent = 0;
    817   unsigned int ttbl_index  = 0;
    818   char whole_path[1024];
    819 
    820   /*
    821    * Whatever is leftover in the list needs to get merged back
    822    * into the directory.
    823    */
    824   for( i=0; i < n_orig; i++ )
    825     {
    826       if( pnt[i] == NULL )
    827 	{
    828 	  continue;
    829 	}
    830 
    831       if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL)
    832        {
    833          /*
    834           * Set the name for this directory.
    835           */
    836          strcpy(whole_path, this_dir->de_name);
    837          strcat(whole_path, SPATH_SEPARATOR);
    838          strcat(whole_path, pnt[i]->name);
    839 
    840          pnt[i]->whole_name = strdup(whole_path);
    841        }
    842 
    843       if( pnt[i]->name != NULL
    844 	  && strcmp(pnt[i]->name, "<translation table>") == 0 )
    845 	{
    846 	  ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent);
    847 	  ttbl_index = i;
    848 	  continue;
    849 	}
    850       /*
    851        * Skip directories for now - these need to be treated
    852        * differently.
    853        */
    854       if( (pnt[i]->isorec.flags[0] & 2) != 0 )
    855 	{
    856 	  /*
    857 	   * FIXME - we need to insert this directory into the
    858 	   * tree, so that the path tables we generate will
    859 	   * be correct.
    860 	   */
    861 	  if(    (strcmp(pnt[i]->name, ".") == 0)
    862 	      || (strcmp(pnt[i]->name, "..") == 0) )
    863 	    {
    864 	      free(pnt[i]);
    865 	      pnt[i] = NULL;
    866 	      continue;
    867 	    }
    868 	  else
    869 	    {
    870 	      merge_old_directory_into_tree(pnt[i], this_dir);
    871 	    }
    872 	}
    873       pnt[i]->next = this_dir->contents;
    874       pnt[i]->filedir = this_dir;
    875       this_dir->contents = pnt[i];
    876       pnt[i] = NULL;
    877     }
    878 
    879 
    880   /*
    881    * If we don't have an entry for the translation table, then
    882    * don't bother trying to copy the starting extent over.
    883    * Note that it is possible that if we are copying the entire
    884    * directory, the entry for the translation table will have already
    885    * been inserted into the linked list and removed from the old
    886    * entries list, in which case we want to leave the extent number
    887    * as it was before.
    888    */
    889   if( ttbl_extent == 0 )
    890     {
    891       return;
    892     }
    893 
    894   /*
    895    * Finally, check the directory we are creating to see whether
    896    * there are any new entries in it.  If there are not, we can
    897    * reuse the same translation table.
    898    */
    899   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
    900     {
    901       /*
    902        * Don't care about '.' or '..'.  They are never in the table
    903        * anyways.
    904        */
    905       if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 )
    906 	{
    907 	  continue;
    908 	}
    909       if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 )
    910 	{
    911 	  continue;
    912 	}
    913       if( strcmp(s_entry->name, "<translation table>") == 0)
    914 	{
    915 	  continue;
    916 	}
    917       if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 )
    918 	{
    919 	  return;
    920 	}
    921     }
    922 
    923   /*
    924    * Locate the translation table, and re-use the same extent.
    925    * It isn't clear that there should ever be one in there already
    926    * so for now we try and muddle through the best we can.
    927    */
    928   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
    929     {
    930       if( strcmp(s_entry->name, "<translation table>") == 0)
    931 	{
    932 	  fprintf(stderr,"Should never get here\n");
    933 	  set_733(s_entry->isorec.extent, ttbl_extent);
    934 	  return;
    935 	}
    936     }
    937 
    938   pnt[ttbl_index]->next = this_dir->contents;
    939   pnt[ttbl_index]->filedir = this_dir;
    940   this_dir->contents = pnt[ttbl_index];
    941   pnt[ttbl_index] = NULL;
    942 }
    943 
    944 
    945 /*
    946  * Here we have a case of a directory that has completely disappeared from
    947  * the face of the earth on the tree we are mastering from.  Go through and
    948  * merge it into the tree, as well as everything beneath it.
    949  *
    950  * Note that if a directory has been moved for some reason, this will
    951  * incorrectly pick it up and attempt to merge it back into the old
    952  * location.  FIXME(eric).
    953  */
    954 static int
    955 FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,
    956        struct directory *, parent)
    957 {
    958   struct directory_entry	**contents = NULL;
    959   int				  i;
    960   int				  n_orig;
    961   struct directory		* this_dir, *next_brother;
    962   char				  whole_path[1024];
    963 
    964   this_dir = (struct directory *) e_malloc(sizeof(struct directory));
    965   memset(this_dir, 0, sizeof(struct directory));
    966   this_dir->next = NULL;
    967   this_dir->subdir = NULL;
    968   this_dir->self = dpnt;
    969   this_dir->contents = NULL;
    970   this_dir->size = 0;
    971   this_dir->extent = 0;
    972   this_dir->depth = parent->depth + 1;
    973   this_dir->parent = parent;
    974   if(!parent->subdir)
    975     parent->subdir = this_dir;
    976   else {
    977     next_brother = parent->subdir;
    978     while(next_brother->next) next_brother = next_brother->next;
    979     next_brother->next = this_dir;
    980   }
    981 
    982   /*
    983    * Set the name for this directory.
    984    */
    985   strcpy(whole_path, parent->de_name);
    986   strcat(whole_path, SPATH_SEPARATOR);
    987   strcat(whole_path, dpnt->name);
    988   this_dir->de_name = strdup(whole_path);
    989   this_dir->whole_name = strdup(whole_path);
    990 
    991   /*
    992    * Now fill this directory using information from the previous
    993    * session.
    994    */
    995   contents = read_merging_directory(&dpnt->isorec, &n_orig);
    996   /*
    997    * Start by simply copying the '.', '..' and non-directory
    998    * entries to this directory.  Technically we could let
    999    * merge_remaining_entries handle this, but it gets rather confused
   1000    * by the '.' and '..' entries.
   1001    */
   1002   for(i=0; i < n_orig; i ++ )
   1003     {
   1004       /*
   1005        * We can always reuse the TRANS.TBL in this particular case.
   1006        */
   1007       contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
   1008 
   1009       if(    ((contents[i]->isorec.flags[0] & 2) != 0)
   1010 	  && (i >= 2) )
   1011 	{
   1012 	  continue;
   1013 	}
   1014 
   1015       /*
   1016        * If we have a directory, don't reuse the extent number.
   1017        */
   1018       if( (contents[i]->isorec.flags[0] & 2) != 0 )
   1019 	{
   1020 	  memset(contents[i]->isorec.extent, 0, 8);
   1021 
   1022 	  if( strcmp(contents[i]->name, ".") == 0 )
   1023 	      this_dir->dir_flags |= DIR_HAS_DOT;
   1024 
   1025 	  if( strcmp(contents[i]->name, "..") == 0 )
   1026 	      this_dir->dir_flags |= DIR_HAS_DOTDOT;
   1027 	}
   1028 
   1029       /*
   1030        * Set the whole name for this file.
   1031        */
   1032       strcpy(whole_path, this_dir->whole_name);
   1033       strcat(whole_path, SPATH_SEPARATOR);
   1034       strcat(whole_path, contents[i]->name);
   1035 
   1036       contents[i]->whole_name = strdup(whole_path);
   1037 
   1038       contents[i]->next = this_dir->contents;
   1039       contents[i]->filedir = this_dir;
   1040       this_dir->contents = contents[i];
   1041       contents[i] = NULL;
   1042     }
   1043 
   1044   /*
   1045    * Zero the extent number for ourselves.
   1046    */
   1047   memset(dpnt->isorec.extent, 0, 8);
   1048 
   1049   /*
   1050    * Anything that is left are other subdirectories that need to be merged.
   1051    */
   1052   merge_remaining_entries(this_dir, contents, n_orig);
   1053   free_mdinfo(contents, n_orig);
   1054 #if 0
   1055   /*
   1056    * This is no longer required.  The post-scan sort will handle
   1057    * all of this for us.
   1058    */
   1059   sort_n_finish(this_dir);
   1060 #endif
   1061 
   1062   return 0;
   1063 }
   1064 
   1065 
   1066 char * cdwrite_data = NULL;
   1067 
   1068 int
   1069 FDECL1(get_session_start, int *, file_addr)
   1070 {
   1071   char * pnt;
   1072 
   1073 #ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS
   1074   /*
   1075    * FIXME(eric).  We need to coordinate with cdwrite to obtain
   1076    * the parameters.  For now, we assume we are writing the 2nd session,
   1077    * so we start from the session that starts at 0.
   1078    */
   1079 
   1080   *file_addr = (16 << 11);
   1081 
   1082   /*
   1083    * We need to coordinate with cdwrite to get the next writable address
   1084    * from the device.  Here is where we use it.
   1085    */
   1086   session_start = last_extent = last_extent_written = cdwrite_result();
   1087 
   1088 #else
   1089 
   1090   if( cdwrite_data == NULL )
   1091     {
   1092       fprintf(stderr,"Special parameters for cdwrite not specified with -C\n");
   1093       exit(1);
   1094     }
   1095 
   1096   /*
   1097    * Next try and find the ',' in there which delimits the two numbers.
   1098    */
   1099   pnt = strchr(cdwrite_data, ',');
   1100   if( pnt == NULL )
   1101     {
   1102       fprintf(stderr, "Malformed cdwrite parameters\n");
   1103       exit(1);
   1104     }
   1105 
   1106   *pnt = '\0';
   1107   if (file_addr != NULL) {
   1108     *file_addr = atol(cdwrite_data) * SECTOR_SIZE;
   1109   }
   1110   pnt++;
   1111 
   1112   session_start = last_extent = last_extent_written = atol(pnt);
   1113 
   1114   pnt--;
   1115   *pnt = ',';
   1116 
   1117 #endif
   1118   return 0;
   1119 }
   1120 
   1121 /*
   1122  * This function scans the directory tree, looking for files, and it makes
   1123  * note of everything that is found.  We also begin to construct the ISO9660
   1124  * directory entries, so that we can determine how large each directory is.
   1125  */
   1126 
   1127 int
   1128 FDECL2(merge_previous_session,struct directory *, this_dir,
   1129        struct iso_directory_record *, mrootp)
   1130 {
   1131   struct directory_entry	**orig_contents = NULL;
   1132   struct directory_entry        * odpnt = NULL;
   1133   int				  n_orig;
   1134   struct directory_entry	* s_entry;
   1135   int				  status, lstatus;
   1136   struct stat			  statbuf, lstatbuf;
   1137 
   1138   /*
   1139    * Parse the same directory in the image that we are merging
   1140    * for multisession stuff.
   1141    */
   1142   orig_contents = read_merging_directory(mrootp, &n_orig);
   1143   if( orig_contents == NULL )
   1144     {
   1145       return 0;
   1146     }
   1147 
   1148 
   1149 /* Now we scan the directory itself, and look at what is inside of it. */
   1150 
   1151   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
   1152     {
   1153       status  =  stat_filter(s_entry->whole_name, &statbuf);
   1154       lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
   1155 
   1156       /*
   1157        * We always should create an entirely new directory tree whenever
   1158        * we generate a new session, unless there were *no* changes whatsoever
   1159        * to any of the directories, in which case it would be kind of pointless
   1160        * to generate a new session.
   1161        *
   1162        * I believe it is possible to rigorously prove that any change anywhere
   1163        * in the filesystem will force the entire tree to be regenerated
   1164        * because the modified directory will get a new extent number.  Since
   1165        * each subdirectory of the changed directory has a '..' entry, all of
   1166        * them will need to be rewritten too, and since the parent directory
   1167        * of the modified directory will have an extent pointer to the directory
   1168        * it too will need to be rewritten.  Thus we will never be able to reuse
   1169        * any directory information when writing new sessions.
   1170        *
   1171        * We still check the previous session so we can mark off the equivalent
   1172        * entry in the list we got from the original disc, however.
   1173        */
   1174 
   1175       /*
   1176        * The check_prev_session function looks for an identical entry in
   1177        * the previous session.  If we see it, then we copy the extent
   1178        * number to s_entry, and cross it off the list.
   1179        */
   1180       check_prev_session(orig_contents, n_orig, s_entry,
   1181 			 &statbuf, &lstatbuf, &odpnt);
   1182 
   1183       if(S_ISDIR(statbuf.st_mode) && odpnt != NULL)
   1184 	{
   1185 	  int dflag;
   1186 
   1187 	  if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
   1188 	    {
   1189 	      struct directory * child;
   1190 
   1191 	      child = find_or_create_directory(this_dir,
   1192 					       s_entry->whole_name,
   1193 					       s_entry, 1);
   1194 	      dflag = merge_previous_session(child,
   1195 					     &odpnt->isorec);
   1196 	      /* If unable to scan directory, mark this as a non-directory */
   1197 	      if(!dflag)
   1198 		lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
   1199 	      free(odpnt);
   1200 	      odpnt = NULL;
   1201 	    }
   1202 	}
   1203     }
   1204 
   1205   /*
   1206    * Whatever is left over, are things which are no longer in the tree
   1207    * on disk.  We need to also merge these into the tree.
   1208    */
   1209    merge_remaining_entries(this_dir, orig_contents, n_orig);
   1210    free_mdinfo(orig_contents, n_orig);
   1211 
   1212   return 1;
   1213 }
   1214 
   1215