1 /* @(#)write.c	1.146 16/12/13 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)write.c	1.146 16/12/13 joerg";
6 #endif
7 /*
8  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
9  *
10  * Written by Eric Youngdale (1993).
11  *
12  * Copyright 1993 Yggdrasil Computing, Incorporated
13  * Copyright (c) 1999-2016 J. Schilling
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2, or (at your option)
18  * any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28  */
29 
30 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
31 
32 /* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
33 
34 #include "mkisofs.h"
35 #include <schily/time.h>
36 #include <schily/fcntl.h>
37 #ifdef SORTING
38 #include "match.h"
39 #endif /* SORTING */
40 #include <schily/errno.h>
41 #include <schily/schily.h>
42 #include <schily/checkerr.h>
43 #ifdef DVD_AUD_VID
44 #include "dvd_reader.h"
45 #include "dvd_file.h"
46 #include "ifo_read.h"
47 #endif
48 #ifdef APPLE_HYB
49 #include <schily/ctype.h>
50 #endif
51 
52 #ifdef	VMS
53 #include "vms.h"
54 #endif
55 
56 #define	SIZEOF_UDF_EXT_ATTRIBUTE_COMMON	50
57 
58 /* Max number of sectors we will write at  one time */
59 #define	NSECT	32
60 
61 #define	INSERTMACRESFORK 1
62 
63 /* Counters for statistics */
64 
65 LOCAL int	table_size = 0;
66 LOCAL int	total_dir_size = 0;
67 LOCAL int	rockridge_size = 0;
68 LOCAL struct directory **pathlist;
69 LOCAL int	next_path_index = 1;
70 LOCAL int	sort_goof;
71 
72 LOCAL int	is_rr_dir = 0;
73 
74 struct output_fragment *out_tail;
75 struct output_fragment *out_list;
76 
77 EXPORT	struct iso_primary_descriptor	vol_desc;
78 LOCAL	int				vol_desc_sum;
79 
80 #ifndef	APPLE_HFS_HYB
81 	char	*hfs_error = __("no error");
82 #endif
83 
84 LOCAL	int	xawrite		__PR((void *buffer, int size, int count,
85 					FILE *file, int submode, BOOL islast));
86 EXPORT	void	xfwrite		__PR((void *buffer, int size, int count,
87 					FILE *file, int submode, BOOL islast));
88 LOCAL 	int	assign_directory_addresses __PR((struct directory *node));
89 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
90 LOCAL 	void	write_one_file	__PR((char *filename, off_t size,
91 					FILE *outfile, off_t off,
92 					int isrfile, unsigned rba));
93 #else
94 LOCAL 	void	write_one_file	__PR((char *filename, off_t size,
95 					FILE *outfile));
96 #endif
97 #ifdef UDF
98 LOCAL	void	write_udf_symlink	__PR((char *filename, off_t size,
99 					FILE *outfile));
100 #endif
101 LOCAL 	void	write_files	__PR((FILE *outfile));
102 #if 0
103 LOCAL 	void	dump_filelist	__PR((void));
104 #endif
105 LOCAL 	int	compare_dirs	__PR((const void *rr, const void *ll));
106 EXPORT	int	sort_directory	__PR((struct directory_entry **sort_dir,
107 						int rr));
108 LOCAL 	int	root_gen	__PR((void));
109 LOCAL 	BOOL	assign_file_addresses __PR((struct directory *dpnt, BOOL isnest));
110 LOCAL 	void	free_one_directory  __PR((struct directory *dpnt));
111 LOCAL 	void	free_directories __PR((struct directory *dpnt));
112 EXPORT	void	generate_one_directory __PR((struct directory *dpnt,
113 						FILE *outfile));
114 LOCAL 	void	build_pathlist	__PR((struct directory *node));
115 LOCAL 	int	compare_paths	__PR((void const *r, void const *l));
116 LOCAL 	int	generate_path_tables __PR((void));
117 EXPORT	void	memcpy_max	__PR((char *to, char *from, int max));
118 EXPORT	void	outputlist_insert __PR((struct output_fragment *frag));
119 LOCAL 	int	file_write	__PR((FILE *outfile));
120 LOCAL 	int	pvd_write	__PR((FILE *outfile));
121 LOCAL 	int	xpvd_write	__PR((FILE *outfile));
122 LOCAL 	int	evd_write	__PR((FILE *outfile));
123 LOCAL 	int	vers_write	__PR((FILE *outfile));
124 LOCAL 	int	graftcp		__PR((char *to, char *from, char *ep));
125 LOCAL 	int	pathcp		__PR((char *to, char *from, char *ep));
126 LOCAL 	int	pathtab_write	__PR((FILE *outfile));
127 LOCAL 	int	exten_write	__PR((FILE *outfile));
128 EXPORT	int	oneblock_size	__PR((UInt32_t starting_extent));
129 LOCAL 	int	pathtab_size	__PR((UInt32_t starting_extent));
130 LOCAL 	int	startpad_size	__PR((UInt32_t starting_extent));
131 LOCAL 	int	interpad_size	__PR((UInt32_t starting_extent));
132 LOCAL 	int	endpad_size	__PR((UInt32_t starting_extent));
133 LOCAL 	int	file_gen	__PR((void));
134 LOCAL 	int	dirtree_dump	__PR((void));
135 LOCAL 	int	dirtree_fixup	__PR((UInt32_t starting_extent));
136 LOCAL 	int	dirtree_size	__PR((UInt32_t starting_extent));
137 LOCAL 	int	ext_size	__PR((UInt32_t starting_extent));
138 LOCAL 	int	dirtree_write	__PR((FILE *outfile));
139 LOCAL 	int	dirtree_cleanup	__PR((FILE *outfile));
140 LOCAL 	int	startpad_write	__PR((FILE *outfile));
141 LOCAL 	int	interpad_write	__PR((FILE *outfile));
142 LOCAL 	int	endpad_write	__PR((FILE *outfile));
143 #ifdef APPLE_HYB
144 LOCAL 	int	hfs_pad;
145 LOCAL 	int	hfs_get_parms	__PR((char *key));
146 LOCAL 	void	hfs_file_gen	__PR((UInt32_t start_extent));
147 LOCAL 	void	gen_prepboot	__PR((void));
148 EXPORT	Ulong	get_adj_size	__PR((int Csize));
149 EXPORT	int	adj_size	__PR((int Csize, UInt32_t start_extent, int extra));
150 EXPORT	void	adj_size_other	__PR((struct directory *dpnt));
151 LOCAL 	int	hfs_hce_write	__PR((FILE *outfile));
152 EXPORT	int	insert_padding_file __PR((int size));
153 #endif	/* APPLE_HYB */
154 
155 #ifdef SORTING
156 LOCAL 	int	compare_sort	__PR((const void *rr, const void *ll));
157 LOCAL 	void	reassign_link_addresses	__PR((struct directory *dpnt));
158 LOCAL 	int	sort_file_addresses __PR((void));
159 #endif /* SORTING */
160 
161 /*
162  * Routines to actually write the disc.  We write sequentially so that
163  * we could write a tape, or write the disc directly
164  */
165 #define	FILL_SPACE(X)	memset(vol_desc.X, ' ', sizeof (vol_desc.X))
166 
167 EXPORT void
xfwrite(buffer,size,count,file,submode,islast)168 xfwrite(buffer, size, count, file, submode, islast)
169 	void	*buffer;
170 	int	size;
171 	int	count;
172 	FILE	*file;
173 	int	submode;
174 	BOOL	islast;
175 {
176 	/*
177 	 * This is a hack that could be made better.
178 	 * XXXIs this the only place?
179 	 * It is definitely needed on Operating Systems that do not allow to
180 	 * write files that are > 2GB. If the system is fast enough to be able
181 	 * to feed 1400 KB/s writing speed of a DVD-R drive, use stdout.
182 	 * If the system cannot do this reliable, you need to use this hacky
183 	 * option.
184 	 */
185 	static int	idx = 0;
186 
187 #ifdef	XFWRITE_DEBUG
188 	if (count != 1 || (size % 2048) != 0)
189 		error(_("Count: %d, size: %d\n"), count, size);
190 #endif
191 	if (count == 0 || size == 0) {
192 		errmsgno(EX_BAD,
193 		_("Implementation botch, write 0 bytes (size %d count %d).\n"),
194 		size, count);
195 		abort();
196 	}
197 
198 	if (split_output != 0 &&
199 		(idx == 0 || ftell(file) >= ((off_t)1024 * 1024 * 1024))) {
200 		char		nbuf[512];
201 		extern char	*outfile;
202 
203 		if (idx == 0)
204 			unlink(outfile);
205 		sprintf(nbuf, "%s_%02d", outfile, idx++);
206 		file = freopen(nbuf, "wb", file);
207 		if (file == NULL) {
208 			comerr(_("Cannot open '%s'.\n"), nbuf);
209 		}
210 	}
211 	while (count) {
212 		int	got;
213 
214 		seterrno(0);
215 		if (osecsize != 0)
216 			got = xawrite(buffer, size, count, file, submode, islast);
217 		else
218 			got = fwrite(buffer, size, count, file);
219 
220 		if (got <= 0) {
221 			comerr(_("cannot fwrite %d*%d\n"), size, count);
222 		}
223 		/*
224 		 * This comment is in hope to prevent silly people from
225 		 * e.g. SuSE (who did not yet learn C but believe that
226 		 * they need to patch other peoples code) from changing the
227 		 * next cast into an illegal lhs cast expression.
228 		 * The cast below is the correct way to handle the problem.
229 		 * The (void *) cast is to avoid a GCC warning like:
230 		 * "warning: dereferencing type-punned pointer will break \
231 		 * strict-aliasing rules"
232 		 * which is wrong this code. (void *) introduces a compatible
233 		 * intermediate type in the cast list.
234 		 */
235 		count -= got, *(char **)(void *)&buffer += size * got;
236 	}
237 }
238 
239 LOCAL int
xawrite(buffer,size,count,file,submode,islast)240 xawrite(buffer, size, count, file, submode, islast)
241 	void	*buffer;
242 	int	size;
243 	int	count;
244 	FILE	*file;
245 	int	submode;
246 	BOOL	islast;
247 {
248 	register char	*p = buffer;
249 	register int	amt = size * count;
250 	register int	n;
251 	struct xa_subhdr subhdr[2];
252 
253 	if (osecsize == 2048)
254 		return (fwrite(buffer, size, count, file));
255 
256 	if (amt % 2048)
257 		comerrno(EX_BAD,
258 			_("Trying to write %d bytes (not a multiple of 2048).\n"),
259 			amt);
260 
261 	subhdr[0].file_number		= subhdr[1].file_number		= 0;
262 	subhdr[0].channel_number	= subhdr[1].channel_number	= 0;
263 	subhdr[0].coding		= subhdr[1].coding		= 0;
264 
265 	while (amt > 0) {
266 #ifdef	LATER
267 		if (submode < 0)
268 			subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
269 		else
270 			subhdr[0].sub_mode = subhdr[1].sub_mode = submode;
271 #else
272 		subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
273 #endif
274 
275 		if ((amt <= 2048) && islast) {
276 			subhdr[0].sub_mode = subhdr[1].sub_mode
277 						|= (XA_SUBH_EOR|XA_SUBH_EOF);
278 		}
279 		n = fwrite(subhdr, sizeof (subhdr), 1, file);
280 		if (n <= 0)
281 			return (n);
282 
283 		n = fwrite(p, 2048, 1, file);
284 		if (n <= 0)
285 			return (n);
286 
287 		p += 2048;
288 		amt -= 2048;
289 	}
290 	return (1);
291 }
292 
293 #ifdef APPLE_HYB
294 /*
295  * use the deferred_write struct to store info about the hfs_boot_file
296  */
297 LOCAL struct deferred_write mac_boot;
298 
299 #endif	/* APPLE_HYB */
300 LOCAL struct deferred_write	*dw_head = NULL,
301 				*dw_tail = NULL;
302 
303 UInt32_t	last_extent_written = 0;
304 LOCAL	Uint	path_table_index;
305 EXPORT	time_t	begun;
306 EXPORT	struct timeval tv_begun;
307 
308 /*
309  * We recursively walk through all of the directories and assign extent
310  * numbers to them.  We have already assigned extent numbers to everything that
311  * goes in front of them
312  */
313 LOCAL int
assign_directory_addresses(node)314 assign_directory_addresses(node)
315 	struct directory	*node;
316 {
317 	int		dir_size;
318 	struct directory *dpnt;
319 
320 	dpnt = node;
321 
322 	while (dpnt) {
323 		/* skip if it's hidden */
324 		if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
325 			dpnt = dpnt->next;
326 			continue;
327 		}
328 		/*
329 		 * If we already have an extent for this (i.e. it came from a
330 		 * multisession disc), then don't reassign a new extent.
331 		 */
332 		dpnt->path_index = next_path_index++;
333 		if (dpnt->extent == 0) {
334 			dpnt->extent = last_extent;
335 			dir_size = ISO_BLOCKS(dpnt->size);
336 
337 			last_extent += dir_size;
338 
339 			/*
340 			 * Leave room for the CE entries for this directory.
341 			 * Keep them close to the reference directory so that
342 			 * access will be quick.
343 			 */
344 			if (dpnt->ce_bytes) {
345 				last_extent += ISO_BLOCKS(dpnt->ce_bytes);
346 			}
347 		}
348 		if (dpnt->subdir) {
349 			assign_directory_addresses(dpnt->subdir);
350 		}
351 		dpnt = dpnt->next;
352 	}
353 	return (0);
354 }
355 
356 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
357 LOCAL void
write_one_file(filename,size,outfile,off,isrfile,rba)358 write_one_file(filename, size, outfile, off, isrfile, rba)
359 	char		*filename;
360 	off_t		size;
361 	FILE		*outfile;
362 	off_t		off;
363 	int		isrfile;
364 	unsigned	rba;
365 #else
366 LOCAL void
367 write_one_file(filename, size, outfile)
368 	char		*filename;
369 	off_t		size;
370 	FILE		*outfile;
371 #endif	/* APPLE_HYB || USE_LARGEFILES */
372 {
373 	/*
374 	 * It seems that there are still stone age C-compilers
375 	 * around.
376 	 * The Metrowerks C found on BeOS/PPC does not allow
377 	 * more than 32kB of local vars.
378 	 * As we do not need to call write_one_file() recursively
379 	 * we make buffer static.
380 	 */
381 #ifdef	__BEOS__
382 static	char		buffer[SECTOR_SIZE * NSECT];
383 #else
384 	char		buffer[SECTOR_SIZE * NSECT];
385 #endif
386 	FILE		*infile;
387 	off_t		remain;
388 	int	use;
389 	int	unroundeduse;
390 	int	bytestowrite = 0;	/* Dummy init. to serve GCC bug */
391 	int	correctedsize = 0;
392 
393 
394 	if ((infile = fopen(filename, "rb")) == NULL) {
395 		if (!errhidden(E_OPEN, filename)) {
396 			if (!errwarnonly(E_OPEN, filename))
397 				;
398 			errmsg(_("Cannot open '%s'.\n"), filename);
399 			(void) errabort(E_OPEN, filename, TRUE);
400 		}
401 	}
402 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
403 	if (infile)
404 		fseek(infile, off, SEEK_SET);
405 #if defined(INSERTMACRESFORK) && defined(UDF)
406 	if (isrfile && use_udf) {
407 		memset(buffer, 0, sizeof (buffer));
408 		udf_set_extattr_freespace((Uchar *)buffer, size, rba);
409 		xfwrite(buffer, SECTOR_SIZE, 1, outfile, XA_SUBH_DATA, 1);
410 		last_extent_written++;
411 
412 		memset(buffer, 0, sizeof (buffer));
413 		udf_set_extattr_macresfork((Uchar *)buffer, size, rba);
414 		xfwrite(buffer, SIZEOF_UDF_EXT_ATTRIBUTE_COMMON, 1, outfile, XA_SUBH_DATA, 1);
415 		correctedsize = SIZEOF_UDF_EXT_ATTRIBUTE_COMMON;
416 	}
417 #endif
418 #endif	/* APPLE_HYB || USE_LARGEFILES */
419 	remain = size;
420 
421 	while (remain > 0) {
422 		int	amt;
423 
424 		unroundeduse = use = (remain > SECTOR_SIZE * NSECT - 1 ?
425 				NSECT * SECTOR_SIZE : remain);
426 		use = ISO_ROUND_UP(use);	/* Round up to nearest sector */
427 						/* boundary */
428 		memset(buffer, 0, use);
429 		seterrno(0);
430 		if (infile) {
431 #ifdef VMS
432 			amt = fread(buffer, 1, use, infile);
433 #else
434 			amt = ffileread(infile, buffer, use);
435 #endif
436 		} else {
437 			amt = use;
438 		}
439 		if (amt < use && amt != remain) {
440 			/*
441 			 * Note that mkisofs is not star and no 100% archiver.
442 			 * We only detect file growth if the new size does not
443 			 * match 'use' at the last read.
444 			 */
445 			if (geterrno() == 0) {
446 				if (!errhidden(amt > remain ? E_GROW:E_SHRINK, filename)) {
447 					if (!errwarnonly(amt < remain ? E_SHRINK:E_GROW, filename)) {
448 						errmsgno(EX_BAD,
449 						_("Try to use the option -data-change-warn\n"));
450 						errmsgno(EX_BAD,
451 						_("Files should not change while mkisofs is running.\n"));
452 					}
453 					errmsgno(EX_BAD,
454 					_("File '%s' did %s.\n"),
455 						filename,
456 						amt < remain ?
457 						_("shrink"):_("grow"));
458 					(void) errabort(amt < remain ?
459 							E_SHRINK:E_GROW,
460 							filename, TRUE);
461 				}
462 			} else if (!errhidden(E_READ, filename)) {
463 				if (!errwarnonly(E_READ, filename))
464 					;
465 				errmsg(_("Cannot read from '%s'\n"), filename);
466 				(void) errabort(E_READ, filename, TRUE);
467 			}
468 			amt = remain;		/* Fake success */
469 			if (infile) {
470 				fclose(infile);	/* Prevent furthe failure */
471 				infile = NULL;
472 			}
473 		}
474 #if defined(APPLE_HYB) && defined(INSERTMACRESFORK) && defined(UDF)
475 		if (unroundeduse == remain && isrfile && use_udf && correctedsize) {
476 			/* adjust the last block to write according to correctedsize */
477 			if (use - unroundeduse == correctedsize) {
478 				bytestowrite = use;
479 				correctedsize = 0;
480 			} else if (use - unroundeduse > correctedsize) {
481 				bytestowrite = use - correctedsize;
482 				correctedsize = 0;
483 			} else if (use - unroundeduse < correctedsize) {
484 				bytestowrite = unroundeduse;
485 				correctedsize -= use - unroundeduse;
486 			}
487 		} else {
488 			bytestowrite = use;
489 		}
490 #else
491 		bytestowrite = use;
492 #endif
493 
494 		xfwrite(buffer, bytestowrite, 1, outfile,
495 				XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
496 		last_extent_written += use / SECTOR_SIZE;
497 #if 0
498 		if ((last_extent_written % 1000) < use / SECTOR_SIZE) {
499 			fprintf(stderr, "%d..", last_extent_written);
500 		}
501 #else
502 		if (verbose > 0 &&
503 		    (int)(last_extent_written % (gui ? 500 : 5000)) <
504 							use / SECTOR_SIZE) {
505 			time_t	now;
506 			time_t	the_end;
507 			double	frac;
508 
509 			time(&now);
510 			frac = last_extent_written / (1.0 * last_extent);
511 			the_end = begun + (now - begun) / frac;
512 #ifndef NO_FLOATINGPOINT
513 			fprintf(stderr, _("%6.2f%% done, estimate finish %s"),
514 				frac * 100., ctime(&the_end));
515 #else
516 			fprintf(stderr, _("%3d.%-02d%% done, estimate finish %s"),
517 				(int)(frac * 100.),
518 				(int)((frac+.00005) * 10000.)%100,
519 				ctime(&the_end));
520 #endif
521 			fflush(stderr);
522 		}
523 #endif
524 		remain -= use;
525 	}
526 #ifdef APPLE_HYB
527 #if defined(INSERTMACRESFORK) && defined(UDF)
528 	if (isrfile && use_udf && correctedsize) {
529 		if (ISO_ROUND_UP(size) < ISO_ROUND_UP(size + SIZEOF_UDF_EXT_ATTRIBUTE_COMMON)) {
530 			memset(buffer, 0, sizeof (buffer));
531 			xfwrite(buffer, SECTOR_SIZE - correctedsize, 1, outfile, XA_SUBH_DATA, 1);
532 			last_extent_written++;
533 		}
534 	}
535 #endif
536 #endif
537 	if (infile)
538 		fclose(infile);
539 } /* write_one_file(... */
540 
541 #ifdef UDF
542 LOCAL void
write_udf_symlink(filename,size,outfile)543 write_udf_symlink(filename, size, outfile)
544 	char		*filename;
545 	off_t		size;
546 	FILE		*outfile;
547 {
548 	static	char	buffer[SECTOR_SIZE * NSECT];
549 	off_t		remain = sizeof (buffer);
550 	int		use;
551 
552 	if (udf_get_symlinkcontents(filename, buffer, &remain) < 0) {
553 		comerr(_("Cannot open smylink '%s'\n"), filename);
554 	}
555 	if (remain != size) {
556 		comerrno(EX_BAD, _("Symlink '%s' did %s.\n"),
557 					filename,
558 					size > remain ?
559 					_("shrink"):_("grow"));
560 	}
561 	use = (remain > SECTOR_SIZE * NSECT - 1 ?
562 			NSECT * SECTOR_SIZE : remain);
563 	use = ISO_ROUND_UP(use);
564 	xfwrite(buffer, use, 1, outfile,
565 			XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
566 	last_extent_written += use / SECTOR_SIZE;
567 
568 } /* write_udf_symlink(... */
569 #endif
570 
571 LOCAL void
write_files(outfile)572 write_files(outfile)
573 	FILE	*outfile;
574 {
575 	struct deferred_write	*dwpnt,
576 				*dwnext;
577 	unsigned		rba = 0;
578 
579 	dwpnt = dw_head;
580 	while (dwpnt) {
581 /*#define DEBUG*/
582 #ifdef DEBUG
583 		fprintf(stderr,
584 		_("The file name is %s and pad is %d, size is %lld and extent is %d\n"),
585 				dwpnt->name, dwpnt->pad,
586 				(Llong)dwpnt->size, dwpnt->extent);
587 #endif
588 		if (dwpnt->table) {
589 			xfwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
590 							outfile,
591 							XA_SUBH_DATA, TRUE);
592 			last_extent_written += ISO_BLOCKS(dwpnt->size);
593 			table_size += dwpnt->size;
594 /*			fprintf(stderr, _("Size %lld "), (Llong)dwpnt->size); */
595 			free(dwpnt->table);
596 			dwpnt->table = NULL;
597 		} else {
598 
599 #ifdef VMS
600 			vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
601 #else
602 #ifdef UDF
603 			if ((dwpnt->dw_flags & IS_SYMLINK) && use_udf && create_udfsymlinks) {
604 				write_udf_symlink(dwpnt->name, dwpnt->size, outfile);
605 			} else {
606 #endif	/* UDF */
607 #ifdef APPLE_HYB
608 #if defined(INSERTMACRESFORK) && defined(UDF)
609 				if (file_is_resource(dwpnt->name, dwpnt->hfstype) && (dwpnt->size > 0) && use_udf) {
610 					rba = dwpnt->extent;
611 				} else {
612 					rba = 0;
613 				}
614 #endif	/* INSERTMACRESFORK && UDF */
615 				write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off,
616 					file_is_resource(dwpnt->name, dwpnt->hfstype) && (dwpnt->size > 0), rba);
617 #else
618 #ifdef	USE_LARGEFILES
619 				write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off, 0, 0);
620 #else
621 				write_one_file(dwpnt->name, dwpnt->size, outfile);
622 #endif
623 #endif	/* APPLE_HYB */
624 #ifdef UDF
625 			}
626 #endif
627 #endif	/* VMS */
628 			free(dwpnt->name);
629 			dwpnt->name = NULL;
630 		}
631 
632 
633 #ifndef DVD_AUD_VID
634 #define	dvd_aud_vid_flag	0
635 #endif
636 
637 #ifndef APPLE_HYB
638 #define	apple_hyb	0
639 #endif
640 
641 #if	defined(APPLE_HYB) || defined(DVD_AUD_VID)
642 
643 		if ((apple_hyb && !donotwrite_macpart) || (dvd_aud_vid_flag & DVD_SPEC_VIDEO)) {
644 			/*
645 			 * we may have to pad out ISO files to work with HFS
646 			 * clump sizes
647 			 */
648 			char	blk[SECTOR_SIZE];
649 			Uint	i;
650 
651 			for (i = 0; i < dwpnt->pad; i++)
652 				xfwrite(blk, SECTOR_SIZE, 1, outfile, 0, FALSE);
653 
654 			last_extent_written += dwpnt->pad;
655 		}
656 #endif	/* APPLE_HYB || DVD_AUD_VID */
657 
658 
659 		dwnext = dwpnt;
660 		dwpnt = dwpnt->next;
661 		free(dwnext);
662 		dwnext = NULL;
663 	}
664 } /* write_files(... */
665 
666 #if 0
667 LOCAL void
668 dump_filelist()
669 {
670 	struct deferred_write *dwpnt;
671 
672 	dwpnt = dw_head;
673 	while (dwpnt) {
674 		fprintf(stderr, _("File %s\n"), dwpnt->name);
675 		dwpnt = dwpnt->next;
676 	}
677 	fprintf(stderr, "\n");
678 }
679 
680 #endif
681 
682 LOCAL int
compare_dirs(rr,ll)683 compare_dirs(rr, ll)
684 	const void	*rr;
685 	const void	*ll;
686 {
687 	char		*rpnt,
688 			*lpnt;
689 	struct directory_entry **r,
690 			**l;
691 
692 	r = (struct directory_entry **)rr;
693 	l = (struct directory_entry **)ll;
694 	rpnt = (*r)->isorec.name;
695 	lpnt = (*l)->isorec.name;
696 
697 #ifdef APPLE_HYB
698 	/*
699 	 * resource fork MUST (not sure if this is true for HFS volumes) be
700 	 * before the data fork - so force it here
701 	 */
702 	if ((*r)->assoc && (*r)->assoc == (*l))
703 		return (1);
704 	if ((*l)->assoc && (*l)->assoc == (*r))
705 		return (-1);
706 #endif	/* APPLE_HYB */
707 
708 	/*
709 	 * If the names are the same, multiple extent sections of the same file
710 	 * are sorted by part number.  If the part numbers do not differ, this
711 	 * is an error.
712 	 */
713 	if (strcmp(rpnt, lpnt) == 0) {
714 #ifdef USE_LARGEFILES
715 		if ((*r)->mxpart < (*l)->mxpart)
716 			return (-1);
717 		else if ((*r)->mxpart > (*l)->mxpart)
718 			return (1);
719 #endif
720 		errmsgno(EX_BAD,
721 			_("Error: '%s' and '%s' have the same ISO9660 name '%s'.\n"),
722 			(*r)->whole_name, (*l)->whole_name,
723 			rpnt);
724 		sort_goof++;
725 	}
726 	/* Check we don't have the same RR name */
727 	if (use_RockRidge && !is_rr_dir) {
728 		/*
729 		 * entries *can* have the same RR name in the "rr_moved"
730 		 * directory so skip checks if we're in reloc_dir
731 		 */
732 		if (strcmp((*r)->name, (*l)->name) == 0) {
733 			errmsgno(EX_BAD,
734 			_("Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n"),
735 				(*r)->whole_name, (*l)->whole_name,
736 				(*r)->name);
737 			sort_goof++;
738 		}
739 	}
740 	/*
741 	 * Put the '.' and '..' entries on the head of the sorted list. For
742 	 * normal ASCII, this always happens to be the case, but out of band
743 	 * characters cause this not to be the case sometimes.
744 	 * FIXME(eric) - these tests seem redundant, in that the name is never
745 	 * assigned these values.  It will instead be \000 or \001, and thus
746 	 * should always be sorted correctly.   I need to figure out why I
747 	 * thought I needed this in the first place.
748 	 */
749 #if 0
750 	if (strcmp(rpnt, ".") == 0)
751 		return (-1);
752 	if (strcmp(lpnt, ".") == 0)
753 		return (1);
754 
755 	if (strcmp(rpnt, "..") == 0)
756 		return (-1);
757 	if (strcmp(lpnt, "..") == 0)
758 		return (1);
759 #else
760 	/*
761 	 * The code above is wrong (as explained in Eric's comment), leading to
762 	 * incorrect sort order iff the -L option ("allow leading dots") is in
763 	 * effect and a directory contains entries that start with a dot.
764 	 *  (TF, Tue Dec 29 13:49:24 CET 1998)
765 	 */
766 	if ((*r)->isorec.name_len[0] == 1 && *rpnt == 0)
767 		return (-1);	/* '.' */
768 	if ((*l)->isorec.name_len[0] == 1 && *lpnt == 0)
769 		return (1);
770 
771 	if ((*r)->isorec.name_len[0] == 1 && *rpnt == 1)
772 		return (-1);	/* '..' */
773 	if ((*l)->isorec.name_len[0] == 1 && *lpnt == 1)
774 		return (1);
775 #endif
776 
777 	while (*rpnt && *lpnt) {
778 		if (*rpnt == ';' && *lpnt != ';')
779 			return (-1);
780 		if (*rpnt != ';' && *lpnt == ';')
781 			return (1);
782 
783 		if (*rpnt == ';' && *lpnt == ';')
784 			return (0);
785 
786 		if (*rpnt == '.' && *lpnt != '.')
787 			return (-1);
788 		if (*rpnt != '.' && *lpnt == '.')
789 			return (1);
790 
791 		if ((unsigned char) *rpnt < (unsigned char) *lpnt)
792 			return (-1);
793 		if ((unsigned char) *rpnt > (unsigned char) *lpnt)
794 			return (1);
795 		rpnt++;
796 		lpnt++;
797 	}
798 	if (*rpnt)
799 		return (1);
800 	if (*lpnt)
801 		return (-1);
802 	return (0);
803 }
804 
805 /*
806  * Function:		sort_directory
807  *
808  * Purpose:		Sort the directory in the appropriate ISO9660
809  *			order.
810  *
811  * Notes:		Returns 0 if OK, returns > 0 if an error occurred.
812  */
813 EXPORT int
sort_directory(sort_dir,rr)814 sort_directory(sort_dir, rr)
815 	struct directory_entry **sort_dir;
816 	int		rr;
817 {
818 	int		dcount = 0;
819 	int		xcount = 0;
820 	int		j;
821 	int		i,
822 			len;
823 	struct directory_entry *s_entry;
824 	struct directory_entry **sortlist;
825 
826 	/* need to keep a count of how many entries are hidden */
827 	s_entry = *sort_dir;
828 	while (s_entry) {
829 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
830 			xcount++;
831 		dcount++;
832 		s_entry = s_entry->next;
833 	}
834 
835 	if (dcount == 0) {
836 		return (0);
837 	}
838 	/* OK, now we know how many there are.  Build a vector for sorting. */
839 	sortlist = (struct directory_entry **)
840 		e_malloc(sizeof (struct directory_entry *) * dcount);
841 
842 	j = dcount - xcount;
843 	dcount = 0;
844 	s_entry = *sort_dir;
845 	while (s_entry) {
846 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
847 			/* put any hidden entries at the end of the vector */
848 			sortlist[j++] = s_entry;
849 		} else {
850 			sortlist[dcount] = s_entry;
851 			dcount++;
852 		}
853 		len = s_entry->isorec.name_len[0];
854 		s_entry->isorec.name[len] = 0;
855 		s_entry = s_entry->next;
856 	}
857 
858 	/* Each directory is required to contain at least . and .. */
859 	if (dcount < 2) {
860 		errmsgno(EX_BAD,
861 			_("Directory size too small (. or .. may be missing)\n"));
862 		sort_goof = 1;
863 
864 	} else {
865 		/* only sort the non-hidden entries */
866 		sort_goof = 0;
867 		is_rr_dir = rr;
868 #ifdef PROTOTYPES
869 		qsort(sortlist, dcount, sizeof (struct directory_entry *),
870 			(int (*) (const void *, const void *)) compare_dirs);
871 #else
872 		qsort(sortlist, dcount, sizeof (struct directory_entry *),
873 			compare_dirs);
874 #endif
875 
876 		/*
877 		 * Now reassemble the linked list in the proper sorted order
878 		 * We still need the hidden entries, as they may be used in
879 		 * the Joliet tree.
880 		 */
881 		for (i = 0; i < dcount + xcount - 1; i++) {
882 			sortlist[i]->next = sortlist[i + 1];
883 		}
884 
885 		sortlist[dcount + xcount - 1]->next = NULL;
886 		*sort_dir = sortlist[0];
887 	}
888 
889 	free(sortlist);
890 	sortlist = NULL;
891 	return (sort_goof);
892 }
893 
894 LOCAL int
root_gen()895 root_gen()
896 {
897 	init_fstatbuf();
898 
899 	root_record.length[0] = 1 +
900 			offsetof(struct iso_directory_record, name[0]);
901 	root_record.ext_attr_length[0] = 0;
902 	set_733((char *)root_record.extent, root->extent);
903 	set_733((char *)root_record.size, ISO_ROUND_UP(root->size));
904 	iso9660_date(root_record.date, root_statbuf.st_mtime);
905 	root_record.flags[0] = ISO_DIRECTORY;
906 	root_record.file_unit_size[0] = 0;
907 	root_record.interleave[0] = 0;
908 	set_723(root_record.volume_sequence_number, volume_sequence_number);
909 	root_record.name_len[0] = 1;
910 	return (0);
911 }
912 
913 #ifdef SORTING
914 /*
915  *	sorts deferred_write entries based on the sort weight
916  */
917 LOCAL int
compare_sort(rr,ll)918 compare_sort(rr, ll)
919 	const void	*rr;
920 	const void	*ll;
921 {
922 	struct deferred_write	**r;
923 	struct deferred_write	**l;
924 	int			r_sort;
925 	int			l_sort;
926 
927 	r = (struct deferred_write **)rr;
928 	l = (struct deferred_write **)ll;
929 	r_sort = (*r)->s_entry->sort;
930 	l_sort = (*l)->s_entry->sort;
931 
932 	if (r_sort != l_sort)
933 		return (r_sort < l_sort ? 1 : -1);
934 	else
935 		return ((*r)->extent - (*l)->extent);
936 }
937 
938 /*
939  *	reassign start extents to files that are "hard links" to
940  *	files that may have been sorted
941  */
942 LOCAL void
reassign_link_addresses(dpnt)943 reassign_link_addresses(dpnt)
944 	struct directory	*dpnt;
945 {
946 	struct directory_entry	*s_entry;
947 	struct file_hash	*s_hash;
948 
949 	while (dpnt) {
950 		s_entry = dpnt->contents;
951 		for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
952 			/* link files have already been given the weight NOT_SORTED */
953 			if (s_entry->sort != NOT_SORTED)
954 				continue;
955 
956 			/* update the start extent */
957 			s_hash = find_hash(s_entry);
958 			if (s_hash) {
959 				set_733((char *)s_entry->isorec.extent, s_hash->starting_block);
960 				s_entry->starting_block = s_hash->starting_block;
961 			}
962 		}
963 		if (dpnt->subdir) {
964 			reassign_link_addresses(dpnt->subdir);
965 		}
966 
967 		dpnt = dpnt->next;
968 	}
969 }
970 
971 /*
972  *	sort files in order of the given sort weight
973  */
974 LOCAL int
sort_file_addresses()975 sort_file_addresses()
976 {
977 	struct deferred_write	*dwpnt;
978 	struct deferred_write	**sortlist;
979 	struct directory_entry	*s_entry;
980 	UInt32_t		start_extent;
981 	int			num = 0;
982 	int			i;
983 
984 	/* need to store start extents for linked files */
985 	flush_hash();
986 
987 	/* find out how many files we have */
988 	dwpnt = dw_head;
989 	while (dwpnt) {
990 		num++;
991 		dwpnt = dwpnt->next;
992 	}
993 
994 	/* return if we have none */
995 	if (num == 0) {
996 		return (1);
997 	}
998 
999 	/* save the start extent of the first file */
1000 	start_extent = dw_head->extent;
1001 
1002 	/* set up vector to store entries */
1003 	sortlist = (struct deferred_write **)
1004 		e_malloc(sizeof (struct deferred_write *) * num);
1005 
1006 	for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next)
1007 		sortlist[i] = dwpnt;
1008 
1009 	/* sort the list */
1010 #ifdef PROTOTYPES
1011 	qsort(sortlist, num, sizeof (struct deferred_write *),
1012 		(int (*)(const void *, const void *))compare_sort);
1013 #else
1014 	qsort(sortlist, num, sizeof (struct deferred_write *), compare_sort);
1015 #endif
1016 
1017 	/* reconstruct the linked list */
1018 	for (i = 0; i < num-1; i++) {
1019 		sortlist[i]->next = sortlist[i+1];
1020 	}
1021 
1022 	sortlist[num-1]->next = NULL;
1023 	dw_head = sortlist[0];
1024 
1025 	free(sortlist);
1026 
1027 	/* set the new start extents for the sorted list */
1028 	for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next) {
1029 		s_entry = dwpnt->s_entry;
1030 		dwpnt->extent = s_entry->starting_block = start_extent;
1031 
1032 		if (s_entry->de_flags & MULTI_EXTENT) {
1033 			struct directory_entry  *s_e;
1034 			UInt32_t		ext = start_extent;
1035 
1036 			/*
1037 			 * For unknown reason, we sometimes get mxroot as
1038 			 * part of the chain and sometime it's missing.
1039 			 * Be careful to distinct between the mxroot entry and
1040 			 * others to select both corectly in a conservative way.
1041 			 */
1042 			s_entry->mxroot->starting_block = start_extent;
1043 			set_733((char *)s_entry->mxroot->isorec.extent,
1044 								start_extent);
1045 			start_extent += ISO_BLOCKS(s_entry->mxroot->size);
1046 
1047 			for (s_e = s_entry;
1048 			    s_e && s_e->mxroot == s_entry->mxroot;
1049 			    s_e = s_e->next) {
1050 				if (s_e == s_entry->mxroot)
1051 					continue;
1052 
1053 				set_733((char *)s_e->isorec.extent, ext);
1054 				s_entry->starting_block = ext;
1055 				ext += ISO_BLOCKS(s_e->size);
1056 			}
1057 		} else {
1058 			set_733((char *)s_entry->isorec.extent, start_extent);
1059 			start_extent += ISO_BLOCKS(s_entry->size);
1060 		}
1061 #ifdef DVD_AUD_VID
1062 		/*
1063 		 * Shouldn't this be done for every type of sort? Otherwise
1064 		 * we will loose every pad info we add if we sort the files
1065 		 */
1066 		if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
1067 			start_extent += dwpnt->pad;
1068 		}
1069 #endif /* DVD_AUD_VID */
1070 
1071 		/* cache start extents for any linked files */
1072 		add_hash(s_entry);
1073 	}
1074 
1075 	return (0);
1076 }
1077 #endif /* SORTING */
1078 
1079 
1080 
1081 LOCAL BOOL
assign_file_addresses(dpnt,isnest)1082 assign_file_addresses(dpnt, isnest)
1083 	struct directory	*dpnt;
1084 	BOOL			isnest;
1085 {
1086 	struct directory *finddir;
1087 	struct directory_entry *s_entry;
1088 	struct file_hash *s_hash;
1089 	struct deferred_write *dwpnt;
1090 	char		whole_path[PATH_MAX];
1091 #ifdef DVD_AUD_VID
1092 	char		dvd_path[PATH_MAX];
1093 	title_set_info_t *title_set_info = NULL;
1094 	char	*p;
1095 #endif
1096 	BOOL	ret = FALSE;
1097 
1098 	while (dpnt) {
1099 #ifdef DVD_AUD_VID
1100 		if ((dvd_aud_vid_flag & DVD_SPEC_VIDEO) && root == dpnt->parent &&
1101 		    ((p = strstr(dpnt->whole_name, "VIDEO_TS")) != 0)&&
1102 					strcmp(p, "VIDEO_TS") == 0) {
1103 			int	maxlen = strlen(dpnt->whole_name)-8+1;
1104 
1105 			if (maxlen > sizeof (dvd_path))
1106 				maxlen = sizeof (dvd_path);
1107 			strlcpy(dvd_path, dpnt->whole_name, maxlen);
1108 #ifdef DEBUG
1109 			fprintf(stderr, _("Found 'VIDEO_TS', the path is %s \n"), dvd_path);
1110 #endif
1111 			title_set_info = DVDGetFileSet(dvd_path);
1112 			if (title_set_info == 0) {
1113 				/*
1114 				 * Do not switch off -dvd-video but let is fail later.
1115 				 */
1116 /*				dvd_aud_vid_flag &= ~DVD_SPEC_VIDEO;*/
1117 				errmsgno(EX_BAD, _("Unable to parse DVD-Video structures.\n"));
1118 			} else {
1119 				ret = TRUE;
1120 			}
1121 		}
1122 #endif /* DVD_AUD_VID */
1123 
1124 		for (s_entry = dpnt->contents; s_entry;
1125 						s_entry = s_entry->next) {
1126 			/*
1127 			 * If we already have an extent for this entry, then
1128 			 * don't assign a new one.  It must have come from a
1129 			 * previous session on the disc.  Note that we don't
1130 			 * end up scheduling the thing for writing either.
1131 			 */
1132 			if (get_733(s_entry->isorec.extent) != 0) {
1133 				continue;
1134 			}
1135 			/*
1136 			 * This saves some space if there are symlinks present.
1137 			 * If this is a multi-extent file, we get mxpart == 1
1138 			 * from find_hash().
1139 			 */
1140 			s_hash = find_hash(s_entry);
1141 			if (s_hash) {
1142 				if (verbose > 2) {
1143 					fprintf(stderr, _("Cache hit for '%s%s%s'\n"),
1144 						s_entry->filedir->de_name,
1145 						SPATH_SEPARATOR,
1146 						s_entry->name);
1147 				}
1148 				s_entry->starting_block = s_hash->starting_block;
1149 				set_733((char *)s_entry->isorec.extent,
1150 						s_hash->starting_block);
1151 				set_733((char *)s_entry->isorec.size,
1152 						s_hash->size);
1153 #ifdef USE_LARGEFILES
1154 				if (s_entry->de_flags & MULTI_EXTENT) {
1155 					struct directory_entry *s_e;
1156 					unsigned int		ext = s_hash->starting_block;
1157 
1158 					/*
1159 					 * Skip the multi extent root entry.
1160 					 */
1161 					if (s_entry->mxpart == 0)
1162 						continue;
1163 					/*
1164 					 * The directory is sorted, so we should
1165 					 * see s_entry->mxpart == 1 first.
1166 					 */
1167 					if (s_entry->mxpart != 1) {
1168 						comerrno(EX_BAD,
1169 						_("Panic: Multi extent parts for %s not sorted.\n"),
1170 						s_entry->whole_name);
1171 					}
1172 					s_entry->mxroot->starting_block = ext;
1173 					for (s_e = s_entry;
1174 					    s_e && s_e->mxroot == s_entry->mxroot;
1175 								s_e = s_e->next) {
1176 						set_733((char *)s_e->isorec.extent,
1177 									ext);
1178 						ext += ISO_BLOCKS(s_e->size);
1179 					}
1180 				}
1181 #endif
1182 
1183 #ifdef SORTING
1184 				/* check for non-directory files */
1185 				if (do_sort && ((s_entry->isorec.flags[0] & ISO_DIRECTORY) == 0)) {
1186 					/* make sure the real file has the highest weighting */
1187 					s_hash->de->sort = MAX(s_entry->sort, s_hash->de->sort);
1188 					/* flag this as a potential non-sorted file */
1189 					s_entry->sort = NOT_SORTED;
1190 				}
1191 #endif /* SORTING */
1192 				continue;
1193 			}
1194 			/*
1195 			 * If this is for a directory that is not a . or
1196 			 * a .. entry, then look up the information for the
1197 			 * entry.  We have already assigned extents for
1198 			 * directories, so we just need to fill in the blanks
1199 			 * here.
1200 			 */
1201 			if (strcmp(s_entry->name, ".") != 0 &&
1202 					strcmp(s_entry->name, "..") != 0 &&
1203 					s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1204 				finddir = dpnt->subdir;
1205 				while (finddir && finddir->self != s_entry) {
1206 					finddir = finddir->next;
1207 				}
1208 				if (!finddir) {
1209 #ifdef	DVD_AUD_VID
1210 					if (title_set_info != 0) {
1211 						DVDFreeFileSet(title_set_info);
1212 					}
1213 #endif
1214 					comerrno(EX_BAD,
1215 						_("Fatal goof - could not find dir entry for '%s'\n"),
1216 						s_entry->name);
1217 				}
1218 				set_733((char *)s_entry->isorec.extent,
1219 						finddir->extent);
1220 				s_entry->starting_block = finddir->extent;
1221 				s_entry->size = ISO_ROUND_UP(finddir->size);
1222 				total_dir_size += s_entry->size;
1223 				add_hash(s_entry);
1224 				set_733((char *)s_entry->isorec.size,
1225 						ISO_ROUND_UP(finddir->size));
1226 				continue;
1227 			}
1228 			/*
1229 			 * If this is . or .., then look up the relevant info
1230 			 * from the tables.
1231 			 */
1232 			if (strcmp(s_entry->name, ".") == 0) {
1233 				set_733((char *)s_entry->isorec.extent,
1234 								dpnt->extent);
1235 
1236 				/*
1237 				 * Set these so that the hash table has the
1238 				 * correct information
1239 				 */
1240 				s_entry->starting_block = dpnt->extent;
1241 				s_entry->size = ISO_ROUND_UP(dpnt->size);
1242 
1243 				add_hash(s_entry);
1244 				s_entry->starting_block = dpnt->extent;
1245 				set_733((char *)s_entry->isorec.size,
1246 						ISO_ROUND_UP(dpnt->size));
1247 				continue;
1248 			}
1249 			if (strcmp(s_entry->name, "..") == 0) {
1250 				if (dpnt == root) {
1251 					total_dir_size += root->size;
1252 				}
1253 				set_733((char *)s_entry->isorec.extent,
1254 							dpnt->parent->extent);
1255 
1256 				/*
1257 				 * Set these so that the hash table has the
1258 				 * correct information
1259 				 */
1260 				s_entry->starting_block = dpnt->parent->extent;
1261 				s_entry->size =
1262 					ISO_ROUND_UP(dpnt->parent->size);
1263 
1264 				add_hash(s_entry);
1265 				s_entry->starting_block = dpnt->parent->extent;
1266 				set_733((char *)s_entry->isorec.size,
1267 					ISO_ROUND_UP(dpnt->parent->size));
1268 				continue;
1269 			}
1270 			/*
1271 			 * Some ordinary non-directory file.  Just schedule
1272 			 * the file to be written.  This is all quite
1273 			 * straightforward, just make a list and assign
1274 			 * extents as we go.  Once we get through writing all
1275 			 * of the directories, we should be ready write out
1276 			 * these files
1277 			 */
1278 			if (s_entry->size) {
1279 				dwpnt = (struct deferred_write *)
1280 					e_malloc(sizeof (struct deferred_write));
1281 				/* save this directory entry for later use */
1282 				dwpnt->s_entry = s_entry;
1283 				/* set the initial padding to zero */
1284 				dwpnt->pad = 0;
1285 				dwpnt->dw_flags = 0;
1286 #ifdef DVD_AUD_VID
1287 				if ((dvd_aud_vid_flag & DVD_SPEC_VIDEO) && (title_set_info != 0)) {
1288 					int pad;
1289 
1290 					pad = DVDGetFilePad(title_set_info, s_entry->name);
1291 					if (pad < 0) {
1292 						errmsgno(EX_BAD,
1293 						_("Implementation botch. Video pad for file %s is %d\n"),
1294 						s_entry->name, pad),
1295 						comerrno(EX_BAD,
1296 						_("Either the *.IFO file is bad or you found a mkisofs bug.\n"));
1297 					}
1298 					dwpnt->pad = pad;
1299 					if (verbose > 0 && pad != 0) {
1300 						fprintf(stderr,
1301 							_("The pad was %d for file %s\n"),
1302 								dwpnt->pad, s_entry->name);
1303 					}
1304 				}
1305 #endif /* DVD_AUD_VID */
1306 #ifdef APPLE_HYB
1307 				/*
1308 				 * maybe an offset to start of the real
1309 				 * file/fork
1310 				 */
1311 				dwpnt->off = s_entry->hfs_off;
1312 				dwpnt->hfstype = s_entry->hfs_type;
1313 #else
1314 				dwpnt->off = (off_t)0;
1315 #endif	/* APPLE_HYB */
1316 				if (s_entry->inode == TABLE_INODE) {
1317 					dwpnt->table = s_entry->table;
1318 					dwpnt->name = NULL;
1319 					sprintf(whole_path, "%s%s%s",
1320 						s_entry->filedir->whole_name,
1321 						SPATH_SEPARATOR, trans_tbl);
1322 				} else {
1323 					dwpnt->table = NULL;
1324 					strlcpy(whole_path,
1325 						s_entry->whole_name,
1326 						sizeof (whole_path));
1327 					dwpnt->name = e_strdup(whole_path);
1328 				}
1329 				dwpnt->next = NULL;
1330 				dwpnt->size = s_entry->size;
1331 				dwpnt->extent = last_extent;
1332 				set_733((char *)s_entry->isorec.extent,
1333 								last_extent);
1334 				s_entry->starting_block = last_extent;
1335 #ifdef USE_LARGEFILES
1336 				/*
1337 				 * Update the entries for multi-section files
1338 				 * as we now know the starting extent numbers.
1339 				 */
1340 				if (s_entry->de_flags & MULTI_EXTENT) {
1341 					struct directory_entry *s_e;
1342 					unsigned int		ext = last_extent;
1343 
1344 					/*
1345 					 * Skip the multi extent root entry.
1346 					 */
1347 					if (s_entry->mxpart == 0) {
1348 						if (dwpnt->name)
1349 							free(dwpnt->name);
1350 						free(dwpnt);
1351 						continue;
1352 					}
1353 					/*
1354 					 * The directory is sorted, so we should
1355 					 * see s_entry->mxpart == 1 first.
1356 					 */
1357 					if (s_entry->mxpart != 1) {
1358 						comerrno(EX_BAD,
1359 						_("Panic: Multi extent parts for %s not sorted.\n"),
1360 						s_entry->whole_name);
1361 					}
1362 					dwpnt->size = s_entry->mxroot->size;
1363 					s_entry->mxroot->starting_block = ext;
1364 					/*
1365 					 * Set the mxroot (mxpart == 0) to allow
1366 					 * the UDF code to fetch the starting
1367 					 * extent number.
1368 					 */
1369 					set_733((char *)s_entry->mxroot->isorec.extent, ext);
1370 					for (s_e = s_entry;
1371 					    s_e && s_e->mxroot == s_entry->mxroot;
1372 								s_e = s_e->next) {
1373 						if (s_e->mxpart == 0)
1374 							continue;
1375 						set_733((char *)s_e->isorec.extent,
1376 									ext);
1377 						ext += ISO_BLOCKS(s_e->size);
1378 					}
1379 					add_hash(s_entry);
1380 				}
1381 #endif
1382 				if (dw_tail) {
1383 					dw_tail->next = dwpnt;
1384 					dw_tail = dwpnt;
1385 				} else {
1386 					dw_head = dwpnt;
1387 					dw_tail = dwpnt;
1388 				}
1389 				add_hash(s_entry);
1390 				/*
1391 				 * The cache holds the full size of the file
1392 				 */
1393 				last_extent += ISO_BLOCKS(dwpnt->size);
1394 				dwpnt->dw_flags = s_entry->de_flags;
1395 #ifdef APPLE_HYB
1396 #if defined(INSERTMACRESFORK) && defined(UDF)
1397 				if (file_is_resource(dwpnt->name, dwpnt->s_entry->hfs_type) && (dwpnt->size > 0) && use_udf) {
1398 					last_extent++;
1399 					if (ISO_ROUND_UP(dwpnt->size) <
1400 					    ISO_ROUND_UP(dwpnt->size + SIZEOF_UDF_EXT_ATTRIBUTE_COMMON)) {
1401 						last_extent++;
1402 					}
1403 				}
1404 #endif
1405 #endif	/* APPLE_HYB */
1406 #ifdef DVD_AUD_VID
1407 				/* Shouldn't we always add the pad info? */
1408 				if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
1409 					last_extent += dwpnt->pad;
1410 				}
1411 #endif /* DVD_AUD_VID */
1412 				if (verbose > 2) {
1413 					fprintf(stderr, "%u %d %s\n",
1414 						s_entry->starting_block,
1415 						last_extent - 1, whole_path);
1416 				}
1417 #ifdef DBG_ISO
1418 				if (ISO_BLOCKS(s_entry->size) > 500) {
1419 					fprintf(stderr,
1420 						_("Warning: large file '%s'\n"),
1421 						whole_path);
1422 					fprintf(stderr,
1423 						_("Starting block is %d\n"),
1424 						s_entry->starting_block);
1425 					fprintf(stderr,
1426 					_("Reported file size is %lld\n"),
1427 						(Llong)s_entry->size);
1428 
1429 				}
1430 #endif
1431 #ifdef	NOT_NEEDED	/* Never use this code if you like to create a DVD */
1432 
1433 				if (last_extent > (800000000 >> 11)) {
1434 					/* More than 800Mb? Punt */
1435 					fprintf(stderr,
1436 					_("Extent overflow processing file '%s'\n"),
1437 						whole_path);
1438 					fprintf(stderr,
1439 						_("Starting block is %d\n"),
1440 						s_entry->starting_block);
1441 					fprintf(stderr,
1442 					_("Reported file size is %lld\n"),
1443 							(Llong)s_entry->size);
1444 					exit(1);
1445 				}
1446 #endif
1447 				continue;
1448 			}
1449 			/*
1450 			 * This is for zero-length files.  If we leave the
1451 			 * extent 0, then we get screwed, because many readers
1452 			 * simply drop files that have an extent of zero.
1453 			 * Thus we leave the size 0, and just assign the
1454 			 * extent number.
1455 			 */
1456 			set_733((char *)s_entry->isorec.extent, last_extent);
1457 		}
1458 		if (dpnt->subdir) {
1459 			if (assign_file_addresses(dpnt->subdir, TRUE))
1460 				ret = TRUE;
1461 		}
1462 		dpnt = dpnt->next;
1463 	}
1464 #ifdef DVD_AUD_VID
1465 	if (title_set_info != NULL) {
1466 		DVDFreeFileSet(title_set_info);
1467 	}
1468 	if ((dvd_aud_vid_flag & DVD_SPEC_VIDEO)&& !ret && !isnest) {
1469 		errmsgno(EX_BAD,
1470 			_("Could not find correct 'VIDEO_TS' directory.\n"));
1471 	}
1472 #endif /* DVD_AUD_VID */
1473 	return (ret);
1474 } /* assign_file_addresses(... */
1475 
1476 LOCAL void
free_one_directory(dpnt)1477 free_one_directory(dpnt)
1478 	struct directory	*dpnt;
1479 {
1480 	struct directory_entry *s_entry;
1481 	struct directory_entry *s_entry_d;
1482 
1483 	s_entry = dpnt->contents;
1484 	while (s_entry) {
1485 		s_entry_d = s_entry;
1486 		s_entry = s_entry->next;
1487 
1488 		if (s_entry_d->rr_attributes) {
1489 			free(s_entry_d->rr_attributes);
1490 			s_entry_d->rr_attributes = NULL;
1491 		}
1492 		if (s_entry_d->name != NULL) {
1493 			free(s_entry_d->name);
1494 			s_entry_d->name = NULL;
1495 		}
1496 		if (s_entry_d->whole_name != NULL) {
1497 			free(s_entry_d->whole_name);
1498 			s_entry_d->whole_name = NULL;
1499 		}
1500 #ifdef APPLE_HYB
1501 		if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc &&
1502 		    (s_entry_d->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
1503 			free(s_entry_d->hfs_ent);
1504 		}
1505 #endif	/* APPLE_HYB */
1506 
1507 #ifdef	DUPLICATES_ONCE
1508 		if (s_entry_d->digest_fast) {
1509 
1510 			if (s_entry_d->digest_full &&
1511 			    (s_entry_d->digest_full != s_entry_d->digest_fast))
1512 				free(s_entry_d->digest_full);
1513 
1514 			free(s_entry_d->digest_fast);
1515 
1516 			s_entry_d->digest_fast = NULL;
1517 			s_entry_d->digest_full = NULL;
1518 		}
1519 #endif
1520 		free(s_entry_d);
1521 		s_entry_d = NULL;
1522 	}
1523 	dpnt->contents = NULL;
1524 } /* free_one_directory(... */
1525 
1526 LOCAL void
free_directories(dpnt)1527 free_directories(dpnt)
1528 	struct directory	*dpnt;
1529 {
1530 	while (dpnt) {
1531 		free_one_directory(dpnt);
1532 		if (dpnt->subdir)
1533 			free_directories(dpnt->subdir);
1534 		dpnt = dpnt->next;
1535 	}
1536 }
1537 
1538 EXPORT void
generate_one_directory(dpnt,outfile)1539 generate_one_directory(dpnt, outfile)
1540 	struct directory	*dpnt;
1541 	FILE			*outfile;
1542 {
1543 	unsigned int	ce_address = 0;
1544 	char		*ce_buffer;
1545 	unsigned int	ce_index = 0;
1546 	unsigned int	ce_size;
1547 	unsigned int	dir_index;
1548 	char		*directory_buffer;
1549 	int		new_reclen;
1550 	struct directory_entry *s_entry;
1551 	struct directory_entry *s_entry_d;
1552 	unsigned int	total_size;
1553 
1554 	total_size = ISO_ROUND_UP(dpnt->size);
1555 	directory_buffer = (char *)e_malloc(total_size);
1556 	memset(directory_buffer, 0, total_size);
1557 	dir_index = 0;
1558 
1559 	ce_size = ISO_ROUND_UP(dpnt->ce_bytes);
1560 	ce_buffer = NULL;
1561 
1562 	if (ce_size > 0) {
1563 		ce_buffer = (char *)e_malloc(ce_size);
1564 		memset(ce_buffer, 0, ce_size);
1565 
1566 		ce_index = 0;
1567 
1568 		/* Absolute sector address of CE entries for this directory */
1569 		ce_address = last_extent_written + (total_size >> 11);
1570 	}
1571 	s_entry = dpnt->contents;
1572 	while (s_entry) {
1573 		/* skip if it's hidden */
1574 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1575 			s_entry = s_entry->next;
1576 			continue;
1577 		}
1578 		/*
1579 		 * We do not allow directory entries to cross sector
1580 		 * boundaries. Simply pad, and then start the next entry at
1581 		 * the next sector
1582 		 */
1583 		new_reclen = s_entry->isorec.length[0];
1584 		if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >=
1585 								SECTOR_SIZE) {
1586 			dir_index = ISO_ROUND_UP(dir_index);
1587 		}
1588 		memcpy(directory_buffer + dir_index, &s_entry->isorec,
1589 			offsetof(struct iso_directory_record, name[0]) +
1590 			s_entry->isorec.name_len[0]);
1591 		dir_index += offsetof(struct iso_directory_record, name[0]) +
1592 			s_entry->isorec.name_len[0];
1593 
1594 		/* Add the Rock Ridge attributes, if present */
1595 		if (s_entry->rr_attr_size) {
1596 			if (dir_index & 1) {
1597 				directory_buffer[dir_index++] = 0;
1598 			}
1599 			/*
1600 			 * If the RR attributes were too long, then write the
1601 			 * CE records, as required.
1602 			 */
1603 			if (s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
1604 				struct iso_xa_dir_record *xadp;
1605 				unsigned char	*pnt;
1606 				int		len,
1607 						nbytes;
1608 
1609 				/*
1610 				 * Go through the entire record, first skip
1611 				 * the XA record and then fix up the
1612 				 * CE entries so that the extent and offset
1613 				 * are correct
1614 				 */
1615 				pnt = s_entry->rr_attributes;
1616 				len = s_entry->total_rr_attr_size;
1617 
1618 				if (len >= 14) {
1619 					xadp = (struct iso_xa_dir_record *)pnt;
1620 
1621 					if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
1622 									xadp->reserved[0] == '\0') {
1623 						len -= 14;
1624 						pnt += 14;
1625 					}
1626 				}
1627 
1628 				while (len > 3) {
1629 #ifdef DEBUG
1630 					if (ce_size <= 0) {
1631 						fprintf(stderr,
1632 						_("Warning: ce_index(%d) && ce_address(%d) not initialized\n"),
1633 							ce_index, ce_address);
1634 					}
1635 #endif
1636 
1637 					if (pnt[0] == 'C' && pnt[1] == 'E') {
1638 						nbytes = get_733((char *)pnt + 20);
1639 
1640 						if ((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
1641 							SECTOR_SIZE) {
1642 							ce_index = ISO_ROUND_UP(ce_index);
1643 						}
1644 						set_733((char *)pnt + 4,
1645 							ce_address + (ce_index >> 11));
1646 						set_733((char *)pnt + 12,
1647 							ce_index & (SECTOR_SIZE - 1));
1648 
1649 
1650 
1651 						/*
1652 						 * Now store the block in the
1653 						 * ce buffer
1654 						 */
1655 						memcpy(ce_buffer + ce_index,
1656 							pnt + pnt[2], nbytes);
1657 						ce_index += nbytes;
1658 						if (ce_index & 1) {
1659 							ce_index++;
1660 						}
1661 					}
1662 					len -= pnt[2];
1663 					pnt += pnt[2];
1664 				}
1665 
1666 			}
1667 			rockridge_size += s_entry->total_rr_attr_size;
1668 			memcpy(directory_buffer + dir_index,
1669 				s_entry->rr_attributes,
1670 				s_entry->rr_attr_size);
1671 			dir_index += s_entry->rr_attr_size;
1672 		}
1673 		if (dir_index & 1) {
1674 			directory_buffer[dir_index++] = 0;
1675 		}
1676 		s_entry_d = s_entry;
1677 		s_entry = s_entry->next;
1678 
1679 		/*
1680 		 * Joliet doesn't use the Rock Ridge attributes, so we free
1681 		 * it here.
1682 		 */
1683 		if (s_entry_d->rr_attributes) {
1684 			free(s_entry_d->rr_attributes);
1685 			s_entry_d->rr_attributes = NULL;
1686 		}
1687 	}
1688 
1689 	if (dpnt->size != dir_index) {
1690 		errmsgno(EX_BAD,
1691 			_("Unexpected directory length %lld expected: %d '%s'\n"),
1692 			(Llong)dpnt->size,
1693 			dir_index, dpnt->de_name);
1694 	}
1695 	xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
1696 	last_extent_written += total_size >> 11;
1697 	free(directory_buffer);
1698 	directory_buffer = NULL;
1699 
1700 	if (ce_size > 0) {
1701 		if (ce_index != dpnt->ce_bytes) {
1702 			errmsgno(EX_BAD,
1703 			_("Continuation entry record length mismatch %d expected: %d.\n"),
1704 				ce_index, dpnt->ce_bytes);
1705 		}
1706 		xfwrite(ce_buffer, ce_size, 1, outfile, 0, FALSE);
1707 		last_extent_written += ce_size >> 11;
1708 		free(ce_buffer);
1709 		ce_buffer = NULL;
1710 	}
1711 } /* generate_one_directory(... */
1712 
1713 LOCAL void
build_pathlist(node)1714 build_pathlist(node)
1715 	struct directory	*node;
1716 {
1717 	struct directory *dpnt;
1718 
1719 	dpnt = node;
1720 
1721 	while (dpnt) {
1722 		/* skip if it's hidden */
1723 		if ((dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
1724 			pathlist[dpnt->path_index] = dpnt;
1725 
1726 		if (dpnt->subdir)
1727 			build_pathlist(dpnt->subdir);
1728 		dpnt = dpnt->next;
1729 	}
1730 } /* build_pathlist(... */
1731 
1732 LOCAL int
compare_paths(r,l)1733 compare_paths(r, l)
1734 	void const	*r;
1735 	void const	*l;
1736 {
1737 	struct directory const *ll = *(struct directory * const *) l;
1738 	struct directory const *rr = *(struct directory * const *) r;
1739 
1740 	if (rr->parent->path_index < ll->parent->path_index) {
1741 		return (-1);
1742 	}
1743 	if (rr->parent->path_index > ll->parent->path_index) {
1744 		return (1);
1745 	}
1746 	return (strcmp(rr->self->isorec.name, ll->self->isorec.name));
1747 
1748 } /* compare_paths(... */
1749 
1750 LOCAL int
generate_path_tables()1751 generate_path_tables()
1752 {
1753 	struct directory_entry *de = NULL;
1754 	struct directory *dpnt;
1755 	int		fix;
1756 	int		i;
1757 	int		j;
1758 	int		namelen;
1759 	char		*npnt;
1760 	char		*npnt1;
1761 	int		tablesize;
1762 
1763 	/* First allocate memory for the tables and initialize the memory */
1764 	tablesize = path_blocks << 11;
1765 	path_table_m = (char *)e_malloc(tablesize);
1766 	path_table_l = (char *)e_malloc(tablesize);
1767 	memset(path_table_l, 0, tablesize);
1768 	memset(path_table_m, 0, tablesize);
1769 
1770 	/*
1771 	 * Now start filling in the path tables.  Start with root directory
1772 	 */
1773 
1774 	path_table_index = 0;
1775 	pathlist = (struct directory **)e_malloc(sizeof (struct directory *)
1776 		*next_path_index);
1777 	memset(pathlist, 0, sizeof (struct directory *) * next_path_index);
1778 	build_pathlist(root);
1779 
1780 	do {
1781 		fix = 0;
1782 #ifdef PROTOTYPES
1783 		qsort(&pathlist[1], next_path_index - 1,
1784 			sizeof (struct directory *),
1785 			(int (*) (const void *, const void *)) compare_paths);
1786 #else
1787 		qsort(&pathlist[1], next_path_index - 1,
1788 			sizeof (struct directory *),
1789 			compare_paths);
1790 #endif
1791 
1792 		for (j = 1; j < next_path_index; j++) {
1793 			if (pathlist[j]->path_index != j) {
1794 				pathlist[j]->path_index = j;
1795 				fix++;
1796 			}
1797 		}
1798 	} while (fix);
1799 
1800 	for (j = 1; j < next_path_index; j++) {
1801 		dpnt = pathlist[j];
1802 		if (!dpnt) {
1803 			comerrno(EX_BAD, _("Entry %d not in path tables\n"), j);
1804 		}
1805 		npnt = dpnt->de_name;
1806 
1807 		/* So the root comes out OK */
1808 		if ((*npnt == 0) || (dpnt == root)) {
1809 			npnt = ".";
1810 		}
1811 		npnt1 = strrchr(npnt, PATH_SEPARATOR);
1812 		if (npnt1) {
1813 			npnt = npnt1 + 1;
1814 		}
1815 		de = dpnt->self;
1816 		if (!de) {
1817 			comerrno(EX_BAD,
1818 			_("Fatal ISO9660 goof - directory has amnesia\n"));
1819 		}
1820 		namelen = de->isorec.name_len[0];
1821 
1822 		path_table_l[path_table_index] = namelen;
1823 		path_table_m[path_table_index] = namelen;
1824 		path_table_index += 2;
1825 
1826 		set_731(path_table_l + path_table_index, dpnt->extent);
1827 		set_732(path_table_m + path_table_index, dpnt->extent);
1828 		path_table_index += 4;
1829 
1830 		set_721(path_table_l + path_table_index,
1831 			dpnt->parent->path_index);
1832 		set_722(path_table_m + path_table_index,
1833 			dpnt->parent->path_index);
1834 
1835 		if (dpnt->parent->path_index > 0xffff) {
1836 			static int warned = 0;
1837 
1838 			if (!warned) {
1839 				warned++;
1840 				errmsgno(EX_BAD,
1841 			_("Unable to generate sane path tables - too many directories (%u)\n"),
1842 					dpnt->parent->path_index);
1843 				if (!nolimitpathtables)
1844 					errmsgno(EX_BAD,
1845 					_("Try to use the option -no-limit-pathtables\n"));
1846 			}
1847 			if (!nolimitpathtables)
1848 				exit(EX_BAD);
1849 			/*
1850 			 * Let it point to the root directory instead.
1851 			 */
1852 			set_721(path_table_l + path_table_index, 1);
1853 			set_722(path_table_m + path_table_index, 1);
1854 		}
1855 
1856 		path_table_index += 2;
1857 
1858 		for (i = 0; i < namelen; i++) {
1859 			path_table_l[path_table_index] = de->isorec.name[i];
1860 			path_table_m[path_table_index] = de->isorec.name[i];
1861 			path_table_index++;
1862 		}
1863 		if (path_table_index & 1) {
1864 			path_table_index++;	/* For odd lengths we pad */
1865 		}
1866 	}
1867 
1868 	free(pathlist);
1869 	pathlist = NULL;
1870 	if (path_table_index != path_table_size) {
1871 		errmsgno(EX_BAD,
1872 			_("Path table lengths do not match %d expected: %d\n"),
1873 			path_table_index,
1874 			path_table_size);
1875 	}
1876 	return (0);
1877 } /* generate_path_tables(... */
1878 
1879 EXPORT void
memcpy_max(to,from,max)1880 memcpy_max(to, from, max)
1881 	char	*to;
1882 	char	*from;
1883 	int	max;
1884 {
1885 	int	n = strlen(from);
1886 
1887 	if (n > max) {
1888 		n = max;
1889 	}
1890 	memcpy(to, from, n);
1891 
1892 } /* memcpy_max(... */
1893 
1894 EXPORT void
outputlist_insert(frag)1895 outputlist_insert(frag)
1896 	struct output_fragment *frag;
1897 {
1898 	struct output_fragment *nfrag;
1899 
1900 	nfrag = e_malloc(sizeof (*frag));
1901 	movebytes(frag, nfrag, sizeof (*frag));
1902 	nfrag->of_start_extent = 0;
1903 
1904 	if (out_tail == NULL) {
1905 		out_list = out_tail = nfrag;
1906 	} else {
1907 		out_tail->of_next = nfrag;
1908 		out_tail = nfrag;
1909 	}
1910 }
1911 
1912 LOCAL int
file_write(outfile)1913 file_write(outfile)
1914 	FILE	*outfile;
1915 {
1916 	Uint	should_write;
1917 
1918 #ifdef APPLE_HYB
1919 	char	buffer[SECTOR_SIZE];
1920 
1921 	memset(buffer, 0, sizeof (buffer));
1922 
1923 	if (apple_hyb && !donotwrite_macpart) {
1924 
1925 		int	i;
1926 
1927 		/*
1928 		 * write out padding to round up to HFS allocation block
1929 		 */
1930 		for (i = 0; i < hfs_pad; i++)
1931 			xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
1932 
1933 		last_extent_written += hfs_pad;
1934 	}
1935 #endif	/* APPLE_HYB */
1936 
1937 	/*
1938 	 * OK, all done with that crap.  Now write out the directories. This is
1939 	 * where the fur starts to fly, because we need to keep track of each
1940 	 * file as we find it and keep track of where we put it.
1941 	 */
1942 	should_write = last_extent - session_start;
1943 
1944 	if (verbose > 2) {
1945 #ifdef DBG_ISO
1946 		fprintf(stderr,
1947 			_("Total directory extents being written = %u\n"),
1948 							last_extent);
1949 #endif
1950 
1951 #ifdef APPLE_HYB
1952 		if (apple_hyb && !donotwrite_macpart)
1953 			fprintf(stderr,
1954 			_("Total extents scheduled to be written (inc HFS) = %u\n"),
1955 				last_extent - session_start);
1956 		else
1957 #endif	/* APPLE_HYB */
1958 
1959 			fprintf(stderr,
1960 				_("Total extents scheduled to be written = %u\n"),
1961 				last_extent - session_start);
1962 	}
1963 	/* Now write all of the files that we need. */
1964 	write_files(outfile);
1965 
1966 #ifdef APPLE_HYB
1967 	/* write out extents/catalog/dt file */
1968 	if (apple_hyb && !donotwrite_macpart) {
1969 
1970 		xfwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, outfile, 0, FALSE);
1971 
1972 		/* round up to a whole CD block */
1973 		if (HFS_ROUND_UP(hce->hfs_tot_size) -
1974 					hce->hfs_tot_size * HFS_BLOCKSZ) {
1975 			xfwrite(buffer,
1976 				HFS_ROUND_UP(hce->hfs_tot_size) -
1977 				hce->hfs_tot_size * HFS_BLOCKSZ, 1, outfile, 0, FALSE);
1978 		}
1979 		last_extent_written += ISO_ROUND_UP(hce->hfs_tot_size *
1980 						HFS_BLOCKSZ) / SECTOR_SIZE;
1981 
1982 		/* write out HFS boot block */
1983 		if (mac_boot.name)
1984 			write_one_file(mac_boot.name, mac_boot.size, outfile,
1985 								mac_boot.off, 0, 0);
1986 	}
1987 #endif	/* APPLE_HYB */
1988 
1989 	/* The rest is just fluff. */
1990 	if (verbose == 0) {
1991 		return (0);
1992 	}
1993 #ifdef APPLE_HYB
1994 	if (apple_hyb && !donotwrite_macpart) {
1995 		fprintf(stderr,
1996 			_("Total extents actually written (inc HFS) = %u\n"),
1997 			last_extent_written - session_start);
1998 		fprintf(stderr, _("(Size of ISO volume = %d, HFS extra = %d)\n"),
1999 			last_extent_written - session_start - hfs_extra,
2000 			hfs_extra);
2001 	} else
2002 #else
2003 	fprintf(stderr, _("Total extents actually written = %d\n"),
2004 		last_extent_written - session_start);
2005 #endif	/* APPLE_HYB */
2006 
2007 	/* Hard links throw us off here */
2008 	if (should_write != (last_extent - session_start)) {
2009 		fprintf(stderr,
2010 		_("Number of extents written not what was predicted.  Please fix.\n"));
2011 		fprintf(stderr, _("Predicted = %d, written = %d\n"),
2012 						should_write, last_extent);
2013 	}
2014 	fprintf(stderr, _("Total translation table size: %d\n"), table_size);
2015 	fprintf(stderr, _("Total rockridge attributes bytes: %d\n"),
2016 						rockridge_size);
2017 	fprintf(stderr, _("Total directory bytes: %d\n"), total_dir_size);
2018 	fprintf(stderr, _("Path table size(bytes): %d\n"), path_table_size);
2019 
2020 #ifdef DEBUG
2021 	fprintf(stderr,
2022 		"next extent, last_extent, last_extent_written %d %d %d\n",
2023 		next_extent, last_extent, last_extent_written);
2024 #endif
2025 
2026 	return (0);
2027 
2028 } /* iso_write(... */
2029 
2030 /*
2031  * Function to write the PVD for the disc.
2032  */
2033 LOCAL int
pvd_write(outfile)2034 pvd_write(outfile)
2035 	FILE	*outfile;
2036 {
2037 	char		iso_time[17];
2038 	int		should_write;
2039 	int		i;
2040 	int		s;
2041 	Uchar		*cp;
2042 extern	ldate		modification_date;
2043 
2044 
2045 	iso9660_ldate(iso_time, tv_begun.tv_sec, tv_begun.tv_usec * 1000, -100);
2046 
2047 	/* Next we write out the primary descriptor for the disc */
2048 	memset(&vol_desc, 0, sizeof (vol_desc));
2049 	vol_desc.type[0] = ISO_VD_PRIMARY;
2050 	strncpy(vol_desc.id, ISO_STANDARD_ID, sizeof (vol_desc.id));
2051 	vol_desc.version[0] = 1;
2052 
2053 	memset(vol_desc.system_id, ' ', sizeof (vol_desc.system_id));
2054 	memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
2055 
2056 	memset(vol_desc.volume_id, ' ', sizeof (vol_desc.volume_id));
2057 	memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
2058 
2059 	should_write = last_extent - session_start;
2060 	set_733((char *)vol_desc.volume_space_size, should_write);
2061 	set_723(vol_desc.volume_set_size, volume_set_size);
2062 	set_723(vol_desc.volume_sequence_number, volume_sequence_number);
2063 	set_723(vol_desc.logical_block_size, SECTOR_SIZE);
2064 
2065 	/*
2066 	 * The path tables are used by DOS based machines to cache directory
2067 	 * locations
2068 	 */
2069 	set_733((char *)vol_desc.path_table_size, path_table_size);
2070 	set_731(vol_desc.type_l_path_table, path_table[0]);
2071 	set_731(vol_desc.opt_type_l_path_table, path_table[1]);
2072 	set_732(vol_desc.type_m_path_table, path_table[2]);
2073 	set_732(vol_desc.opt_type_m_path_table, path_table[3]);
2074 
2075 	/* Now we copy the actual root directory record */
2076 	memcpy(vol_desc.root_directory_record, &root_record,
2077 		offsetof(struct iso_directory_record, name[0]) + 1);
2078 
2079 	/*
2080 	 * The rest is just fluff.  It looks nice to fill in many of these
2081 	 * fields, though.
2082 	 */
2083 	FILL_SPACE(volume_set_id);
2084 	if (volset_id)
2085 		memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id));
2086 
2087 	FILL_SPACE(publisher_id);
2088 	if (publisher)
2089 		memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher));
2090 
2091 	FILL_SPACE(preparer_id);
2092 	if (preparer)
2093 		memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer));
2094 
2095 	FILL_SPACE(application_id);
2096 	if (appid)
2097 		memcpy_max(vol_desc.application_id, appid, strlen(appid));
2098 
2099 	FILL_SPACE(copyright_file_id);
2100 	if (copyright)
2101 		memcpy_max(vol_desc.copyright_file_id, copyright,
2102 			strlen(copyright));
2103 
2104 	FILL_SPACE(abstract_file_id);
2105 	if (abstract)
2106 		memcpy_max(vol_desc.abstract_file_id, abstract,
2107 			strlen(abstract));
2108 
2109 	FILL_SPACE(bibliographic_file_id);
2110 	if (biblio)
2111 		memcpy_max(vol_desc.bibliographic_file_id, biblio,
2112 			strlen(biblio));
2113 
2114 	FILL_SPACE(creation_date);
2115 	FILL_SPACE(modification_date);
2116 	FILL_SPACE(expiration_date);
2117 	FILL_SPACE(effective_date);
2118 	vol_desc.file_structure_version[0] = 1;
2119 	FILL_SPACE(application_data);
2120 
2121 	iso9660_ldate(vol_desc.modification_date,
2122 		modification_date.l_sec,
2123 		modification_date.l_usec * 1000,
2124 		modification_date.l_gmtoff);
2125 
2126 	memcpy(vol_desc.creation_date, iso_time, 17);
2127 	memcpy(vol_desc.expiration_date, "0000000000000000", 17);
2128 	memcpy(vol_desc.effective_date, iso_time, 17);
2129 
2130 	if (use_XA) {
2131 		char	*xap = &((char *)&vol_desc)[1024];
2132 
2133 		memcpy(&xap[0], "CD-XA001", 8);			/* XA Sign.  */
2134 		memcpy(&xap[8], "\0\0", 2);			/* XA flags  */
2135 		memcpy(&xap[10], "\0\0\0\0\0\0\0\0", 8);	/* Start dir */
2136 		memcpy(&xap[18], "\0\0\0\0\0\0\0\0", 8);	/* Reserved  */
2137 	}
2138 
2139 	/*
2140 	 * Compute a checksum to be used as a fingerprint in case we
2141 	 * include correct inode/link-count information in the current image.
2142 	 */
2143 	for (i = 0, s = 0, cp = (Uchar *)&vol_desc; i < SECTOR_SIZE; i++) {
2144 		s += cp[i] & 0xFF;
2145 	}
2146 	vol_desc_sum = s;
2147 
2148 	/* if not a bootable cd do it the old way */
2149 	xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2150 	last_extent_written++;
2151 	return (0);
2152 }
2153 
2154 /*
2155  * Function to write the Extended PVD for the disc.
2156  */
2157 LOCAL int
xpvd_write(outfile)2158 xpvd_write(outfile)
2159 	FILE	*outfile;
2160 {
2161 	vol_desc.type[0] = ISO_VD_SUPPLEMENTARY;
2162 	vol_desc.version[0] = 2;
2163 	vol_desc.file_structure_version[0] = 2;
2164 
2165 	/* if not a bootable cd do it the old way */
2166 	xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2167 	last_extent_written++;
2168 	return (0);
2169 }
2170 
2171 /*
2172  * Function to write the EVD for the disc.
2173  */
2174 LOCAL int
evd_write(outfile)2175 evd_write(outfile)
2176 	FILE	*outfile;
2177 {
2178 	struct iso_primary_descriptor evol_desc;
2179 
2180 	/*
2181 	 * Now write the end volume descriptor.  Much simpler than the other
2182 	 * one
2183 	 */
2184 	memset(&evol_desc, 0, sizeof (evol_desc));
2185 	evol_desc.type[0] = (unsigned char) ISO_VD_END;
2186 	strncpy(evol_desc.id, ISO_STANDARD_ID, sizeof (evol_desc.id));
2187 	evol_desc.version[0] = 1;
2188 	xfwrite(&evol_desc, SECTOR_SIZE, 1, outfile, 0, TRUE);
2189 	last_extent_written += 1;
2190 	return (0);
2191 }
2192 
2193 /*
2194  * Function to write the version information for the disc.
2195  * Warning: Do not disable or change this function. The data created by this
2196  * function is used to tell the filesystem driver in the OS kernel that this
2197  * mkisofs version includes correct inode information.
2198  */
2199 LOCAL int
vers_write(outfile)2200 vers_write(outfile)
2201 	FILE	*outfile;
2202 {
2203 	char		vers[SECTOR_SIZE+1];
2204 	int		X_ac;
2205 	char		**X_av;
2206 	char		*cp;
2207 	int		i;
2208 	int		idx = 4;
2209 	int		len;
2210 	extern char	version_string[];
2211 	extern int	path_ind;
2212 
2213 	/* Now write the version descriptor. */
2214 	memset(vers, 0, sizeof (vers));
2215 	strcpy(vers, "MKI ");			/* strcpy() OK here */
2216 
2217 	cp = vers;
2218 	X_ac = saved_ac();
2219 	X_av = saved_av();
2220 	strlcpy(&cp[idx], ctime(&begun), 26);
2221 	idx += 25;
2222 	strlcpy(&cp[idx], version_string, SECTOR_SIZE - idx);
2223 	idx += strlen(version_string);
2224 	for (i = 1; i < X_ac; i++) {
2225 		len = strlen(X_av[i]);
2226 		if ((idx + len + 2) >= SECTOR_SIZE)
2227 			break;
2228 		cp[idx++] = ' ';
2229 		/*
2230 		 * Do not give away secret information when not in debug mode.
2231 		 */
2232 		if (debug)
2233 			strlcpy(&cp[idx], X_av[i], SECTOR_SIZE - idx);
2234 		else if (i >= path_ind)
2235 			len = graftcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2236 		else if (X_av[i][0] == '/')
2237 			len = pathcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2238 		else
2239 			strlcpy(&cp[idx], X_av[i], SECTOR_SIZE - idx);
2240 		idx += len;
2241 	}
2242 
2243 	cp[SECTOR_SIZE - 1] = '\0';
2244 	len = 0;
2245 	if (correct_inodes) {
2246 		/*
2247 		 * Only add this fingerprint in case we include correct
2248 		 * inode/link-count information in the current image.
2249 		 */
2250 		len = vol_desc_sum;
2251 	}
2252 	cp = &vers[SECTOR_SIZE - 1];
2253 	*(Uchar *)cp = len % 256;
2254 	len /= 256;
2255 	*(Uchar *)--cp = len % 256;
2256 	len /= 256;
2257 	*(Uchar *)--cp = len % 256;
2258 
2259 	xfwrite(vers, SECTOR_SIZE, 1, outfile, 0, TRUE);
2260 	last_extent_written += 1;
2261 	return (0);
2262 }
2263 
2264 /*
2265  * Avoid to write unwanted information into the version info string.
2266  */
2267 LOCAL int
graftcp(to,from,ep)2268 graftcp(to, from, ep)
2269 	char	*to;
2270 	char	*from;
2271 	char	*ep;
2272 {
2273 	int	len = strlen(from);
2274 	char	*node = NULL;
2275 
2276 	if (use_graft_ptrs)
2277 		node = findgequal(from);
2278 
2279 	if (node == NULL) {
2280 		len = 0;
2281 		node = from;
2282 	} else {
2283 		len = node - from;
2284 		*node = '\0';
2285 		strncpy(to, from, ep - to);
2286 		*node++ = '=';
2287 		to += len++;
2288 		*to++ = '=';
2289 	}
2290 	return (len + pathcp(to, node, ep));
2291 }
2292 
2293 LOCAL int
pathcp(to,from,ep)2294 pathcp(to, from, ep)
2295 	char	*to;
2296 	char	*from;
2297 	char	*ep;
2298 {
2299 	int	len = strlen(from);
2300 	char	*p;
2301 
2302 	p = strrchr(from, '/');
2303 	if (p == NULL) {
2304 		strncpy(to, from, ep - to);
2305 	} else {
2306 		if (p[1] == '\0') {
2307 			--p;
2308 			while (p > from && *p != '/')
2309 				--p;
2310 		}
2311 		len = 0;
2312 		if (*p == '/') {
2313 			strncpy(to, "...", ep - to);
2314 			to += 3;
2315 			len = 3;
2316 		}
2317 		if (to < ep) {
2318 			strncpy(to, p, ep - to);
2319 			len += strlen(to);
2320 		}
2321 	}
2322 	return (len);
2323 }
2324 
2325 
2326 /*
2327  * Function to write the path table for the disc.
2328  */
2329 LOCAL int
pathtab_write(outfile)2330 pathtab_write(outfile)
2331 	FILE	*outfile;
2332 {
2333 	/* Next we write the path tables */
2334 	xfwrite(path_table_l, path_blocks << 11, 1, outfile, 0, FALSE);
2335 	xfwrite(path_table_m, path_blocks << 11, 1, outfile, 0, FALSE);
2336 	last_extent_written += 2 * path_blocks;
2337 	free(path_table_l);
2338 	free(path_table_m);
2339 	path_table_l = NULL;
2340 	path_table_m = NULL;
2341 	return (0);
2342 }
2343 
2344 LOCAL int
exten_write(outfile)2345 exten_write(outfile)
2346 	FILE	*outfile;
2347 {
2348 	xfwrite(extension_record, SECTOR_SIZE, 1, outfile, 0, FALSE);
2349 	last_extent_written++;
2350 	return (0);
2351 }
2352 
2353 /*
2354  * Functions to describe padding block at the start of the disc.
2355  */
2356 EXPORT int
oneblock_size(starting_extent)2357 oneblock_size(starting_extent)
2358 	UInt32_t	starting_extent;
2359 {
2360 	last_extent++;
2361 	return (0);
2362 }
2363 
2364 /*
2365  * Functions to describe path table size.
2366  */
2367 LOCAL int
pathtab_size(starting_extent)2368 pathtab_size(starting_extent)
2369 	UInt32_t	starting_extent;
2370 {
2371 	path_table[0] = starting_extent;
2372 
2373 	path_table[1] = 0;
2374 	path_table[2] = path_table[0] + path_blocks;
2375 	path_table[3] = 0;
2376 	last_extent += 2 * path_blocks;
2377 	return (0);
2378 }
2379 
2380 /*
2381  * Functions to describe padding blocks before PVD.
2382  */
2383 LOCAL int
startpad_size(starting_extent)2384 startpad_size(starting_extent)
2385 	UInt32_t	starting_extent;
2386 {
2387 	last_extent = session_start + 16;
2388 	return (0);
2389 }
2390 
2391 /*
2392  * Functions to describe padding blocks between sections.
2393  */
2394 LOCAL int
interpad_size(starting_extent)2395 interpad_size(starting_extent)
2396 	UInt32_t	starting_extent;
2397 {
2398 	int	emod = 0;
2399 
2400 #ifdef	needed
2401 	starting_extent += 16;	/* First add 16 pad blocks */
2402 #endif
2403 	if ((emod = starting_extent % 16) != 0) {
2404 		starting_extent += 16 - emod;	/* Now pad to mod 16 #	   */
2405 	}
2406 	last_extent = starting_extent;
2407 	return (0);
2408 }
2409 
2410 /*
2411  * Functions to describe padding blocks at end of disk.
2412  */
2413 LOCAL int
endpad_size(starting_extent)2414 endpad_size(starting_extent)
2415 	UInt32_t	starting_extent;
2416 {
2417 	starting_extent += 150;			/* 150 pad blocks (post gap) */
2418 	last_extent = starting_extent;
2419 	return (0);
2420 }
2421 
2422 LOCAL int
file_gen()2423 file_gen()
2424 {
2425 #ifdef APPLE_HYB
2426 	UInt32_t	start_extent = last_extent;	/* orig ISO files start */
2427 
2428 #endif	/* APPLE_HYB */
2429 
2430 	if (!assign_file_addresses(root, FALSE)) {
2431 #ifdef DVD_AUD_VID
2432 		if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
2433 			comerrno(EX_BAD, _("Unable to make a DVD-Video image.\n"));
2434 		}
2435 #else
2436 		;
2437 		/* EMPTY */
2438 #endif
2439 	}
2440 
2441 
2442 #ifdef SORTING
2443 	if (do_sort) {
2444 		if (sort_file_addresses() == 0)
2445 			reassign_link_addresses(root);
2446 	}
2447 #endif /* SORTING */
2448 
2449 #ifdef APPLE_HYB
2450 	/*
2451 	 * put this here for the time being - may when I've worked out how to
2452 	 * use Eric's new system for creating/writing parts of the image it
2453 	 * may move to it's own routine
2454 	 */
2455 	if (apple_hyb && !donotwrite_macpart)
2456 		hfs_file_gen(start_extent);
2457 #ifdef PREP_BOOT
2458 	else if (use_prep_boot || use_chrp_boot)
2459 		gen_prepboot();
2460 #endif	/* PREP_BOOT */
2461 #endif	/* APPLE_HYB */
2462 
2463 	/*
2464 	 * Do inode/hard link related stuff for non-directory type files.
2465 	 */
2466 	do_inode(root);
2467 	return (0);
2468 }
2469 
2470 LOCAL int
dirtree_dump()2471 dirtree_dump()
2472 {
2473 	if (verbose > 2) {
2474 		dump_tree(root);
2475 	}
2476 	return (0);
2477 }
2478 
2479 LOCAL int
dirtree_fixup(starting_extent)2480 dirtree_fixup(starting_extent)
2481 	UInt32_t	starting_extent;
2482 {
2483 	if (use_RockRidge && reloc_dir)
2484 		finish_cl_pl_entries();
2485 
2486 	/*
2487 	 * Set the link count for directories to 2 + number of sub-directories.
2488 	 */
2489 	if (use_RockRidge)
2490 		do_dir_nlink(root);
2491 	return (0);
2492 }
2493 
2494 LOCAL int
dirtree_size(starting_extent)2495 dirtree_size(starting_extent)
2496 	UInt32_t	starting_extent;
2497 {
2498 	assign_directory_addresses(root);
2499 	return (0);
2500 }
2501 
2502 LOCAL int
ext_size(starting_extent)2503 ext_size(starting_extent)
2504 	UInt32_t	starting_extent;
2505 {
2506 	extern int		extension_record_size;
2507 	struct directory_entry *s_entry;
2508 
2509 	extension_record_extent = starting_extent;
2510 	s_entry = root->contents;
2511 	set_733((char *)s_entry->rr_attributes + s_entry->rr_attr_size - 24,
2512 		extension_record_extent);
2513 	set_733((char *)s_entry->rr_attributes + s_entry->rr_attr_size - 8,
2514 		extension_record_size);
2515 	last_extent++;
2516 	return (0);
2517 }
2518 
2519 LOCAL int
dirtree_write(outfile)2520 dirtree_write(outfile)
2521 	FILE	*outfile;
2522 {
2523 	generate_iso9660_directories(root, outfile);
2524 	return (0);
2525 }
2526 
2527 LOCAL int
dirtree_cleanup(outfile)2528 dirtree_cleanup(outfile)
2529 	FILE	*outfile;
2530 {
2531 	free_directories(root);
2532 	return (0);
2533 }
2534 
2535 LOCAL int
startpad_write(outfile)2536 startpad_write(outfile)
2537 	FILE	*outfile;
2538 {
2539 	char	buffer[SECTOR_SIZE];
2540 	int	i;
2541 	int	npad;
2542 
2543 	memset(buffer, 0, sizeof (buffer));
2544 
2545 	npad = session_start + 16 - last_extent_written;
2546 
2547 	for (i = 0; i < npad; i++) {
2548 		xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2549 	}
2550 
2551 	last_extent_written += npad;
2552 	return (0);
2553 }
2554 
2555 LOCAL int
interpad_write(outfile)2556 interpad_write(outfile)
2557 	FILE	*outfile;
2558 {
2559 	char	buffer[SECTOR_SIZE];
2560 	int	i;
2561 	int	npad = 0;
2562 
2563 	memset(buffer, 0, sizeof (buffer));
2564 
2565 #ifdef	needed
2566 	npad = 16;
2567 #endif
2568 	if ((i = last_extent_written % 16) != 0)
2569 		npad += 16 - i;
2570 
2571 	for (i = 0; i < npad; i++) {
2572 		xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2573 	}
2574 
2575 	last_extent_written += npad;
2576 	return (0);
2577 }
2578 
2579 LOCAL int
endpad_write(outfile)2580 endpad_write(outfile)
2581 	FILE	*outfile;
2582 {
2583 	char	buffer[SECTOR_SIZE];
2584 	int	i;
2585 
2586 	memset(buffer, 0, sizeof (buffer));
2587 
2588 	for (i = 0; i < 150; i++) {
2589 		xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2590 	}
2591 
2592 	last_extent_written += 150;
2593 	return (0);
2594 }
2595 
2596 #ifdef APPLE_HYB
2597 
2598 /*
2599  *	hfs_get_parms:	get HFS parameters from the command line
2600  */
2601 
2602 LOCAL int
hfs_get_parms(key)2603 hfs_get_parms(key)
2604 	char	*key;
2605 {
2606 	int	ret = 0;
2607 	char	*p;
2608 
2609 	if (hfs_parms == NULL)
2610 		return (ret);
2611 
2612 	if ((p = strstr(hfs_parms, key)) != NULL) {
2613 		p += strlen(key) + 1;
2614 		sscanf(p, "%d", &ret);
2615 	}
2616 
2617 	return (ret);
2618 }
2619 
2620 /*
2621  *	hfs_file_gen:	set up "fake" HFS volume using the ISO9660 tree
2622  */
2623 LOCAL void
hfs_file_gen(start_extent)2624 hfs_file_gen(start_extent)
2625 	UInt32_t	start_extent;
2626 {
2627 	int	Csize;	/* clump size for HFS vol */
2628 	int	loop;
2629 	UInt32_t last_extent_save = last_extent;
2630 	char	*p;
2631 
2632 	/* allocate memory for the libhfs/mkisofs extra info */
2633 	hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2634 
2635 	hce->error = (char *)e_malloc(1024);
2636 
2637 	/* mark as unallocated for use later */
2638 	hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2639 
2640 	/* reserve space for the label partition - if it is needed */
2641 #ifdef PREP_BOOT
2642 	/* a PReP bootable partition needs the map.. */
2643 	if (gen_pt || use_prep_boot || use_chrp_boot)
2644 #else
2645 	if (gen_pt)
2646 #endif	/* PREP_BOOT */
2647 		hce->hfs_map_size = HFS_MAP_SIZE;
2648 	else
2649 		hce->hfs_map_size = 0;
2650 
2651 	/* set the HFS parameter string to upper case */
2652 	if (hfs_parms) {
2653 		for (p = hfs_parms; *p; p++)
2654 			*p = toupper((*p & 0xFF));
2655 	}
2656 
2657 	/* set the initial factor to increase Catalog file size */
2658 	if ((hce->ctc_size = hfs_get_parms("CTC")) == 0)
2659 		hce->ctc_size = CTC;
2660 
2661 	/* set the max size of the Catalog file */
2662 	if ((hce->max_XTCsize = hfs_get_parms("MAX_XTCSIZE")) == 0)
2663 		hce->max_XTCsize = MAX_XTCSIZE;
2664 
2665 	/* set the number of time to try to make an HFS volume */
2666 	if ((loop = hfs_get_parms("CTC_LOOP")) == 0)
2667 		loop = CTC_LOOP;
2668 
2669 	/*
2670 	 * "create" the HFS volume (just the header, catalog/extents files) if
2671 	 * there's a problem with the Catalog file being too small, we keep on
2672 	 * increasing the size (up to CTC_LOOP) times and try again.
2673 	 * Unfortunately I don't know enough about the inner workings of HFS,
2674 	 * so I can't workout the size of the Catalog file in advance (and I
2675 	 * don't want to "grow" as is is normally allowed to), therefore, this
2676 	 * approach is a bit over the top as it involves throwing away the
2677 	 * "volume" we have created and trying again ...
2678 	 */
2679 	do {
2680 		hce->error[0] = '\0';
2681 
2682 		/* attempt to create the Mac volume */
2683 #ifdef APPLE_HFS_HYB
2684 		Csize = make_mac_volume(root, start_extent);
2685 #else
2686 		Csize = -1;
2687 #endif
2688 
2689 		/* if we have a problem ... */
2690 		if (Csize < 0) {
2691 			/*
2692 			 * we've made too many attempts, or got some other
2693 			 * error
2694 			 */
2695 			if (loop == 0 || errno != HCE_ERROR) {
2696 				/* HCE_ERROR is not a valid errno value */
2697 				if (errno == HCE_ERROR)
2698 					errno = 0;
2699 
2700 				/* exit with the error */
2701 				if (*hce->error)
2702 					fprintf(stderr, "%s\n", hce->error);
2703 				perr(hfs_error);
2704 			} else {
2705 				/* increase Catalog file size factor */
2706 				hce->ctc_size *= CTC;
2707 
2708 				/*
2709 				 * reset the initial "last_extent" and try
2710 				 * again
2711 				 */
2712 				last_extent = last_extent_save;
2713 			}
2714 		} else {
2715 			/* everything OK - just carry on ... */
2716 			loop = 0;
2717 		}
2718 	}
2719 	while (loop--);
2720 
2721 	hfs_extra = HFS_ROUND_UP(hce->hfs_tot_size) / SECTOR_SIZE;
2722 
2723 	last_extent += hfs_extra;
2724 
2725 	/* generate the Mac label and HFS partition maps */
2726 	mac_boot.name = hfs_boot_file;
2727 
2728 	/*
2729 	 * only generate the partition tables etc. if we are making a bootable
2730 	 * CD - or if the -part option is given
2731 	 */
2732 	if (gen_pt) {
2733 		if (gen_mac_label(&mac_boot)) {
2734 			if (*hce->error)
2735 				fprintf(stderr, "%s\n", hce->error);
2736 			perr(hfs_error);
2737 		}
2738 	}
2739 	/* set Autostart filename if required */
2740 	if (autoname) {
2741 		if (autostart())
2742 			perr("Autostart filename must less than 12 characters");
2743 	}
2744 	/* finished with any HFS type errors */
2745 	free(hce->error);
2746 	hce->error = 0;
2747 
2748 	/*
2749 	 * the ISO files need to start on a multiple of the HFS allocation
2750 	 * blocks, so find out how much padding we need
2751 	 */
2752 
2753 	/*
2754 	 * take in accout alignment of files wrt HFS volume start - remove any
2755 	 * previous session as well
2756 	 */
2757 	start_extent -= session_start;
2758 	hfs_pad = ROUND_UP(start_extent*SECTOR_SIZE +
2759 			(hce->hfs_hdr_size + hce->hfs_map_size) * HFS_BLOCKSZ,
2760 							Csize) / SECTOR_SIZE;
2761 
2762 	hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size) /
2763 							HFS_BLK_CONV);
2764 
2765 #ifdef PREP_BOOT
2766 	gen_prepboot_label(hce->hfs_map);
2767 #endif	/* PREP_BOOT */
2768 
2769 }
2770 
2771 #ifdef PREP_BOOT
2772 LOCAL void
gen_prepboot()2773 gen_prepboot()
2774 {
2775 	/*
2776 	 * we need to allocate the hce struct since hce->hfs_map is used to
2777 	 * generate the fdisk partition map required for PReP booting
2778 	 */
2779 	hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2780 
2781 	/* mark as unallocated for use later */
2782 	hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2783 
2784 	/* reserve space for the label partition - if it is needed */
2785 	hce->hfs_map_size = HFS_MAP_SIZE;
2786 
2787 	hce->hfs_map = (unsigned char *) e_malloc(hce->hfs_map_size * HFS_BLOCKSZ);
2788 	gen_prepboot_label(hce->hfs_map);
2789 }
2790 
2791 #endif	/* PREP_BOOT */
2792 
2793 /*
2794  *	get_adj_size:	get the ajusted size of the volume with the HFS
2795  *			allocation block size for each file
2796  */
2797 EXPORT Ulong
get_adj_size(Csize)2798 get_adj_size(Csize)
2799 	int	Csize;
2800 {
2801 	struct deferred_write *dw;
2802 	Ulong		size = 0;
2803 	int		count = 0;
2804 
2805 	/* loop through all the files finding the new total size */
2806 	for (dw = dw_head; dw; dw = dw->next) {
2807 		size += (ROUND_UP(dw->size, Csize)/HFS_BLOCKSZ);
2808 		count++;
2809 	}
2810 
2811 	/*
2812 	 * crude attempt to prevent overflows - HFS can only cope with a
2813 	 * maximum of about 65536 forks (actually less) - this will trap cases
2814 	 * when we have far too many files
2815 	 */
2816 
2817 	if (count >= 65536)
2818 		return (-1);
2819 	else
2820 		return (size);
2821 }
2822 
2823 /*
2824  *	adj_size:	adjust the ISO record entries for all files
2825  *			based on the HFS allocation block size
2826  */
2827 EXPORT int
adj_size(Csize,start_extent,extra)2828 adj_size(Csize, start_extent, extra)
2829 	int	Csize;
2830 	UInt32_t	start_extent;
2831 	int	extra;
2832 {
2833 	struct deferred_write *dw;
2834 	struct directory_entry *s_entry;
2835 	int		size;
2836 
2837 	/* get the adjusted start_extent (with padding) */
2838 	/* take in accout alignment of files wrt HFS volume start */
2839 
2840 	start_extent -= session_start;
2841 
2842 	start_extent = ROUND_UP(start_extent*SECTOR_SIZE + extra*HFS_BLOCKSZ,
2843 						Csize) / SECTOR_SIZE;
2844 
2845 	start_extent -= (extra / HFS_BLK_CONV);
2846 
2847 	start_extent += session_start;
2848 
2849 	/* initialise file hash */
2850 	flush_hash();
2851 
2852 	/*
2853 	 * loop through all files changing their starting blocks and finding
2854 	 * any padding needed to written out latter
2855 	 */
2856 	for (dw = dw_head; dw; dw = dw->next) {
2857 		s_entry = dw->s_entry;
2858 		s_entry->starting_block = dw->extent = start_extent;
2859 		set_733((char *)s_entry->isorec.extent, start_extent);
2860 		size = ROUND_UP(dw->size, Csize) / SECTOR_SIZE;
2861 		dw->pad = size - ISO_ROUND_UP(dw->size) / SECTOR_SIZE;
2862 
2863 		/*
2864 		 * cache non-HFS files - as there may be multiple links to
2865 		 * these files (HFS files can't have multiple links). We will
2866 		 * need to change the starting extent of the other links later
2867 		 */
2868 		if (!s_entry->hfs_ent)
2869 			add_hash(s_entry);
2870 
2871 		start_extent += size;
2872 	}
2873 
2874 	return (start_extent);
2875 }
2876 
2877 /*
2878  *	adj_size_other:	adjust any non-HFS files that may be linked
2879  *			to an existing file (i.e. not have a deferred_write
2880  *			entry of it's own
2881  */
2882 EXPORT void
adj_size_other(dpnt)2883 adj_size_other(dpnt)
2884 	struct directory	*dpnt;
2885 {
2886 	struct directory_entry *s_entry;
2887 	struct file_hash *s_hash;
2888 
2889 	while (dpnt) {
2890 		s_entry = dpnt->contents;
2891 		for (s_entry = dpnt->contents; s_entry;
2892 						s_entry = s_entry->next) {
2893 			/*
2894 			 * if it's an HFS file or a directory - then ignore
2895 			 * (we're after non-HFS files)
2896 			 */
2897 			if (s_entry->hfs_ent ||
2898 			    (s_entry->isorec.flags[0] & ISO_DIRECTORY))
2899 				continue;
2900 
2901 			/*
2902 			 * find any cached entry and assign new starting
2903 			 * extent
2904 			 */
2905 			s_hash = find_hash(s_entry);
2906 			if (s_hash) {
2907 				set_733((char *)s_entry->isorec.extent,
2908 						s_hash->starting_block);
2909 				/* not vital - but tidy */
2910 				s_entry->starting_block =
2911 							s_hash->starting_block;
2912 			}
2913 		}
2914 		if (dpnt->subdir) {
2915 			adj_size_other(dpnt->subdir);
2916 		}
2917 		dpnt = dpnt->next;
2918 	}
2919 
2920 	/* clear file hash */
2921 	flush_hash();
2922 }
2923 
2924 /*
2925  *	hfs_hce_write:	write out the HFS header stuff
2926  */
2927 LOCAL int
hfs_hce_write(outfile)2928 hfs_hce_write(outfile)
2929 	FILE	*outfile;
2930 {
2931 	char	buffer[SECTOR_SIZE];
2932 	int	n = 0;
2933 	int	r;	/* HFS hdr output */
2934 	int	tot_size = hce->hfs_map_size + hce->hfs_hdr_size;
2935 
2936 	memset(buffer, 0, sizeof (buffer));
2937 
2938 	/*
2939 	 * hack time ... if the tot_size is greater than 32Kb then
2940 	 * it won't fit in the first 16 blank SECTORS (64 512 byte
2941 	 * blocks, as most of this is padding, we just truncate this
2942 	 * data to 64x4xHFS_BLOCKSZ ... hope this is OK ...
2943 	 */
2944 
2945 	if (tot_size > 64) tot_size = 64;
2946 
2947 	/* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */
2948 	n = tot_size / HFS_BLK_CONV;
2949 	r = tot_size % HFS_BLK_CONV;
2950 
2951 	/* write out HFS volume header info */
2952 	xfwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, outfile, 0, FALSE);
2953 
2954 	/* fill up to a complete CD block */
2955 	if (r) {
2956 		xfwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, outfile, 0, FALSE);
2957 		n++;
2958 	}
2959 	last_extent_written += n;
2960 	return (0);
2961 }
2962 
2963 /*
2964  *	insert_padding_file : insert a dumy file to make volume at least
2965  *				800k
2966  *
2967  *	XXX If we ever need to write more then 2 GB, make size off_t
2968  */
2969 EXPORT int
insert_padding_file(size)2970 insert_padding_file(size)
2971 	int	size;
2972 {
2973 	struct deferred_write *dwpnt;
2974 
2975 	/* get the size in bytes */
2976 	size *= HFS_BLOCKSZ;
2977 
2978 	dwpnt = (struct deferred_write *)
2979 		e_malloc(sizeof (struct deferred_write));
2980 	dwpnt->s_entry = 0;
2981 	/* set the padding to zero */
2982 	dwpnt->pad = 0;
2983 	/* set offset to zero */
2984 	dwpnt->off = (off_t)0;
2985 	dwpnt->dw_flags = 0;
2986 #ifdef	APPLE_HYB
2987 	dwpnt->hfstype = TYPE_NONE;
2988 #endif
2989 
2990 	/*
2991 	 * don't need to wory about the s_entry stuff as it won't be touched#
2992 	 * at this point onwards
2993 	 */
2994 
2995 	/* insert the entry in the list */
2996 	if (dw_tail) {
2997 		dw_tail->next = dwpnt;
2998 		dw_tail = dwpnt;
2999 	} else {
3000 		dw_head = dwpnt;
3001 		dw_tail = dwpnt;
3002 	}
3003 
3004 	/* aloocate memory as a "Table" file */
3005 	dwpnt->table = e_malloc(size);
3006 	dwpnt->name = NULL;
3007 
3008 	dwpnt->next = NULL;
3009 	dwpnt->size = size;
3010 	dwpnt->extent = last_extent;
3011 	last_extent += ISO_BLOCKS(size);
3012 
3013 	/* retune the size in HFS blocks */
3014 	return (ISO_ROUND_UP(size) / HFS_BLOCKSZ);
3015 }
3016 
3017 struct output_fragment hfs_desc		= {NULL, NULL, NULL, hfs_hce_write, "HFS volume header"};
3018 
3019 #endif	/* APPLE_HYB */
3020 
3021 struct output_fragment startpad_desc	= {NULL, startpad_size,	NULL,	  startpad_write, "Initial Padblock"};
3022 struct output_fragment voldesc_desc	= {NULL, oneblock_size,	root_gen, pvd_write,	  "Primary Volume Descriptor"};
3023 struct output_fragment xvoldesc_desc	= {NULL, oneblock_size,	NULL,	  xpvd_write,	  "Enhanced Volume Descriptor"};
3024 struct output_fragment end_vol		= {NULL, oneblock_size,	NULL,	  evd_write,	  "End Volume Descriptor" };
3025 struct output_fragment version_desc	= {NULL, oneblock_size,	NULL,	  vers_write,	  "Version block" };
3026 struct output_fragment pathtable_desc	= {NULL, pathtab_size,	generate_path_tables, pathtab_write, "Path table"};
3027 struct output_fragment dirtree_desc	= {NULL, dirtree_size,	NULL,	  dirtree_write,  "Directory tree" };
3028 struct output_fragment dirtree_clean	= {NULL, dirtree_fixup,	dirtree_dump, dirtree_cleanup, "Directory tree cleanup" };
3029 struct output_fragment extension_desc	= {NULL, ext_size,	NULL,	  exten_write,	  "Extension record" };
3030 struct output_fragment files_desc	= {NULL, NULL,		file_gen, file_write,	  "The File(s)"};
3031 struct output_fragment interpad_desc	= {NULL, interpad_size,	NULL,	  interpad_write, "Intermediate Padblock"};
3032 struct output_fragment endpad_desc	= {NULL, endpad_size,	NULL,	  endpad_write,	  "Ending Padblock"};
3033