xref: /openbsd/gnu/usr.sbin/mkhybrid/src/multi.c (revision 463a9bef)
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
isonum_711(unsigned char * p)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
isonum_721(unsigned char * p)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
isonum_723(unsigned char * p)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
isonum_731(unsigned char * p)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
isonum_733(unsigned char * p)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
readsecs(int startsecno,void * buffer,int sectorcount)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
FDECL3(parse_rr,unsigned char *,pnt,int,len,struct directory_entry *,dpnt)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
FDECL4(check_rr_dates,struct directory_entry *,dpnt,struct directory_entry *,current,struct stat *,statbuf,struct stat *,lstatbuf)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 **
FDECL2(read_merging_directory,struct iso_directory_record *,mrootp,int *,nent)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
FDECL2(free_mdinfo,struct directory_entry **,ptr,int,len)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
FDECL6(check_prev_session,struct directory_entry **,ptr,int,len,struct directory_entry *,curr_entry,struct stat *,statbuf,struct stat *,lstatbuf,struct directory_entry **,odpnt)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  */
FDECL1(merge_isofs,char *,path)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 
FDECL3(merge_remaining_entries,struct directory *,this_dir,struct directory_entry **,pnt,int,n_orig)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
FDECL2(merge_old_directory_into_tree,struct directory_entry *,dpnt,struct directory *,parent)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
FDECL1(get_session_start,int *,file_addr)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
FDECL2(merge_previous_session,struct directory *,this_dir,struct iso_directory_record *,mrootp)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