1 /* @(#)multi.c	1.104 16/01/06 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)multi.c	1.104 16/01/06 joerg";
6 #endif
7 /*
8  * File multi.c - scan existing iso9660 image and merge into
9  * iso9660 filesystem.  Used for multisession support.
10  *
11  * Written by Eric Youngdale (1996).
12  * Copyright (c) 1999-2016 J. Schilling
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  */
28 
29 #include "mkisofs.h"
30 #include "rock.h"
31 #include <schily/time.h>
32 #include <schily/errno.h>
33 #include <schily/utypes.h>
34 #include <schily/schily.h>
35 #include <schily/ctype.h>		/* Needed for printasc()	*/
36 
37 #ifdef VMS
38 
39 #include <sys/file.h>
40 #include <vms/fabdef.h>
41 #include "vms.h"
42 #endif
43 
44 #ifndef howmany
45 #define	howmany(x, y)   (((x)+((y)-1))/(y))
46 #endif
47 #ifndef roundup
48 #define	roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
49 #endif
50 
51 /*
52  * Cannot debug memset() with gdb on Linux, so use fillbytes()
53  */
54 /*#define	memset(s, c, n)	fillbytes(s, n, c)*/
55 
56 #define	TF_CREATE 1
57 #define	TF_MODIFY 2
58 #define	TF_ACCESS 4
59 #define	TF_ATTRIBUTES 8
60 
61 LOCAL	void	printasc	__PR((char *txt, unsigned char *p, int len));
62 LOCAL	void	prbytes		__PR((char *txt, unsigned char *p, int len));
63 unsigned char	*parse_xa	__PR((unsigned char *pnt, int *lenp,
64 					struct directory_entry *dpnt));
65 EXPORT	int	rr_flags	__PR((struct iso_directory_record *idr));
66 LOCAL	int	parse_rrflags	__PR((Uchar *pnt, int len, int cont_flag));
67 LOCAL	BOOL	find_rr		__PR((struct iso_directory_record *idr, Uchar **pntp, int *lenp));
68 LOCAL	 int	parse_rr	__PR((unsigned char *pnt, int len,
69 					struct directory_entry *dpnt));
70 LOCAL	int	check_rr_dates	__PR((struct directory_entry *dpnt,
71 					struct directory_entry *current,
72 					struct stat *statbuf,
73 					struct stat *lstatbuf));
74 LOCAL	BOOL 	valid_iso_directory __PR((struct iso_directory_record *idr,
75 					int idr_off,
76 					size_t space_left));
77 LOCAL	struct directory_entry **
78 		read_merging_directory __PR((struct iso_directory_record *, int *));
79 LOCAL	int	free_mdinfo	__PR((struct directory_entry **, int len));
80 LOCAL	void	free_directory_entry __PR((struct directory_entry *dirp));
81 LOCAL	int	iso_dir_ents	__PR((struct directory_entry *de));
82 LOCAL	void	copy_mult_extent __PR((struct directory_entry *se1,
83 					struct directory_entry *se2));
84 LOCAL	void	merge_remaining_entries __PR((struct directory *,
85 					struct directory_entry **, int));
86 
87 LOCAL	int	merge_old_directory_into_tree __PR((struct directory_entry *,
88 							struct directory *));
89 LOCAL	void	check_rr_relocation __PR((struct directory_entry *de));
90 
91 FILE	*in_image = NULL;
92 BOOL	ignerr = FALSE;
93 int	su_version = -1;
94 int	rr_version = -1;
95 int	aa_version = -1;
96 char	er_id[256];
97 
98 #ifndef	USE_SCG
99 /*
100  * Don't define readsecs if mkisofs is linked with
101  * the SCSI library.
102  * readsecs() will be implemented as SCSI command in this case.
103  *
104  * Use global var in_image directly in readsecs()
105  * the SCSI equivalent will not use a FILE* for I/O.
106  *
107  * The main point of this pointless abstraction is that Solaris won't let
108  * you read 2K sectors from the cdrom driver.  The fact that 99.9% of the
109  * discs out there have a 2K sectorsize doesn't seem to matter that much.
110  * Anyways, this allows the use of a scsi-generics type of interface on
111  * Solaris.
112  */
113 #ifdef	PROTOTYPES
114 EXPORT int
readsecs(UInt32_t startsecno,void * buffer,int sectorcount)115 readsecs(UInt32_t startsecno, void *buffer, int sectorcount)
116 #else
117 EXPORT int
118 readsecs(startsecno, buffer, sectorcount)
119 	UInt32_t	startsecno;
120 	void		*buffer;
121 	int		sectorcount;
122 #endif
123 {
124 	int		f = fileno(in_image);
125 
126 	if (lseek(f, (off_t)startsecno * SECTOR_SIZE, SEEK_SET) == (off_t)-1) {
127 		comerr(_("Seek error on old image\n"));
128 	}
129 	if (read(f, buffer, (sectorcount * SECTOR_SIZE))
130 		!= (sectorcount * SECTOR_SIZE)) {
131 		comerr(_("Read error on old image\n"));
132 	}
133 	return (sectorcount * SECTOR_SIZE);
134 }
135 
136 #endif
137 
138 LOCAL void
printasc(txt,p,len)139 printasc(txt, p, len)
140 	char		*txt;
141 	unsigned char	*p;
142 	int		len;
143 {
144 	int		i;
145 
146 	error("%s ", txt);
147 	for (i = 0; i < len; i++) {
148 		if (isprint(p[i]))
149 			error("%c", p[i]);
150 		else
151 			error(".");
152 	}
153 	error("\n");
154 }
155 
156 LOCAL void
prbytes(txt,p,len)157 prbytes(txt, p, len)
158 		char	*txt;
159 	register Uchar	*p;
160 	register int	len;
161 {
162 	error("%s", txt);
163 	while (--len >= 0)
164 		error(" %02X", *p++);
165 	error("\n");
166 }
167 
168 unsigned char *
parse_xa(pnt,lenp,dpnt)169 parse_xa(pnt, lenp, dpnt)
170 	unsigned char	*pnt;
171 	int		*lenp;
172 	struct directory_entry *dpnt;
173 {
174 	struct iso_xa_dir_record *xadp;
175 	int		len = *lenp;
176 static	int		did_xa = 0;
177 
178 /*error("len: %d\n", len);*/
179 
180 	if (len >= 14) {
181 		xadp = (struct iso_xa_dir_record *)pnt;
182 
183 /*		if (dpnt) prbytes("XA ", pnt, len);*/
184 		if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
185 				xadp->reserved[0] == '\0') {
186 			len -= 14;
187 			pnt += 14;
188 			*lenp = len;
189 			if (!did_xa) {
190 				did_xa = 1;
191 				errmsgno(EX_BAD, _("Found XA directory extension record.\n"));
192 			}
193 		} else if (pnt[2] == 0) {
194 			char *cp = NULL;
195 
196 			if (dpnt)
197 				cp = (char *)&dpnt->isorec;
198 			if (cp) {
199 				prbytes("ISOREC:", (Uchar *)cp, 33+cp[32]);
200 				printasc("ISOREC:", (Uchar *)cp, 33+cp[32]);
201 				prbytes("XA REC:", pnt, len);
202 				printasc("XA REC:", pnt, len);
203 			}
204 			if (no_rr == 0) {
205 				errmsgno(EX_BAD, _("Disabling RR / XA / AA.\n"));
206 				no_rr = 1;
207 			}
208 			*lenp = 0;
209 			if (cp) {
210 				errmsgno(EX_BAD, _("Problems with old ISO directory entry for file: '%s'.\n"), &cp[33]);
211 			}
212 			errmsgno(EX_BAD, _("Illegal extended directory attributes found (bad XA disk?).\n"));
213 /*			errmsgno(EX_BAD, _("Disabling Rock Ridge for old session.\n"));*/
214 			comerrno(EX_BAD, _("Try again using the -no-rr option.\n"));
215 		}
216 	}
217 	if (len >= 4 && pnt[3] != 1 && pnt[3] != 2) {
218 		prbytes("BAD RR ATTRIBUTES:", pnt, len);
219 		printasc("BAD RR ATTRIBUTES:", pnt, len);
220 	}
221 	return (pnt);
222 }
223 
224 LOCAL BOOL
find_rr(idr,pntp,lenp)225 find_rr(idr, pntp, lenp)
226 	struct iso_directory_record *idr;
227 	Uchar		**pntp;
228 	int		*lenp;
229 {
230 	struct iso_xa_dir_record *xadp;
231 	int		len;
232 	unsigned char	*pnt;
233 	BOOL		ret = FALSE;
234 
235 	len = idr->length[0] & 0xff;
236 	len -= sizeof (struct iso_directory_record);
237 	len += sizeof (idr->name);
238 	len -= idr->name_len[0];
239 
240 	pnt = (unsigned char *) idr;
241 	pnt += sizeof (struct iso_directory_record);
242 	pnt -= sizeof (idr->name);
243 	pnt += idr->name_len[0];
244 	if ((idr->name_len[0] & 1) == 0) {
245 		pnt++;
246 		len--;
247 	}
248 	if (len >= 14) {
249 		xadp = (struct iso_xa_dir_record *)pnt;
250 
251 		if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
252 				xadp->reserved[0] == '\0') {
253 			len -= 14;
254 			pnt += 14;
255 			ret = TRUE;
256 		}
257 	}
258 	*pntp = pnt;
259 	*lenp = len;
260 	return (ret);
261 }
262 
263 LOCAL int
parse_rrflags(pnt,len,cont_flag)264 parse_rrflags(pnt, len, cont_flag)
265 	Uchar	*pnt;
266 	int	len;
267 	int	cont_flag;
268 {
269 	int		ncount;
270 	UInt32_t	cont_extent;
271 	UInt32_t	cont_offset;
272 	UInt32_t	cont_size;
273 	int		flag1;
274 	int		flag2;
275 
276 	cont_extent = cont_offset = cont_size = 0;
277 
278 	ncount = 0;
279 	flag1 = -1;
280 	flag2 = 0;
281 	while (len >= 4) {
282 		if (pnt[3] != 1 && pnt[3] != 2) {
283 			errmsgno(EX_BAD,
284 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
285 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
286 			return (0);	/* JS ??? Is this right ??? */
287 		}
288 		if (pnt[2] < 4) {
289 			errmsgno(EX_BAD,
290 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
291 				pnt[2], pnt, pnt[0], pnt[1]);
292 			return (0);	/* JS ??? Is this right ??? */
293 		}
294 		ncount++;
295 		if (pnt[0] == 'R' && pnt[1] == 'R')
296 			flag1 = pnt[4] & 0xff;
297 
298 		if (strncmp((char *)pnt, "PX", 2) == 0)		/* POSIX attributes */
299 			flag2 |= RR_FLAG_PX;
300 		if (strncmp((char *)pnt, "PN", 2) == 0)		/* POSIX device number */
301 			flag2 |= RR_FLAG_PN;
302 		if (strncmp((char *)pnt, "SL", 2) == 0)		/* Symlink */
303 			flag2 |= RR_FLAG_SL;
304 		if (strncmp((char *)pnt, "NM", 2) == 0)		/* Alternate Name */
305 			flag2 |= RR_FLAG_NM;
306 		if (strncmp((char *)pnt, "CL", 2) == 0)		/* Child link */
307 			flag2 |= RR_FLAG_CL;
308 		if (strncmp((char *)pnt, "PL", 2) == 0)		/* Parent link */
309 			flag2 |= RR_FLAG_PL;
310 		if (strncmp((char *)pnt, "RE", 2) == 0)		/* Relocated Direcotry */
311 			flag2 |= RR_FLAG_RE;
312 		if (strncmp((char *)pnt, "TF", 2) == 0)		/* Time stamp */
313 			flag2 |= RR_FLAG_TF;
314 		if (strncmp((char *)pnt, "SP", 2) == 0) {	/* SUSP record */
315 			flag2 |= RR_FLAG_SP;
316 			if (su_version < 0)
317 				su_version = pnt[3] & 0xff;
318 		}
319 		if (strncmp((char *)pnt, "AA", 2) == 0) {	/* Apple Signature record */
320 			flag2 |= RR_FLAG_AA;
321 			if (aa_version < 0)
322 				aa_version = pnt[3] & 0xff;
323 		}
324 		if (strncmp((char *)pnt, "ER", 2) == 0) {
325 			flag2 |= RR_FLAG_ER;				/* ER record */
326 			if (rr_version < 0)
327 				rr_version = pnt[7] & 0xff;		/* Ext Version */
328 			strlcpy(er_id, (char *)&pnt[8], (pnt[4] & 0xFF) + 1);
329 		}
330 
331 		if (strncmp((char *)pnt, "CE", 2) == 0) {	/* Continuation Area */
332 			cont_extent = get_733(pnt+4);
333 			cont_offset = get_733(pnt+12);
334 			cont_size = get_733(pnt+20);
335 		}
336 		if (strncmp((char *)pnt, "ST", 2) == 0) {		/* Terminate SUSP */
337 			break;
338 		}
339 
340 		len -= pnt[2];
341 		pnt += pnt[2];
342 	}
343 	if (cont_extent) {
344 		unsigned char   sector[SECTOR_SIZE];
345 
346 		readsecs(cont_extent, sector, 1);
347 		flag2 |= parse_rrflags(&sector[cont_offset], cont_size, 1);
348 	}
349 	return (flag2);
350 }
351 
352 int
rr_flags(idr)353 rr_flags(idr)
354 	struct iso_directory_record *idr;
355 {
356 	int		len;
357 	unsigned char	*pnt;
358 	int		ret = 0;
359 
360 	if (find_rr(idr, &pnt, &len))
361 		ret |= RR_FLAG_XA;
362 	ret |= parse_rrflags(pnt, len, 0);
363 	return (ret);
364 }
365 
366 /*
367  * Parse the RR attributes so we can find the file name.
368  */
369 LOCAL int
parse_rr(pnt,len,dpnt)370 parse_rr(pnt, len, dpnt)
371 	unsigned char	*pnt;
372 	int		len;
373 	struct directory_entry *dpnt;
374 {
375 	UInt32_t	cont_extent;
376 	UInt32_t	cont_offset;
377 	UInt32_t	cont_size;
378 	char		name_buf[256];
379 
380 	cont_extent = cont_offset = cont_size = 0;
381 
382 	pnt = parse_xa(pnt, &len, dpnt /* 0 */);
383 
384 	while (len >= 4) {
385 		if (pnt[3] != 1 && pnt[3] != 2) {
386 			errmsgno(EX_BAD,
387 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
388 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
389 			return (-1);
390 		}
391 		if (pnt[2] < 4) {
392 			errmsgno(EX_BAD,
393 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
394 				pnt[2], pnt, pnt[0], pnt[1]);
395 			return (-1);
396 		}
397 		if (strncmp((char *)pnt, "NM", 2) == 0) {
398 			strncpy(name_buf, (char *)pnt + 5, pnt[2] - 5);
399 			name_buf[pnt[2] - 5] = 0;
400 			if (dpnt->name) {
401 				size_t nlen = strlen(dpnt->name);
402 
403 				/*
404 				 * append to name from previous NM records
405 				 */
406 				dpnt->name = realloc(dpnt->name, nlen +
407 							strlen(name_buf) + 1);
408 				strcpy(dpnt->name + nlen, name_buf);
409 			} else {
410 				dpnt->name = e_strdup(name_buf);
411 				dpnt->got_rr_name = 1;
412 			}
413 			/* continue searching for more NM records */
414 		} else if (strncmp((char *)pnt, "CE", 2) == 0) {
415 			cont_extent = get_733(pnt + 4);
416 			cont_offset = get_733(pnt + 12);
417 			cont_size = get_733(pnt + 20);
418 		} else if (strncmp((char *)pnt, "ST", 2) == 0) {
419 			break;
420 		}
421 
422 		len -= pnt[2];
423 		pnt += pnt[2];
424 	}
425 	if (cont_extent) {
426 		unsigned char   sector[SECTOR_SIZE];
427 
428 		readsecs(cont_extent, sector, 1);
429 		if (parse_rr(&sector[cont_offset], cont_size, dpnt) == -1)
430 			return (-1);
431 	}
432 
433 	/* Fall back to the iso name if no RR name found */
434 	if (dpnt->name == NULL) {
435 		char	*cp;
436 
437 		strlcpy(name_buf, dpnt->isorec.name, sizeof (name_buf));
438 		cp = strchr(name_buf, ';');
439 		if (cp != NULL) {
440 			*cp = '\0';
441 		}
442 		dpnt->name = e_strdup(name_buf);
443 	}
444 	return (0);
445 } /* parse_rr */
446 
447 
448 /*
449  * Returns 1 if the two files are identical
450  * Returns 0 if the two files differ
451  */
452 LOCAL int
check_rr_dates(dpnt,current,statbuf,lstatbuf)453 check_rr_dates(dpnt, current, statbuf, lstatbuf)
454 	struct directory_entry *dpnt;
455 	struct directory_entry *current;
456 	struct stat	*statbuf;
457 	struct stat	*lstatbuf;
458 {
459 	UInt32_t	cont_extent;
460 	UInt32_t	cont_offset;
461 	UInt32_t	cont_size;
462 	UInt32_t	offset;
463 	unsigned char	*pnt;
464 	int		len;
465 	int		same_file;
466 	int		same_file_type;
467 	mode_t		mode;
468 	char		time_buf[7];
469 
470 
471 	cont_extent = cont_offset = cont_size = 0;
472 	same_file = 1;
473 	same_file_type = 1;
474 
475 	pnt = dpnt->rr_attributes;
476 	len = dpnt->rr_attr_size;
477 	/*
478 	 * We basically need to parse the rr attributes again, and dig out the
479 	 * dates and file types.
480 	 */
481 	pnt = parse_xa(pnt, &len, /* dpnt */ 0);
482 	while (len >= 4) {
483 		if (pnt[3] != 1 && pnt[3] != 2) {
484 			errmsgno(EX_BAD,
485 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
486 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
487 			return (-1);
488 		}
489 		if (pnt[2] < 4) {
490 			errmsgno(EX_BAD,
491 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
492 				pnt[2], pnt, pnt[0], pnt[1]);
493 			return (-1);
494 		}
495 
496 		/*
497 		 * If we have POSIX file modes, make sure that the file type is
498 		 * the same.  If it isn't, then we must always write the new
499 		 * file.
500 		 */
501 		if (strncmp((char *)pnt, "PX", 2) == 0) {
502 			mode = get_733(pnt + 4);
503 			if ((lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT)) {
504 				same_file_type = 0;
505 				same_file = 0;
506 			}
507 		}
508 		if (strncmp((char *)pnt, "TF", 2) == 0) {
509 			offset = 5;
510 			if (pnt[4] & TF_CREATE) {
511 				iso9660_date((char *)time_buf,
512 							lstatbuf->st_ctime);
513 				if (memcmp(time_buf, pnt + offset, 7) != 0)
514 					same_file = 0;
515 				offset += 7;
516 			}
517 			if (pnt[4] & TF_MODIFY) {
518 				iso9660_date((char *)time_buf,
519 							lstatbuf->st_mtime);
520 				if (memcmp(time_buf, pnt + offset, 7) != 0)
521 					same_file = 0;
522 				offset += 7;
523 			}
524 		}
525 		if (strncmp((char *)pnt, "CE", 2) == 0) {
526 			cont_extent = get_733(pnt + 4);
527 			cont_offset = get_733(pnt + 12);
528 			cont_size = get_733(pnt + 20);
529 		}
530 		if (strncmp((char *)pnt, "ST", 2) == 0) {		/* Terminate SUSP */
531 			break;
532 		}
533 
534 		len -= pnt[2];
535 		pnt += pnt[2];
536 	}
537 	if (cont_extent) {
538 		unsigned char   sector[SECTOR_SIZE];
539 
540 		readsecs(cont_extent, sector, 1);
541 		/*
542 		 * Continue to scan the extension record.
543 		 * Note that this has not been tested yet, but it is
544 		 * definitely more correct that calling parse_rr()
545 		 * as done in Eric's old code.
546 		 */
547 		pnt = &sector[cont_offset];
548 		len = cont_size;
549 		/*
550 		 * Clear the "pending extension record" state as
551 		 * we did already read it now.
552 		 */
553 		cont_extent = cont_offset = cont_size = 0;
554 	}
555 
556 	/*
557 	 * If we have the same fundamental file type, then it is clearly safe
558 	 * to reuse the TRANS.TBL entry.
559 	 */
560 	if (same_file_type) {
561 		current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
562 	}
563 	return (same_file);
564 }
565 
566 LOCAL BOOL
valid_iso_directory(idr,idr_off,space_left)567 valid_iso_directory(idr, idr_off, space_left)
568 	struct iso_directory_record	*idr;
569 	int				idr_off;
570 	size_t				space_left;
571 {
572 	size_t	idr_length	= idr->length[0] & 0xFF;
573 	size_t	idr_ext_length	= idr->ext_attr_length[0] & 0xFF;
574 	size_t	idr_namelength	= idr->name_len[0] & 0xFF;
575 	int	namelimit	= space_left -
576 				offsetof(struct iso_directory_record, name[0]);
577 	int	nlimit		= (idr_namelength < namelimit) ?
578 					idr_namelength : namelimit;
579 
580 	/*
581 	 * Check for sane length entries.
582 	 */
583 	if (idr_length > space_left) {
584 		comerrno(EX_BAD,
585 		    _("Bad directory length %zu (> %d available) for '%.*s'.\n"),
586 				idr_length, namelimit, nlimit, idr->name);
587 	}
588 
589 	if (idr_length == 0) {
590 		if ((idr_off % SECTOR_SIZE) != 0) {
591 			/*
592 			 * It marks a valid continuation entry.
593 			 */
594 			return (TRUE);
595 		} else {
596 			comerrno(EX_BAD,
597 				_("Zero directory length for '%.*s'.\n"),
598 				nlimit, idr->name);
599 		}
600 	}
601 	if (idr_length <= offsetof(struct iso_directory_record, name[0])) {
602 		comerrno(EX_BAD, _("Bad directory length %zu (< %zu minimum).\n"),
603 				idr_length, 1 + offsetof(struct iso_directory_record, name[0]));
604 	}
605 	if ((idr_length & 1) != 0) {
606 		comerrno(EX_BAD, _("Odd directory length %zu for '%.*s'.\n"),
607 				idr_length, nlimit, idr->name);
608 	}
609 
610 	if (idr_namelength == 0) {
611 		comerrno(EX_BAD, _("Zero filename length.\n"));
612 	}
613 
614 	if (!(idr_namelength & 1)) {
615 		/*
616 		 * if nam_len[0] is even, there has to be a pad byte at the end
617 		 * to make the directory length even
618 		 */
619 		idr_namelength++;
620 	}
621 	if ((offsetof(struct iso_directory_record, name[0]) +
622 	    idr_namelength) > idr_length) {
623 		int	xlimit = idr_length -
624 			offsetof(struct iso_directory_record, name[0]) -
625 			idr_ext_length;
626 
627 		if (xlimit < 0)
628 			xlimit = 0;
629 		if (nlimit < xlimit)
630 			xlimit = nlimit;
631 		comerrno(EX_BAD, _("Bad filename length %zu (> %d) for '%.*s'.\n"),
632 				idr_namelength, xlimit, xlimit, idr->name);
633 	}
634 	if ((offsetof(struct iso_directory_record, name[0]) +
635 	    idr_namelength + idr_ext_length) > idr_length) {
636 		int	xlimit = idr_length -
637 			offsetof(struct iso_directory_record, name[0]) -
638 			idr_namelength;
639 
640 		comerrno(EX_BAD, _("Bad extended attribute length %zu (> %d) for '%.*s'.\n"),
641 				idr_ext_length, xlimit, nlimit, idr->name);
642 	}
643 
644 #ifdef	__do_rr_
645 	/* check for rock ridge extensions */
646 
647 	if (no_rr) {
648 		/*
649 		 * Rock Ridge extensions are not present or manually disabled.
650 		 */
651 		return (TRUE);
652 	} else {
653 		int	rlen =  idr_length -
654 				offsetof(struct iso_directory_record, name[0]) -
655 				idr_namelength;
656 
657 		/* Check for the minimum of Rock Ridge extensions. */
658 	}
659 #endif
660 	return (TRUE);
661 }
662 
663 LOCAL struct directory_entry **
read_merging_directory(mrootp,nentp)664 read_merging_directory(mrootp, nentp)
665 	struct iso_directory_record *mrootp;
666 	int		*nentp;
667 {
668 	unsigned char	*cpnt;
669 	unsigned char	*cpnt1;
670 	char		*p;
671 	char		*dirbuff;
672 	int		i;
673 	struct iso_directory_record *idr;
674 	UInt32_t	len;
675 	UInt32_t	nbytes;
676 	int		nent;
677 	int		nmult;		/* # of multi extent root entries */
678 	int		mx;
679 	struct directory_entry **pnt;
680 	UInt32_t	rlen;
681 	struct directory_entry **rtn;
682 	int		seen_rockridge;
683 	unsigned char	*tt_buf;
684 	UInt32_t	tt_extent;
685 	UInt32_t		tt_size;
686 
687 	static int	warning_given = 0;
688 
689 	/*
690 	 * This is the number of sectors we will need to read.  We need to
691 	 * round up to get the last fractional sector - we are asking for the
692 	 * data in terms of a number of sectors.
693 	 */
694 	nbytes = roundup(get_733(mrootp->size), SECTOR_SIZE);
695 
696 	/*
697 	 * First, allocate a buffer large enough to read in the entire
698 	 * directory.
699 	 */
700 	dirbuff = (char *)e_malloc(nbytes);
701 
702 	readsecs(get_733(mrootp->extent), dirbuff, nbytes / SECTOR_SIZE);
703 
704 	/*
705 	 * Next look over the directory, and count up how many entries we have.
706 	 */
707 	len = get_733(mrootp->size);
708 	i = 0;
709 	*nentp = 0;
710 	nent = 0;
711 	nmult = 0;
712 	mx = 0;
713 	while ((i + offsetof(struct iso_directory_record, name[0])) < len) {
714 		idr = (struct iso_directory_record *)&dirbuff[i];
715 
716 		if (!valid_iso_directory(idr, i, len - i))
717 			break;
718 
719 		if (idr->length[0] == 0) {
720 			i = ISO_ROUND_UP(i);
721 			continue;
722 		}
723 		nent++;
724 		if ((mx & ISO_MULTIEXTENT) == 0 &&
725 		    (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
726 			nmult++;	/* Need a multi extent root entry */
727 		}
728 		mx = idr->flags[0];
729 		i += idr->length[0];
730 	}
731 
732 	/*
733 	 * Now allocate the buffer which will hold the array we are about to
734 	 * return. We need one entry per real directory entry and in addition
735 	 * one multi-extent root entry per multi-extent file.
736 	 */
737 	rtn = (struct directory_entry **)e_malloc((nent+nmult) * sizeof (*rtn));
738 
739 	/*
740 	 * Finally, scan the directory one last time, and pick out the relevant
741 	 * bits of information, and store it in the relevant bits of the
742 	 * structure.
743 	 */
744 	i = 0;
745 	pnt = rtn;
746 	tt_extent = 0;
747 	seen_rockridge = 0;
748 	tt_size = 0;
749 	mx = 0;
750 	while ((i + offsetof(struct iso_directory_record, name[0])) < len) {
751 		idr = (struct iso_directory_record *)&dirbuff[i];
752 
753 		if (!valid_iso_directory(idr, i, len - i))
754 			break;
755 
756 		if (idr->length[0] == 0) {
757 			i = ISO_ROUND_UP(i);
758 			continue;
759 		}
760 		*pnt = (struct directory_entry *)e_malloc(sizeof (**rtn));
761 		(*pnt)->next = NULL;
762 #ifdef	DEBUG
763 		error("IDR name: '%s' ist: %d soll: %d\n",
764 			idr->name, strlen(idr->name), idr->name_len[0]);
765 #endif
766 		movebytes(idr, &(*pnt)->isorec, idr->length[0] & 0xFF);
767 		(*pnt)->starting_block =
768 				get_733(idr->extent);
769 		(*pnt)->size = get_733(idr->size);
770 		if ((*pnt)->size == 0) {
771 			/*
772 			 * Find lowest used inode number for zero sized files
773 			 */
774 			if (((UInt32_t)(*pnt)->starting_block) <= null_inodes) {
775 				null_inodes = (UInt32_t)(*pnt)->starting_block;
776 				null_inodes--;
777 			}
778 		}
779 		(*pnt)->priority = 0;
780 		(*pnt)->name = NULL;
781 		(*pnt)->got_rr_name = 0;
782 		(*pnt)->table = NULL;
783 		(*pnt)->whole_name = NULL;
784 		(*pnt)->filedir = NULL;
785 		(*pnt)->parent_rec = NULL;
786 		/*
787 		 * Set this information so that we correctly cache previous
788 		 * session bits of information.
789 		 */
790 		(*pnt)->inode = (*pnt)->starting_block;
791 		(*pnt)->dev = PREV_SESS_DEV;
792 		(*pnt)->rr_attributes = NULL;
793 		(*pnt)->rr_attr_size = 0;
794 		(*pnt)->total_rr_attr_size = 0;
795 		(*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY;
796 #ifdef APPLE_HYB
797 		(*pnt)->assoc = NULL;
798 		(*pnt)->hfs_ent = NULL;
799 #endif	/* APPLE_HYB */
800 
801 		/*
802 		 * Check for and parse any RR attributes for the file. All we
803 		 * are really looking for here is the original name of the
804 		 * file.
805 		 */
806 		rlen = idr->length[0] & 0xff;
807 		cpnt = (unsigned char *) idr;
808 
809 		rlen -= offsetof(struct iso_directory_record, name[0]);
810 		cpnt += offsetof(struct iso_directory_record, name[0]);
811 
812 		rlen -= idr->name_len[0];
813 		cpnt += idr->name_len[0];
814 
815 		if ((idr->name_len[0] & 1) == 0) {
816 			cpnt++;
817 			rlen--;
818 		}
819 
820 		if (no_rr)
821 			rlen = 0;
822 		if (rlen > 0) {
823 			(*pnt)->total_rr_attr_size =
824 						(*pnt)->rr_attr_size = rlen;
825 			(*pnt)->rr_attributes = e_malloc(rlen);
826 			memcpy((*pnt)->rr_attributes, cpnt, rlen);
827 			seen_rockridge = 1;
828 		}
829 #ifdef	DEBUG
830 		error("INT name: '%s' ist: %d soll: %d\n",
831 			(*pnt)->isorec.name, strlen((*pnt)->isorec.name),
832 			idr->name_len[0]);
833 #endif
834 
835 		if (idr->name_len[0] < sizeof ((*pnt)->isorec.name)) {
836 			/*
837 			 * Now zero out the remainder of the name field.
838 			 */
839 			cpnt = (unsigned char *) (*pnt)->isorec.name;
840 			cpnt += idr->name_len[0];
841 			memset(cpnt, 0,
842 				sizeof ((*pnt)->isorec.name) - idr->name_len[0]);
843 		} else {
844 			/*
845 			 * Simple sanity work to make sure that we have no
846 			 * illegal data structures in our tree.
847 			 */
848 			(*pnt)->isorec.name[MAX_ISONAME] = '\0';
849 			(*pnt)->isorec.name_len[0] = MAX_ISONAME;
850 		}
851 		/*
852 		 * If the filename len from the old session is more
853 		 * then 31 chars, there is a high risk of hard violations
854 		 * of the ISO9660 standard.
855 		 * Run it through our name canonication machine....
856 		 */
857 		if (idr->name_len[0] > LEN_ISONAME || check_oldnames) {
858 			iso9660_check(idr, *pnt);
859 		}
860 
861 		if (parse_rr((*pnt)->rr_attributes, rlen, *pnt) == -1) {
862 			comerrno(EX_BAD,
863 			    _("Cannot parse Rock Ridge attributes for '%s'.\n"),
864 								idr->name);
865 		}
866 		if (((*pnt)->isorec.name_len[0] == 1) &&
867 		    (((*pnt)->isorec.name[0] == 0) ||	/* "."  entry */
868 		    ((*pnt)->isorec.name[0] == 1))) {	/* ".." entry */
869 
870 			if ((*pnt)->name != NULL) {
871 				free((*pnt)->name);
872 			}
873 			if ((*pnt)->whole_name != NULL) {
874 				free((*pnt)->whole_name);
875 			}
876 			if ((*pnt)->isorec.name[0] == 0) {
877 				(*pnt)->name = e_strdup(".");
878 			} else {
879 				(*pnt)->name = e_strdup("..");
880 			}
881 		}
882 #ifdef DEBUG
883 		fprintf(stderr, "got DE name: %s\n", (*pnt)->name);
884 #endif
885 
886 		if (strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0) {
887 			if ((*pnt)->name != NULL) {
888 				free((*pnt)->name);
889 			}
890 			if ((*pnt)->whole_name != NULL) {
891 				free((*pnt)->whole_name);
892 			}
893 /*			(*pnt)->name = e_strdup("<translation table>");*/
894 			(*pnt)->name = e_strdup(trans_tbl);
895 			tt_extent = get_733(idr->extent);
896 			tt_size = get_733(idr->size);
897 			if (tt_extent == 0)
898 				tt_size = 0;
899 		}
900 		/*
901 		 * The beginning of a new multi extent directory chain is when
902 		 * the last directory had no ISO_MULTIEXTENT flag set and the
903 		 * current entry did set ISO_MULTIEXTENT.
904 		 */
905 		if ((mx & ISO_MULTIEXTENT) == 0 &&
906 		    (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
907 			struct directory_entry		*s_entry;
908 			struct iso_directory_record	*idr2 = idr;
909 			int				i2 = i;
910 			off_t				tsize = 0;
911 
912 			/*
913 			 * Sum up the total file size for the multi extent file
914 			 */
915 			while ((i2 + offsetof(struct iso_directory_record, name[0])) < len) {
916 				idr2 = (struct iso_directory_record *)&dirbuff[i2];
917 				if (idr2->length[0] == 0) {
918 					i2 = ISO_ROUND_UP(i2);
919 					continue;
920 				}
921 
922 				tsize += get_733(idr2->size);
923 				if ((idr2->flags[0] & ISO_MULTIEXTENT) == 0)
924 					break;
925 				i2 += idr2->length[0];
926 			}
927 
928 			s_entry = dup_directory_entry(*pnt);	/* dup first for mxroot */
929 			s_entry->de_flags |= MULTI_EXTENT;
930 			s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
931 			s_entry->size = tsize;
932 			s_entry->starting_block = (*pnt)->starting_block;
933 			s_entry->mxroot = s_entry;
934 			s_entry->mxpart = 0;
935 			s_entry->next = *pnt;	/* Next in list		*/
936 			pnt[1] = pnt[0];	/* Move to next slot	*/
937 			*pnt = s_entry;		/* First slot is mxroot	*/
938 			pnt++;			/* Point again to cur.	*/
939 		}
940 		if ((mx & ISO_MULTIEXTENT) != 0 ||
941 		    (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
942 			(*pnt)->de_flags |= MULTI_EXTENT;
943 			(*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
944 			(pnt[-1])->next = *pnt;
945 			(*pnt)->mxroot = (pnt[-1])->mxroot;
946 			(*pnt)->mxpart = (pnt[-1])->mxpart + 1;
947 		}
948 		pnt++;
949 		mx = idr->flags[0];
950 		i += idr->length[0];
951 	}
952 #ifdef APPLE_HYB
953 	/*
954 	 * If we find an associated file, check if there is a file
955 	 * with same ISO name and link it to this entry
956 	 */
957 	for (pnt = rtn, i = 0; i < nent; i++, pnt++) {
958 		int	j;
959 
960 		rlen = get_711((*pnt)->isorec.name_len);
961 		if ((*pnt)->isorec.flags[0] & ISO_ASSOCIATED) {
962 			for (j = 0; j < nent; j++) {
963 				if (strncmp(rtn[j]->isorec.name,
964 				    (*pnt)->isorec.name, rlen) == 0 &&
965 				    (rtn[j]->isorec.flags[0] & ISO_ASSOCIATED) == 0) {
966 					rtn[j]->assoc = *pnt;
967 
968 					/*
969 					 * don't want this entry to be
970 					 * in the Joliet tree
971 					 */
972 					(*pnt)->de_flags |= INHIBIT_JOLIET_ENTRY;
973 					/*
974 					 * XXX Is it correct to exclude UDF too?
975 					 */
976 					(*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
977 
978 					/*
979 					 * as we have associated files, then
980 					 * assume we are are dealing with
981 					 * Apple's extensions - if not already
982 					 * set
983 					 */
984 					if (apple_both == 0) {
985 						apple_both = apple_ext = 1;
986 					}
987 					break;
988 				}
989 			}
990 		}
991 	}
992 #endif	/* APPLE_HYB */
993 
994 	/*
995 	 * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
996 	 * to get the filenames of the files.  Also, save the table info, just
997 	 * in case we need to use it.
998 	 *
999 	 * The entries look something like: F ISODUMP.;1 isodump
1000 	 */
1001 	if (tt_extent != 0 && tt_size != 0) {
1002 		nbytes = roundup(tt_size, SECTOR_SIZE);
1003 		tt_buf = (unsigned char *) e_malloc(nbytes);
1004 		readsecs(tt_extent, tt_buf, nbytes / SECTOR_SIZE);
1005 
1006 		/*
1007 		 * Loop through the file, examine each entry, and attempt to
1008 		 * attach it to the correct entry.
1009 		 */
1010 		cpnt = tt_buf;
1011 		cpnt1 = tt_buf;
1012 		while (cpnt - tt_buf < tt_size) {
1013 			/* Skip to a line terminator, or end of the file. */
1014 			while ((cpnt1 - tt_buf < tt_size) &&
1015 				(*cpnt1 != '\n') &&
1016 				(*cpnt1 != '\0')) {
1017 				cpnt1++;
1018 			}
1019 			/* Zero terminate this particular line. */
1020 			if (cpnt1 - tt_buf < tt_size) {
1021 				*cpnt1 = '\0';
1022 			}
1023 			/*
1024 			 * Now dig through the actual directories, and try and
1025 			 * find the attachment for this particular filename.
1026 			 */
1027 			for (pnt = rtn, i = 0; i < nent; i++, pnt++) {
1028 				rlen = get_711((*pnt)->isorec.name_len);
1029 
1030 				/*
1031 				 * If this filename is so long that it would
1032 				 * extend past the end of the file, it cannot
1033 				 * be the one we want.
1034 				 */
1035 				if (cpnt + 2 + rlen - tt_buf >= tt_size) {
1036 					continue;
1037 				}
1038 				/*
1039 				 * Now actually compare the name, and make sure
1040 				 * that the character at the end is a ' '.
1041 				 */
1042 				if (strncmp((char *)cpnt + 2,
1043 					(*pnt)->isorec.name, rlen) == 0 &&
1044 					cpnt[2 + rlen] == ' ' &&
1045 					(p = strchr((char *)&cpnt[2 + rlen], '\t'))) {
1046 					p++;
1047 					/*
1048 					 * This is a keeper. Now determine the
1049 					 * correct table entry that we will
1050 					 * use on the new image.
1051 					 */
1052 					if (strlen(p) > 0) {
1053 						(*pnt)->table =
1054 						    e_malloc(strlen(p) + 4);
1055 						sprintf((*pnt)->table,
1056 							"%c\t%s\n",
1057 							*cpnt, p);
1058 					}
1059 					if (!(*pnt)->got_rr_name) {
1060 						if ((*pnt)->name != NULL) {
1061 							free((*pnt)->name);
1062 						}
1063 						(*pnt)->name = e_strdup(p);
1064 					}
1065 					break;
1066 				}
1067 			}
1068 			cpnt = cpnt1 + 1;
1069 			cpnt1 = cpnt;
1070 		}
1071 
1072 		free(tt_buf);
1073 	} else if (!seen_rockridge && !warning_given) {
1074 		/*
1075 		 * Warn the user that iso-9660 names were used because neither
1076 		 * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were
1077 		 * found.
1078 		 */
1079 		fprintf(stderr,
1080 		    _("Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n"));
1081 		fprintf(stderr,
1082 		    _("name translations were found on previous session.\n"));
1083 		fprintf(stderr,
1084 		    _("ISO-9660 file names have been used instead.\n"));
1085 		warning_given = 1;
1086 	}
1087 	if (dirbuff != NULL) {
1088 		free(dirbuff);
1089 	}
1090 	*nentp = nent + nmult;
1091 	return (rtn);
1092 } /* read_merging_directory */
1093 
1094 /*
1095  * Free any associated data related to the structures.
1096  */
1097 LOCAL int
free_mdinfo(ptr,len)1098 free_mdinfo(ptr, len)
1099 	struct directory_entry **ptr;
1100 	int		len;
1101 {
1102 	int		i;
1103 	struct directory_entry **p;
1104 
1105 	p = ptr;
1106 	for (i = 0; i < len; i++, p++) {
1107 		/*
1108 		 * If the tree-handling code decided that it needed an entry, it
1109 		 * will have removed it from the list.  Thus we must allow for
1110 		 * null pointers here.
1111 		 */
1112 		if (*p == NULL) {
1113 			continue;
1114 		}
1115 		free_directory_entry(*p);
1116 	}
1117 
1118 	free(ptr);
1119 	return (0);
1120 }
1121 
1122 LOCAL void
free_directory_entry(dirp)1123 free_directory_entry(dirp)
1124 	struct directory_entry *dirp;
1125 {
1126 	if (dirp->name != NULL)
1127 		free(dirp->name);
1128 
1129 	if (dirp->whole_name != NULL)
1130 		free(dirp->whole_name);
1131 
1132 	if (dirp->rr_attributes != NULL)
1133 		free(dirp->rr_attributes);
1134 
1135 	if (dirp->table != NULL)
1136 		free(dirp->table);
1137 
1138 	free(dirp);
1139 }
1140 
1141 /*
1142  * Search the list to see if we have any entries from the previous
1143  * session that match this entry.  If so, copy the extent number
1144  * over so we don't bother to write it out to the new session.
1145  */
1146 int
check_prev_session(ptr,len,curr_entry,statbuf,lstatbuf,odpnt)1147 check_prev_session(ptr, len, curr_entry, statbuf, lstatbuf, odpnt)
1148 	struct directory_entry	**ptr;
1149 	int		len;
1150 	struct directory_entry *curr_entry;
1151 	struct stat	*statbuf;
1152 	struct stat	*lstatbuf;
1153 	struct directory_entry **odpnt;
1154 {
1155 	int		i;
1156 	int		rr;
1157 	int		retcode = -2;	/* Default not found */
1158 
1159 	for (i = 0; i < len; i++) {
1160 		if (ptr[i] == NULL) {	/* Used or empty entry skip */
1161 			continue;
1162 		}
1163 #if 0
1164 		if (ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 &&
1165 		    ptr[i]->name[0] == '\0') {
1166 			continue;
1167 		}
1168 		if (ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 &&
1169 		    ptr[i]->name[0] == 1) {
1170 			continue;
1171 		}
1172 #else
1173 		if (ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0) {
1174 			continue;
1175 		}
1176 		if (ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0) {
1177 			continue;
1178 		}
1179 #endif
1180 
1181 		if (ptr[i]->name != NULL &&
1182 		    strcmp(ptr[i]->name, curr_entry->name) != 0) {
1183 			/* Not the same name continue */
1184 			continue;
1185 		}
1186 		/*
1187 		 * It's a directory so we must always merge it with the new
1188 		 * session. Never ever reuse directory extents.  See comments
1189 		 * in tree.c for an explaination of why this must be the case.
1190 		 */
1191 		if ((curr_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1192 			retcode = i;
1193 			goto found_it;
1194 		}
1195 		/*
1196 		 * We know that the files have the same name.  If they also
1197 		 * have the same file type (i.e. file, dir, block, etc), then
1198 		 * we can safely reuse the TRANS.TBL entry for this file. The
1199 		 * check_rr_dates() function will do this for us.
1200 		 *
1201 		 * Verify that the file type and dates are consistent. If not,
1202 		 * we probably have a different file, and we need to write it
1203 		 * out again.
1204 		 */
1205 		retcode = i;
1206 
1207 		if (ptr[i]->rr_attributes != NULL) {
1208 			if ((rr = check_rr_dates(ptr[i], curr_entry, statbuf,
1209 							lstatbuf)) == -1)
1210 				return (-1);
1211 
1212 			if (rr == 0) {	/* Different files */
1213 				goto found_it;
1214 			}
1215 		}
1216 		/*
1217 		 * Verify size and timestamp.  If rock ridge is in use, we
1218 		 * need to compare dates from RR too.  Directories are special,
1219 		 * we calculate their size later.
1220 		 */
1221 		if (ptr[i]->size != curr_entry->size) {
1222 			/* Different files */
1223 			goto found_it;
1224 		}
1225 		if (memcmp(ptr[i]->isorec.date,
1226 					curr_entry->isorec.date, 7) != 0) {
1227 			/* Different files */
1228 			goto found_it;
1229 		}
1230 		/* We found it and we can reuse the extent */
1231 		memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
1232 		curr_entry->starting_block = get_733(ptr[i]->isorec.extent);
1233 		curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1234 
1235 		if ((curr_entry->isorec.flags[0] & ISO_MULTIEXTENT) ||
1236 		    (ptr[i]->isorec.flags[0] & ISO_MULTIEXTENT)) {
1237 			copy_mult_extent(curr_entry, ptr[i]);
1238 		}
1239 		goto found_it;
1240 	}
1241 	return (retcode);
1242 
1243 found_it:
1244 	if (ptr[i]->mxroot == ptr[i]) {	/* Remove all multi ext. entries   */
1245 		int	j = i + 1;	/* First one will be removed below */
1246 
1247 		while (j < len && ptr[j] && ptr[j]->mxroot == ptr[i]) {
1248 			free(ptr[j]);
1249 			ptr[j++] = NULL;
1250 		}
1251 	}
1252 	if (odpnt != NULL) {
1253 		*odpnt = ptr[i];
1254 	} else {
1255 		free(ptr[i]);
1256 	}
1257 	ptr[i] = NULL;
1258 	return (retcode);
1259 }
1260 
1261 /*
1262  * Return the number of directory entries for a file. This is usually 1
1263  * but may be 3 or more in case of multi extent files.
1264  */
1265 LOCAL int
iso_dir_ents(de)1266 iso_dir_ents(de)
1267 	struct directory_entry	*de;
1268 {
1269 	struct directory_entry	*de2;
1270 	int	ret = 0;
1271 
1272 	if (de->mxroot == NULL)
1273 		return (1);
1274 	de2 = de;
1275 	while (de2 != NULL && de2->mxroot == de->mxroot) {
1276 		ret++;
1277 		de2 = de2->next;
1278 	}
1279 	return (ret);
1280 }
1281 
1282 /*
1283  * Copy old multi-extent directory information from the previous session.
1284  * If both the old session and the current session are created by mkisofs
1285  * then this code could be extremely simple as the information is only copied
1286  * in case that the file did not change since the last session was made.
1287  * As we don't know the other ISO formatter program, any combination of
1288  * multi-extent files and even a single extent file could be possible.
1289  * We need to handle all files the same way ad the old session was created as
1290  * we reuse the data extents from the file in the old session.
1291  */
1292 LOCAL void
copy_mult_extent(se1,se2)1293 copy_mult_extent(se1, se2)
1294 	struct directory_entry	*se1;
1295 	struct directory_entry	*se2;
1296 {
1297 	struct directory_entry	*curr_entry = se1;
1298 	int			len1;
1299 	int			len2;
1300 	int			mxpart = 0;
1301 
1302 	len1 = iso_dir_ents(se1);
1303 	len2 = iso_dir_ents(se2);
1304 
1305 	if (len1 == 1) {
1306 		/*
1307 		 * Convert single-extent to multi-extent.
1308 		 * If *se1 is not multi-extent, *se2 definitely is
1309 		 * and we need to set up a MULTI_EXTENT directory header.
1310 		 */
1311 		se1->de_flags |= MULTI_EXTENT;
1312 		se1->isorec.flags[0] |= ISO_MULTIEXTENT;
1313 		se1->mxroot = curr_entry;
1314 		se1->mxpart = 0;
1315 		se1 = dup_directory_entry(se1);
1316 		curr_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
1317 		se1->de_flags |= INHIBIT_UDF_ENTRY;
1318 		se1->next = curr_entry->next;
1319 		curr_entry->next = se1;
1320 		se1 = curr_entry;
1321 		len1 = 2;
1322 	}
1323 
1324 	while (se2->isorec.flags[0] & ISO_MULTIEXTENT) {
1325 		len1--;
1326 		len2--;
1327 		if (len1 <= 0) {
1328 			struct directory_entry *sex = dup_directory_entry(se1);
1329 
1330 			sex->mxroot = curr_entry;
1331 			sex->next = se1->next;
1332 			se1->next = sex;
1333 			len1++;
1334 		}
1335 		memcpy(se1->isorec.extent, se2->isorec.extent, 8);
1336 		se1->starting_block = get_733(se2->isorec.extent);
1337 		se1->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1338 		se1->de_flags |= MULTI_EXTENT;
1339 		se1->isorec.flags[0] |= ISO_MULTIEXTENT;
1340 		se1->mxroot = curr_entry;
1341 		se1->mxpart = mxpart++;
1342 
1343 		se1 = se1->next;
1344 		se2 = se2->next;
1345 	}
1346 	memcpy(se1->isorec.extent, se2->isorec.extent, 8);
1347 	se1->starting_block = get_733(se2->isorec.extent);
1348 	se1->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1349 	se1->isorec.flags[0] &= ~ISO_MULTIEXTENT;	/* Last entry */
1350 	se1->mxpart = mxpart;
1351 	while (len1 > 1) {				/* Drop other entries */
1352 		struct directory_entry	*sex;
1353 
1354 		sex = se1->next;
1355 		se1->next = sex->next;
1356 		free(sex);
1357 		len1--;
1358 	}
1359 }
1360 
1361 /*
1362  * open_merge_image:  Open an existing image.
1363  */
1364 int
open_merge_image(path)1365 open_merge_image(path)
1366 	char	*path;
1367 {
1368 #ifndef	USE_SCG
1369 	in_image = fopen(path, "rb");
1370 	if (in_image == NULL) {
1371 		return (-1);
1372 	}
1373 #else
1374 	in_image = fopen(path, "rb");
1375 	if (in_image == NULL) {
1376 		if (scsidev_open(path) < 0)
1377 			return (-1);
1378 	}
1379 #endif
1380 	return (0);
1381 }
1382 
1383 /*
1384  * close_merge_image:  Close an existing image.
1385  */
1386 int
close_merge_image()1387 close_merge_image()
1388 {
1389 #ifdef	USE_SCG
1390 	return (scsidev_close());
1391 #else
1392 	return (fclose(in_image));
1393 #endif
1394 }
1395 
1396 /*
1397  * merge_isofs:  Scan an existing image, and return a pointer
1398  * to the root directory for this image.
1399  */
1400 struct iso_directory_record *
merge_isofs(path)1401 merge_isofs(path)
1402 	char	*path;
1403 {
1404 	char		buffer[SECTOR_SIZE];
1405 	int		file_addr;
1406 	int		i;
1407 	int		sum = 0;
1408 	char		*p = buffer;
1409 	struct iso_primary_descriptor *pri = NULL;
1410 	struct iso_directory_record *rootp;
1411 	struct iso_volume_descriptor *vdp;
1412 
1413 	/*
1414 	 * Start by searching for the volume header. Ultimately, we need to
1415 	 * search for volume headers in multiple places because we might be
1416 	 * starting with a multisession image. FIXME(eric).
1417 	 */
1418 	get_session_start(&file_addr);
1419 
1420 	for (i = 0; i < 100; i++) {
1421 		if (readsecs(file_addr, buffer,
1422 				sizeof (buffer) / SECTOR_SIZE) != sizeof (buffer)) {
1423 			comerr(_("Read error on old image %s\n"), path);
1424 		}
1425 		vdp = (struct iso_volume_descriptor *)buffer;
1426 
1427 		if ((strncmp(vdp->id, ISO_STANDARD_ID, sizeof (vdp->id)) == 0) &&
1428 		    (get_711(vdp->type) == ISO_VD_PRIMARY)) {
1429 			break;
1430 		}
1431 		file_addr += 1;
1432 	}
1433 
1434 	if (i == 100) {
1435 		return (NULL);
1436 	}
1437 	for (i = 0; i < 2048-3; i++) {
1438 		sum += p[i] & 0xFF;
1439 	}
1440 	pri = (struct iso_primary_descriptor *)vdp;
1441 
1442 	/* Check the blocksize of the image to make sure it is compatible. */
1443 	if (get_723(pri->logical_block_size) != SECTOR_SIZE) {
1444 		errmsgno(EX_BAD,
1445 			_("Previous session has incompatible sector size %u.\n"),
1446 			get_723(pri->logical_block_size));
1447 		return (NULL);
1448 	}
1449 	if (get_723(pri->volume_set_size) != 1) {
1450 		errmsgno(EX_BAD,
1451 			_("Previous session has volume set size %u (must be 1).\n"),
1452 			get_723(pri->volume_set_size));
1453 		return (NULL);
1454 	}
1455 	/* Get the location and size of the root directory. */
1456 	rootp = (struct iso_directory_record *)
1457 		e_malloc(sizeof (struct iso_directory_record));
1458 
1459 	memcpy(rootp, pri->root_directory_record,
1460 				sizeof (pri->root_directory_record));
1461 
1462 	for (i = 0; i < 100; i++) {
1463 		if (readsecs(file_addr, buffer,
1464 				sizeof (buffer) / SECTOR_SIZE) != sizeof (buffer)) {
1465 			comerr(_("Read error on old image %s\n"), path);
1466 		}
1467 		if (strncmp(buffer, "MKI ", 4) == 0) {
1468 			int	sum2;
1469 
1470 			sum2  = p[2045] & 0xFF;
1471 			sum2 *= 256;
1472 			sum2 += p[2046] & 0xFF;
1473 			sum2 *= 256;
1474 			sum2 += p[2047] & 0xFF;
1475 			if (sum == sum2) {
1476 				error(_("ISO-9660 image includes checksum signature for correct inode numbers.\n"));
1477 			} else {
1478 				correct_inodes = FALSE;
1479 				rrip112 = FALSE;
1480 			}
1481 			break;
1482 		}
1483 		file_addr += 1;
1484 	}
1485 
1486 	return (rootp);
1487 }
1488 
1489 LOCAL void
merge_remaining_entries(this_dir,pnt,n_orig)1490 merge_remaining_entries(this_dir, pnt, n_orig)
1491 	struct directory *this_dir;
1492 	struct directory_entry **pnt;
1493 	int		n_orig;
1494 {
1495 	int		i;
1496 	struct directory_entry *s_entry;
1497 	UInt32_t	ttbl_extent = 0;
1498 	unsigned int	ttbl_index = 0;
1499 	char		whole_path[PATH_MAX];
1500 
1501 	/*
1502 	 * Whatever is leftover in the list needs to get merged back into the
1503 	 * directory.
1504 	 */
1505 	for (i = 0; i < n_orig; i++) {
1506 		if (pnt[i] == NULL) {
1507 			continue;
1508 		}
1509 		if (pnt[i]->name != NULL && pnt[i]->whole_name == NULL) {
1510 			/* Set the name for this directory. */
1511 			strlcpy(whole_path, this_dir->de_name,
1512 							sizeof (whole_path));
1513 			strcat(whole_path, SPATH_SEPARATOR);
1514 			strcat(whole_path, pnt[i]->name);
1515 
1516 			pnt[i]->whole_name = e_strdup(whole_path);
1517 		}
1518 		if (pnt[i]->name != NULL &&
1519 /*			strcmp(pnt[i]->name, "<translation table>") == 0 )*/
1520 			strcmp(pnt[i]->name, trans_tbl) == 0) {
1521 			ttbl_extent =
1522 			    get_733(pnt[i]->isorec.extent);
1523 			ttbl_index = i;
1524 			continue;
1525 		}
1526 
1527 		/*
1528 		 * Skip directories for now - these need to be treated
1529 		 * differently.
1530 		 */
1531 		if ((pnt[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1532 			/*
1533 			 * FIXME - we need to insert this directory into the
1534 			 * tree, so that the path tables we generate will be
1535 			 * correct.
1536 			 */
1537 			if ((strcmp(pnt[i]->name, ".") == 0) ||
1538 				(strcmp(pnt[i]->name, "..") == 0)) {
1539 				free_directory_entry(pnt[i]);
1540 				pnt[i] = NULL;
1541 				continue;
1542 			} else {
1543 				merge_old_directory_into_tree(pnt[i], this_dir);
1544 			}
1545 		}
1546 		pnt[i]->next = this_dir->contents;
1547 		pnt[i]->filedir = this_dir;
1548 		this_dir->contents = pnt[i];
1549 		pnt[i] = NULL;
1550 	}
1551 
1552 
1553 	/*
1554 	 * If we don't have an entry for the translation table, then don't
1555 	 * bother trying to copy the starting extent over. Note that it is
1556 	 * possible that if we are copying the entire directory, the entry for
1557 	 * the translation table will have already been inserted into the
1558 	 * linked list and removed from the old entries list, in which case we
1559 	 * want to leave the extent number as it was before.
1560 	 */
1561 	if (ttbl_extent == 0) {
1562 		return;
1563 	}
1564 	/*
1565 	 * Finally, check the directory we are creating to see whether there
1566 	 * are any new entries in it.  If there are not, we can reuse the same
1567 	 * translation table.
1568 	 */
1569 	for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1570 		/*
1571 		 * Don't care about '.' or '..'.  They are never in the table
1572 		 * anyways.
1573 		 */
1574 		if (s_entry->name != NULL && strcmp(s_entry->name, ".") == 0) {
1575 			continue;
1576 		}
1577 		if (s_entry->name != NULL && strcmp(s_entry->name, "..") == 0) {
1578 			continue;
1579 		}
1580 /*		if (s_entry->name != NULL &&*/
1581 /*		    strcmp(s_entry->name, "<translation table>") == 0)*/
1582 		if (s_entry->name != NULL &&
1583 		    strcmp(s_entry->name, trans_tbl) == 0) {
1584 			continue;
1585 		}
1586 		if ((s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0) {
1587 			return;
1588 		}
1589 	}
1590 
1591 	/*
1592 	 * Locate the translation table, and re-use the same extent. It isn't
1593 	 * clear that there should ever be one in there already so for now we
1594 	 * try and muddle through the best we can.
1595 	 */
1596 	for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1597 /*		if (strcmp(s_entry->name, "<translation table>") == 0)*/
1598 		if (strcmp(s_entry->name, trans_tbl) == 0) {
1599 			fprintf(stderr, "Should never get here\n");
1600 			set_733(s_entry->isorec.extent, ttbl_extent);
1601 			return;
1602 		}
1603 	}
1604 
1605 	pnt[ttbl_index]->next = this_dir->contents;
1606 	pnt[ttbl_index]->filedir = this_dir;
1607 	this_dir->contents = pnt[ttbl_index];
1608 	pnt[ttbl_index] = NULL;
1609 }
1610 
1611 
1612 /*
1613  * Here we have a case of a directory that has completely disappeared from
1614  * the face of the earth on the tree we are mastering from.  Go through and
1615  * merge it into the tree, as well as everything beneath it.
1616  *
1617  * Note that if a directory has been moved for some reason, this will
1618  * incorrectly pick it up and attempt to merge it back into the old
1619  * location.  FIXME(eric).
1620  */
1621 LOCAL int
merge_old_directory_into_tree(dpnt,parent)1622 merge_old_directory_into_tree(dpnt, parent)
1623 	struct directory_entry	*dpnt;
1624 	struct directory *parent;
1625 {
1626 	struct directory_entry **contents = NULL;
1627 	int		i;
1628 	int		n_orig;
1629 	struct directory *this_dir,
1630 			*next_brother;
1631 	char		whole_path[PATH_MAX];
1632 
1633 	this_dir = (struct directory *)e_malloc(sizeof (struct directory));
1634 	memset(this_dir, 0, sizeof (struct directory));
1635 	this_dir->next = NULL;
1636 	this_dir->subdir = NULL;
1637 	this_dir->self = dpnt;
1638 	this_dir->contents = NULL;
1639 	this_dir->size = 0;
1640 	this_dir->extent = 0;
1641 	this_dir->depth = parent->depth + 1;
1642 	this_dir->parent = parent;
1643 	if (!parent->subdir)
1644 		parent->subdir = this_dir;
1645 	else {
1646 		next_brother = parent->subdir;
1647 		while (next_brother->next)
1648 			next_brother = next_brother->next;
1649 		next_brother->next = this_dir;
1650 	}
1651 
1652 	/* Set the name for this directory. */
1653 	if (strlcpy(whole_path, parent->de_name, sizeof (whole_path)) >= sizeof (whole_path) ||
1654 	    strlcat(whole_path, SPATH_SEPARATOR, sizeof (whole_path)) >= sizeof (whole_path) ||
1655 	    strlcat(whole_path, dpnt->name, sizeof (whole_path)) >= sizeof (whole_path))
1656 		comerrno(EX_BAD, _("Path name '%s%s%s' exceeds max length %zd\n"),
1657 					parent->de_name,
1658 					SPATH_SEPARATOR,
1659 					dpnt->name,
1660 					sizeof (whole_path));
1661 	this_dir->de_name = e_strdup(whole_path);
1662 	this_dir->whole_name = e_strdup(whole_path);
1663 
1664 	/*
1665 	 * Now fill this directory using information from the previous session.
1666 	 */
1667 	contents = read_merging_directory(&dpnt->isorec, &n_orig);
1668 	/*
1669 	 * Start by simply copying the '.', '..' and non-directory entries to
1670 	 * this directory.  Technically we could let merge_remaining_entries
1671 	 * handle this, but it gets rather confused by the '.' and '..' entries
1672 	 */
1673 	for (i = 0; i < n_orig; i++) {
1674 		/*
1675 		 * We can always reuse the TRANS.TBL in this particular case.
1676 		 */
1677 		contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1678 
1679 		if (((contents[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) &&
1680 							(i >= 2)) {
1681 			continue;
1682 		}
1683 		/* If we have a directory, don't reuse the extent number. */
1684 		if ((contents[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1685 			memset(contents[i]->isorec.extent, 0, 8);
1686 
1687 			if (strcmp(contents[i]->name, ".") == 0)
1688 				this_dir->dir_flags |= DIR_HAS_DOT;
1689 
1690 			if (strcmp(contents[i]->name, "..") == 0)
1691 				this_dir->dir_flags |= DIR_HAS_DOTDOT;
1692 		}
1693 		/*
1694 		 * for regilar files, we do it here.
1695 		 * If it has CL or RE attributes, remember its extent
1696 		 */
1697 		check_rr_relocation(contents[i]);
1698 
1699 		/*
1700 		 * Set the whole name for this file.
1701 		 */
1702 		if (strlcpy(whole_path, this_dir->whole_name, sizeof (whole_path)) >= sizeof (whole_path) ||
1703 		    strlcat(whole_path, SPATH_SEPARATOR, sizeof (whole_path)) >= sizeof (whole_path) ||
1704 		    strlcat(whole_path, contents[i]->name, sizeof (whole_path)) >= sizeof (whole_path))
1705 			comerrno(EX_BAD, _("Path name '%s%s%s' exceeds max length %zd\n"),
1706 						this_dir->whole_name,
1707 						SPATH_SEPARATOR,
1708 						contents[i]->name,
1709 						sizeof (whole_path));
1710 
1711 		contents[i]->whole_name = e_strdup(whole_path);
1712 
1713 		contents[i]->next = this_dir->contents;
1714 		contents[i]->filedir = this_dir;
1715 		this_dir->contents = contents[i];
1716 		contents[i] = NULL;
1717 	}
1718 
1719 	/*
1720 	 * and for directories, we do it here.
1721 	 * If it has CL or RE attributes, remember its extent
1722 	 */
1723 	check_rr_relocation(dpnt);
1724 
1725 	/*
1726 	 * Zero the extent number for ourselves.
1727 	 */
1728 	memset(dpnt->isorec.extent, 0, 8);
1729 
1730 	/*
1731 	 * Anything that is left are other subdirectories that need to be
1732 	 * merged.
1733 	 */
1734 	merge_remaining_entries(this_dir, contents, n_orig);
1735 	free_mdinfo(contents, n_orig);
1736 #if 0
1737 	/*
1738 	 * This is no longer required.  The post-scan sort will handle all of
1739 	 * this for us.
1740 	 */
1741 	sort_n_finish(this_dir);
1742 #endif
1743 
1744 	return (0);
1745 }
1746 
1747 
1748 char	*cdrecord_data = NULL;
1749 
1750 int
get_session_start(file_addr)1751 get_session_start(file_addr)
1752 	int		*file_addr;
1753 {
1754 	char		*pnt;
1755 
1756 #ifdef CDRECORD_DETERMINES_FIRST_WRITABLE_ADDRESS
1757 	/*
1758 	 * FIXME(eric).  We need to coordinate with cdrecord to obtain the
1759 	 * parameters.  For now, we assume we are writing the 2nd session, so
1760 	 * we start from the session that starts at 0.
1761 	 */
1762 	if (file_addr != NULL)
1763 		*file_addr = 16;
1764 
1765 	/*
1766 	 * We need to coordinate with cdrecord to get the next writable address
1767 	 * from the device.  Here is where we use it.
1768 	 */
1769 	session_start = last_extent = last_extent_written = cdrecord_result();
1770 #else
1771 
1772 	if (file_addr != NULL)
1773 		*file_addr = 0L;
1774 	session_start = last_extent = last_extent_written = 0L;
1775 	if (check_session && cdrecord_data == NULL)
1776 		return (0);
1777 
1778 	if (cdrecord_data == NULL) {
1779 		comerrno(EX_BAD,
1780 		    _("Special parameters for cdrecord not specified with -C\n"));
1781 	}
1782 	/*
1783 	 * Next try and find the ',' in there which delimits the two numbers.
1784 	 */
1785 	pnt = strchr(cdrecord_data, ',');
1786 	if (pnt == NULL) {
1787 		comerrno(EX_BAD, _("Malformed cdrecord parameters\n"));
1788 	}
1789 
1790 	*pnt = '\0';
1791 	if (file_addr != NULL) {
1792 		*file_addr = atol(cdrecord_data);
1793 	}
1794 	pnt++;
1795 
1796 	session_start = last_extent = last_extent_written = atol(pnt);
1797 
1798 	pnt--;
1799 	*pnt = ',';
1800 
1801 #endif
1802 	return (0);
1803 }
1804 
1805 /*
1806  * This function scans the directory tree, looking for files, and it makes
1807  * note of everything that is found.  We also begin to construct the ISO9660
1808  * directory entries, so that we can determine how large each directory is.
1809  */
1810 int
merge_previous_session(this_dir,mrootp,reloc_root,reloc_old_root)1811 merge_previous_session(this_dir, mrootp, reloc_root, reloc_old_root)
1812 	struct directory *this_dir;
1813 	struct iso_directory_record *mrootp;
1814 	char *reloc_root;
1815 	char *reloc_old_root;
1816 {
1817 	struct directory_entry **orig_contents = NULL;
1818 	struct directory_entry *odpnt = NULL;
1819 	int		n_orig;
1820 	struct directory_entry *s_entry;
1821 	int		status;
1822 	int		lstatus;
1823 	struct stat	statbuf,
1824 			lstatbuf;
1825 	int		retcode;
1826 
1827 	/* skip leading slash */
1828 	while (reloc_old_root && reloc_old_root[0] == PATH_SEPARATOR) {
1829 		reloc_old_root++;
1830 	}
1831 	while (reloc_root && reloc_root[0] == PATH_SEPARATOR) {
1832 		reloc_root++;
1833 	}
1834 
1835 	/*
1836 	 * Parse the same directory in the image that we are merging for
1837 	 * multisession stuff.
1838 	 */
1839 	orig_contents = read_merging_directory(mrootp, &n_orig);
1840 	if (orig_contents == NULL) {
1841 		if (reloc_old_root) {
1842 			comerrno(EX_BAD,
1843 			_("Reading old session failed, cannot execute -old-root.\n"));
1844 		}
1845 		return (0);
1846 	}
1847 
1848 	if (reloc_old_root && reloc_old_root[0]) {
1849 		struct directory_entry	**new_orig_contents = orig_contents;
1850 		int			new_n_orig = n_orig;
1851 
1852 		/* decend until we reach the original root */
1853 		while (reloc_old_root[0]) {
1854 			int	i;
1855 			char	*next;
1856 			int	last;
1857 
1858 			for (next = reloc_old_root; *next && *next != PATH_SEPARATOR; next++);
1859 			if (*next) {
1860 				last = 0;
1861 				*next = 0;
1862 				next++;
1863 			} else {
1864 				last = 1;
1865 			}
1866 			while (*next == PATH_SEPARATOR) {
1867 				next++;
1868 			}
1869 
1870 			for (i = 0; i < new_n_orig; i++) {
1871 				struct iso_directory_record subroot;
1872 
1873 				if (new_orig_contents[i]->name != NULL &&
1874 				    strcmp(new_orig_contents[i]->name, reloc_old_root) != 0) {
1875 					/* Not the same name continue */
1876 					continue;
1877 				}
1878 				/*
1879 				 * enter directory, free old one only if not the top level,
1880 				 * which is still needed
1881 				 */
1882 				subroot = new_orig_contents[i]->isorec;
1883 				if (new_orig_contents != orig_contents) {
1884 					free_mdinfo(new_orig_contents, new_n_orig);
1885 				}
1886 				new_orig_contents = read_merging_directory(&subroot, &new_n_orig);
1887 
1888 				if (!new_orig_contents) {
1889 					comerrno(EX_BAD,
1890 					_("Reading directory %s in old session failed, cannot execute -old-root.\n"),
1891 							reloc_old_root);
1892 				}
1893 				i = -1;
1894 				break;
1895 			}
1896 
1897 			if (i == new_n_orig) {
1898 				comerrno(EX_BAD,
1899 				_("-old-root (sub)directory %s not found in old session.\n"),
1900 						reloc_old_root);
1901 			}
1902 
1903 			/* restore string, proceed to next sub directory */
1904 			if (!last) {
1905 				reloc_old_root[strlen(reloc_old_root)] = PATH_SEPARATOR;
1906 			}
1907 			reloc_old_root = next;
1908 		}
1909 
1910 		/*
1911 		 * preserve the old session, skipping those dirs/files that are found again
1912 		 * in the new root
1913 		 */
1914 		for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1915 			status = stat_filter(s_entry->whole_name, &statbuf);
1916 			lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
1917 
1918 			/*
1919 			 * check_prev_session() will search for s_entry and remove it from
1920 			 * orig_contents if found
1921 			 */
1922 			retcode = check_prev_session(orig_contents, n_orig, s_entry,
1923 			    &statbuf, &lstatbuf, NULL);
1924 			if (retcode == -1)
1925 				return (-1);
1926 			/*
1927 			 * Skip other directory entries for multi-extent files
1928 			 */
1929 			if (s_entry->de_flags & MULTI_EXTENT) {
1930 				struct directory_entry	*s_e;
1931 
1932 				for (s_e = s_entry->mxroot;
1933 					s_e && s_e->mxroot == s_entry->mxroot;
1934 						s_e = s_e->next) {
1935 					s_entry = s_e;
1936 					;
1937 				}
1938 			}
1939 		}
1940 		merge_remaining_entries(this_dir, orig_contents, n_orig);
1941 
1942 		/* use new directory */
1943 		free_mdinfo(orig_contents, n_orig);
1944 		orig_contents = new_orig_contents;
1945 		n_orig = new_n_orig;
1946 
1947 		if (reloc_root && reloc_root[0]) {
1948 			/* also decend into new root before searching for files */
1949 			this_dir = find_or_create_directory(this_dir, reloc_root, NULL, TRUE);
1950 			if (!this_dir) {
1951 				return (-1);
1952 			}
1953 		}
1954 	}
1955 
1956 
1957 	/*
1958 	 * Now we scan the directory itself, and look at what is inside of it.
1959 	 */
1960 	for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1961 		status = stat_filter(s_entry->whole_name, &statbuf);
1962 		lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
1963 
1964 		/*
1965 		 * We always should create an entirely new directory tree
1966 		 * whenever we generate a new session, unless there were
1967 		 * *no* changes whatsoever to any of the directories, in which
1968 		 * case it would be kind of pointless to generate a new
1969 		 * session.
1970 		 * I believe it is possible to rigorously prove that any change
1971 		 * anywhere in the filesystem will force the entire tree to be
1972 		 * regenerated because the modified directory will get a new
1973 		 * extent number.  Since each subdirectory of the changed
1974 		 * directory has a '..' entry, all of them will need to be
1975 		 * rewritten too, and since the parent directory of the
1976 		 * modified directory will have an extent pointer to the
1977 		 * directory it too will need to be rewritten.  Thus we will
1978 		 * never be able to reuse any directory information when
1979 		 * writing new sessions.
1980 		 *
1981 		 * We still check the previous session so we can mark off the
1982 		 * equivalent entry in the list we got from the original disc,
1983 		 * however.
1984 		 */
1985 
1986 		/*
1987 		 * The check_prev_session function looks for an identical
1988 		 * entry in the previous session.  If we see it, then we copy
1989 		 * the extent number to s_entry, and cross it off the list.
1990 		 */
1991 		retcode = check_prev_session(orig_contents, n_orig, s_entry,
1992 			&statbuf, &lstatbuf, &odpnt);
1993 		if (retcode == -1)
1994 			return (-1);
1995 
1996 		if (odpnt != NULL &&
1997 		    (s_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1998 			int	dflag;
1999 
2000 			if (strcmp(s_entry->name, ".") != 0 &&
2001 					strcmp(s_entry->name, "..") != 0) {
2002 				struct directory *child;
2003 
2004 				/*
2005 				 * XXX It seems that the tree that has been
2006 				 * XXX read from the previous session does not
2007 				 * XXX carry whole_name entries. We provide a
2008 				 * XXX hack in
2009 				 * XXX multi.c:find_or_create_directory()
2010 				 * XXX that should be removed when a
2011 				 * XXX reasonable method could be found.
2012 				 */
2013 				child = find_or_create_directory(this_dir,
2014 					s_entry->whole_name,
2015 					s_entry, 1);
2016 				dflag = merge_previous_session(child,
2017 					&odpnt->isorec,
2018 					NULL, reloc_old_root);
2019 				if (dflag == -1) {
2020 					return (-1);
2021 				}
2022 				free(odpnt);
2023 				odpnt = NULL;
2024 			}
2025 		}
2026 		if (odpnt) {
2027 			free(odpnt);
2028 			odpnt = NULL;
2029 		}
2030 		/*
2031 		 * Skip other directory entries for multi-extent files
2032 		 */
2033 		if (s_entry->de_flags & MULTI_EXTENT) {
2034 			struct directory_entry	*s_e;
2035 
2036 			for (s_e = s_entry->mxroot;
2037 				s_e && s_e->mxroot == s_entry->mxroot;
2038 					s_e = s_e->next) {
2039 				s_entry = s_e;
2040 				;
2041 			}
2042 		}
2043 	}
2044 
2045 	if (!reloc_old_root) {
2046 		/*
2047 		 * Whatever is left over, are things which are no longer in the tree on
2048 		 * disk. We need to also merge these into the tree.
2049 		 */
2050 		merge_remaining_entries(this_dir, orig_contents, n_orig);
2051 	}
2052 	free_mdinfo(orig_contents, n_orig);
2053 	return (1);
2054 }
2055 
2056 /*
2057  * This code deals with relocated directories which may exist
2058  * in the previous session.
2059  */
2060 struct dir_extent_link  {
2061 	unsigned int		extent;
2062 	struct directory_entry	*de;
2063 	struct dir_extent_link	*next;
2064 };
2065 
2066 static struct dir_extent_link	*cl_dirs = NULL;
2067 static struct dir_extent_link	*re_dirs = NULL;
2068 
2069 LOCAL void
check_rr_relocation(de)2070 check_rr_relocation(de)
2071 	struct directory_entry *de;
2072 {
2073 	unsigned char	sector[SECTOR_SIZE];
2074 	unsigned char	*pnt = de->rr_attributes;
2075 		int	len = de->rr_attr_size;
2076 		UInt32_t cont_extent = 0,
2077 			cont_offset = 0,
2078 			cont_size = 0;
2079 
2080 	pnt = parse_xa(pnt, &len, /* dpnt */ 0);
2081 	while (len >= 4) {
2082 		if (pnt[3] != 1 && pnt[3] != 2) {
2083 			errmsgno(EX_BAD,
2084 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
2085 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
2086 		}
2087 		if (pnt[2] < 4) {
2088 			errmsgno(EX_BAD,
2089 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
2090 				pnt[2], pnt, pnt[0], pnt[1]);
2091 			break;
2092 		}
2093 		if (strncmp((char *)pnt, "CL", 2) == 0) {
2094 			struct dir_extent_link *dlink = e_malloc(sizeof (*dlink));
2095 
2096 			dlink->extent = get_733(pnt + 4);
2097 			dlink->de = de;
2098 			dlink->next = cl_dirs;
2099 			cl_dirs = dlink;
2100 
2101 		} else if (strncmp((char *)pnt, "RE", 2) == 0) {
2102 			struct dir_extent_link *dlink = e_malloc(sizeof (*dlink));
2103 
2104 			dlink->extent = de->starting_block;
2105 			dlink->de = de;
2106 			dlink->next = re_dirs;
2107 			re_dirs = dlink;
2108 
2109 		} else if (strncmp((char *)pnt, "CE", 2) == 0) {
2110 			cont_extent = get_733(pnt + 4);
2111 			cont_offset = get_733(pnt + 12);
2112 			cont_size = get_733(pnt + 20);
2113 
2114 		} else if (strncmp((char *)pnt, "ST", 2) == 0) {
2115 			len = pnt[2];
2116 		}
2117 		len -= pnt[2];
2118 		pnt += pnt[2];
2119 		if (len <= 3 && cont_extent) {
2120 			/* ??? What if cont_offset+cont_size > SECTOR_SIZE */
2121 			readsecs(cont_extent, sector, 1);
2122 			pnt = sector + cont_offset;
2123 			len = cont_size;
2124 			cont_extent = cont_offset = cont_size = 0;
2125 		}
2126 	}
2127 
2128 }
2129 
2130 void
match_cl_re_entries()2131 match_cl_re_entries()
2132 {
2133 	struct dir_extent_link *re = re_dirs;
2134 
2135 	/* for each relocated directory */
2136 	for (; re; re = re->next) {
2137 		struct dir_extent_link *cl = cl_dirs;
2138 
2139 		for (; cl; cl = cl->next) {
2140 			/* find a place where it was relocated from */
2141 			if (cl->extent == re->extent) {
2142 				/* set link to that place */
2143 				re->de->parent_rec = cl->de;
2144 				re->de->filedir = cl->de->filedir;
2145 
2146 				/*
2147 				 * see if it is in rr_moved
2148 				 */
2149 				if (reloc_dir != NULL) {
2150 					struct directory_entry *rr_moved_e = reloc_dir->contents;
2151 
2152 					for (; rr_moved_e; rr_moved_e = rr_moved_e->next) {
2153 						/* yes it is */
2154 						if (re->de == rr_moved_e) {
2155 							/* forget it */
2156 							re->de = NULL;
2157 						}
2158 					}
2159 				}
2160 				break;
2161 			}
2162 		}
2163 	}
2164 }
2165 
2166 void
finish_cl_pl_for_prev_session()2167 finish_cl_pl_for_prev_session()
2168 {
2169 	struct dir_extent_link *re = re_dirs;
2170 
2171 	/* for those that were relocated, but NOT to rr_moved */
2172 	re = re_dirs;
2173 	for (; re; re = re->next) {
2174 		if (re->de != NULL) {
2175 			/*
2176 			 * here we have hypothetical case when previous session
2177 			 * was not created by mkisofs and contains relocations
2178 			 */
2179 			struct directory_entry *s_entry = re->de;
2180 			struct directory_entry *s_entry1;
2181 			struct directory *d_entry = reloc_dir->subdir;
2182 
2183 			/* do the same as finish_cl_pl_entries */
2184 			if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
2185 				continue;
2186 			}
2187 			while (d_entry) {
2188 				if (d_entry->self == s_entry)
2189 					break;
2190 				d_entry = d_entry->next;
2191 			}
2192 			if (!d_entry) {
2193 				comerrno(EX_BAD, _("Unable to locate directory parent\n"));
2194 			}
2195 
2196 			if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
2197 				char	*rr_attr;
2198 
2199 				/*
2200 				 * First fix the PL pointer in the directory in the
2201 				 * rr_reloc dir
2202 				 */
2203 				s_entry1 = d_entry->contents->next;
2204 				rr_attr = find_rr_attribute(s_entry1->rr_attributes,
2205 					s_entry1->total_rr_attr_size, "PL");
2206 				if (rr_attr != NULL)
2207 					set_733(rr_attr + 4, s_entry->filedir->extent);
2208 
2209 				/* Now fix the CL pointer */
2210 				s_entry1 = s_entry->parent_rec;
2211 
2212 				rr_attr = find_rr_attribute(s_entry1->rr_attributes,
2213 					s_entry1->total_rr_attr_size, "CL");
2214 				if (rr_attr != NULL)
2215 					set_733(rr_attr + 4, d_entry->extent);
2216 			}
2217 		}
2218 	}
2219 	/* free memory */
2220 	re = re_dirs;
2221 	while (re) {
2222 		struct dir_extent_link *next = re->next;
2223 
2224 		free(re);
2225 		re = next;
2226 	}
2227 	re = cl_dirs;
2228 	while (re) {
2229 		struct dir_extent_link *next = re->next;
2230 
2231 		free(re);
2232 		re = next;
2233 	}
2234 }
2235