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