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