1 /* @(#)joliet.c	1.71 18/04/04 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)joliet.c	1.71 18/04/04 joerg";
6 #endif
7 /*
8  * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
9  *
10  * Copyright 1997 Eric Youngdale.
11  * APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000
12  * Copyright (c) 1999-2018 J. Schilling
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  */
28 
29 /*
30  * Joliet extensions for ISO9660.  These are spottily documented by
31  * Microsoft.  In their infinite stupidity, they completely ignored
32  * the possibility of using an SUSP record with the long filename
33  * in it, and instead wrote out a duplicate directory tree with the
34  * long filenames in it.
35  *
36  * I am not sure why they did this.  One reason is that they get the path
37  * tables with the long filenames in them.
38  *
39  * There are two basic principles to Joliet, and the non-Unicode variant
40  * known as Romeo.  Long filenames seem to be the main one, and the second
41  * is that the character set and a few other things is substantially relaxed.
42  *
43  * The SVD is identical to the PVD, except:
44  *
45  *	Id is 2, not 1 (indicates SVD).
46  *	escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
47  *	The root directory record points to a different extent (with different
48  *		size).
49  *	There are different path tables for the two sets of directory trees.
50  *
51  * The Unicode level is coded in the SVD as follows:
52  *
53  *	Standard	Level	ASCII escape code
54  *	UCS-2		Level-1	%/@
55  *	UCS-2		Level-2	%/C
56  *	UCS-2		Level-3	%/E
57  *
58  * The following fields are recorded in Unicode:
59  *	system_id
60  *	volume_id
61  *	volume_set_id
62  *	publisher_id
63  *	preparer_id
64  *	application_id
65  *	copyright_file_id
66  *	abstract_file_id
67  *	bibliographic_file_id
68  *
69  * Unicode strings are always encoded in big-endian format.
70  *
71  * In a directory record, everything is the same as with iso9660, except
72  * that the name is recorded in unicode.  The name length is specified in
73  * total bytes, not in number of unicode characters.
74  *
75  * The character set used for the names is different with UCS - the
76  * restrictions are that the following are not allowed:
77  *
78  *	Characters (00)(00) through (00)(1f) (control chars)
79  *	(00)(2a) '*'
80  *	(00)(2f) '/'
81  *	(00)(3a) ':'
82  *	(00)(3b) ';'
83  *	(00)(3f) '?'
84  *	(00)(5c) '\'
85  */
86 #include "mkisofs.h"
87 #include <schily/time.h>
88 #include <schily/utypes.h>
89 #include <schily/intcvt.h>
90 #include <schily/schily.h>
91 #include <schily/errno.h>
92 
93 LOCAL	Uint		jpath_table_index;
94 LOCAL	struct directory **jpathlist;
95 LOCAL	int		next_jpath_index = 1;
96 LOCAL	int		jsort_goof;
97 LOCAL	int		jsort_glen;
98 
99 LOCAL	char	ucs_codes[] = {
100 		'\0',		/* UCS-level 0 is illegal	*/
101 		'@',		/* UCS-level 1			*/
102 		'C',		/* UCS-level 2			*/
103 		'E',		/* UCS-level 3			*/
104 };
105 
106 #ifdef	UDF
107 EXPORT	void	convert_to_unicode	__PR((unsigned char *buffer,
108 						int size, char *source,
109 						siconvt_t *inls));
110 EXPORT	int	joliet_strlen		__PR((const char *string, size_t maxlen,
111 						siconvt_t *inls));
112 #else
113 LOCAL	void	convert_to_unicode	__PR((unsigned char *buffer,
114 						int size, char *source,
115 						siconvt_t *inls));
116 LOCAL	int	joliet_strlen		__PR((const char *string, size_t maxlen,
117 						siconvt_t *inls));
118 #endif
119 LOCAL	void	get_joliet_vol_desc	__PR((struct iso_primary_descriptor *jvol_desc));
120 LOCAL	void	assign_joliet_directory_addresses __PR((struct directory *node));
121 LOCAL	void	build_jpathlist		__PR((struct directory *node));
122 LOCAL	int	joliet_compare_paths	__PR((void const *r, void const *l));
123 LOCAL	int	generate_joliet_path_tables __PR((void));
124 LOCAL	void	generate_one_joliet_directory __PR((struct directory *dpnt,
125 						FILE *outfile));
126 LOCAL	int	joliet_sort_n_finish	__PR((struct directory *this_dir));
127 
128 LOCAL	int	joliet_compare_dirs	__PR((const void *rr, const void *ll));
129 
130 LOCAL	int	joliet_sort_directory	__PR((struct directory_entry **sort_dir));
131 EXPORT	int	joliet_sort_tree	__PR((struct directory *node));
132 LOCAL	void	generate_joliet_directories __PR((struct directory *node,
133 						FILE *outfile));
134 LOCAL	int	jpathtab_write		__PR((FILE *outfile));
135 LOCAL	int	jdirtree_size		__PR((UInt32_t starting_extent));
136 LOCAL	int	jroot_gen		__PR((void));
137 LOCAL	int	jdirtree_write		__PR((FILE *outfile));
138 LOCAL	int	jvd_write		__PR((FILE *outfile));
139 LOCAL	int	jpathtab_size		__PR((UInt32_t starting_extent));
140 
141 /*
142  *	conv_charset: convert to/from charsets via Unicode.
143  *
144  *	Any unknown character is set to '_'
145  *
146  */
147 EXPORT void
conv_charset(to,tosizep,from,fromsizep,inls,onls)148 conv_charset(to, tosizep, from, fromsizep, inls, onls)
149 	unsigned char	*to;
150 	size_t		*tosizep;
151 	unsigned char	*from;
152 	size_t		*fromsizep;
153 	siconvt_t	*inls;
154 	siconvt_t	*onls;
155 {
156 	UInt16_t	unichar;
157 	size_t		fromsize = *fromsizep;
158 	size_t		tosize   = *tosizep;
159 	Uchar		ob[2];			/* 2 octets (16 Bit) UCS-2 */
160 
161 	if (fromsize == 0 || tosize == 0)
162 		return;
163 
164 	/*
165 	 * If we have a null mapping, just return the input character
166 	 */
167 	if (inls->sic_name == onls->sic_name) {
168 		*to = *from;
169 		(*fromsizep)--;
170 		(*tosizep)--;
171 		return;
172 	}
173 #ifdef	USE_ICONV
174 #ifdef	HAVE_ICONV_CONST
175 #define	__IC_CONST	const
176 #else
177 #define	__IC_CONST
178 #endif
179 	if (use_iconv(inls)) {
180 		char	*obuf = (char *)ob;
181 		size_t	osize = 2;		/* UCS-2 character size */
182 
183 		if (iconv(inls->sic_cd2uni, (__IC_CONST char **)&from,
184 					fromsizep,
185 					&obuf, &osize) == -1) {
186 			int	err = geterrno();
187 
188 			if ((err == EINVAL || err == EILSEQ) &&
189 			    *fromsizep == fromsize) {
190 				ob[0] = 0; ob[1] = '_';
191 				(*fromsizep)--;
192 			}
193 		}
194 		unichar = ob[0] * 256 + ob[1];	/* Compute 16 Bit UCS-2 char */
195 	} else
196 #endif
197 	{
198 		unsigned char c = *from;
199 
200 		unichar = sic_c2uni(inls, c);	/* Get the UNICODE char */
201 		(*fromsizep)--;
202 
203 		if (unichar == 0)
204 			unichar = '_';
205 
206 		ob[0] = unichar >> 8 & 0xFF;	/* Compute 2 octet variant */
207 		ob[1] = unichar & 0xFF;
208 	}
209 
210 #ifdef	USE_ICONV
211 	if (use_iconv(onls)) {
212 		char	*ibuf = (char *)ob;
213 		size_t	isize = 2;		/* UCS-2 character size */
214 
215 		if (iconv(onls->sic_uni2cd, (__IC_CONST char **)&ibuf, &isize,
216 					(char **)&to, tosizep) == -1) {
217 			int	err = geterrno();
218 
219 			if ((err == EINVAL || err == EILSEQ) &&
220 			    *tosizep == tosize) {
221 				*to = '_';
222 				(*tosizep)--;
223 			}
224 		}
225 	} else
226 #endif
227 	{
228 		*to = sic_uni2c(onls, unichar);	/* Get the backconverted char */
229 		(*tosizep)--;
230 	}
231 }
232 
233 
234 /*
235  * Function:		convert_to_unicode
236  *
237  * Purpose:		Perform a unicode conversion on a text string
238  *			using the supplied input character set.
239  *
240  * Notes:
241  */
242 #ifdef	UDF
243 EXPORT void
244 #else
245 LOCAL void
246 #endif
convert_to_unicode(buffer,size,source,inls)247 convert_to_unicode(buffer, size, source, inls)
248 	unsigned char	*buffer;
249 	int		size;
250 	char		*source;
251 	siconvt_t	*inls;
252 {
253 	unsigned char	*tmpbuf;
254 	int		i;
255 	int		j;
256 	UInt16_t	unichar;
257 	unsigned char	uc;
258 	int		jsize;
259 
260 	/*
261 	 * If we get a NULL pointer for the source, it means we have an
262 	 * inplace copy, and we need to make a temporary working copy first.
263 	 */
264 	if (source == NULL) {
265 		tmpbuf = (Uchar *) e_malloc(size);
266 		memcpy(tmpbuf, buffer, size);
267 	} else {
268 		tmpbuf = (Uchar *) source;
269 	}
270 
271 	/*
272 	 * joliet_strlen() behaves the same way: Stop at the first nul byte.
273 	 * Note: we cannot have 16 bit character representations in the source
274 	 * encoding, if we like strlen() to work correctly.
275 	 */
276 	jsize = strlen((char *)tmpbuf);
277 
278 	/*
279 	 * Now start copying characters.  If the size was specified to be 0,
280 	 * then assume the input was 0 terminated.
281 	 */
282 	j = 0;
283 	for (i = 0; (i + 1) < size; i += 2, j++) {	/* Size may be odd! */
284 		/*
285 		 * Let all valid unicode characters pass
286 		 * through (according to charset). Others are set to '_' .
287 		 */
288 		if (j < jsize)
289 			uc = tmpbuf[j];		/* temporary copy */
290 		else
291 			uc = '\0';
292 		if (uc == '\0') {
293 			jsize = j;
294 			unichar = 0;
295 		} else {			/* must be converted */
296 #ifdef	USE_ICONV
297 			if (use_iconv(inls)) {
298 				Uchar		ob[2];
299 				__IC_CONST char	*inbuf = (char *)&tmpbuf[j];
300 				size_t	isize = 3;
301 				char	*obuf = (char *)ob;
302 				size_t	osize = 2;
303 
304 				/*
305 				 * iconv() from glibc ignores osize and thus
306 				 * may try to access more than a single multi
307 				 * byte character from the input and read from
308 				 * non-existent memory.
309 				 *
310 				 * Note that iconv() returns -1 and sets errno
311 				 * to E2BIG if there is not enough room in the
312 				 * target location, but correctly converts the
313 				 * characters before.
314 				 */
315 				if (iconv(inls->sic_cd2uni, &inbuf, &isize,
316 							&obuf, &osize) == -1) {
317 					int	err = geterrno();
318 
319 					if ((err == EINVAL || err == EILSEQ) &&
320 					    isize == 3) {
321 						ob[0] = ob[1] = 0;
322 						isize--;
323 					}
324 				}
325 				unichar = ob[0] * 256 + ob[1];
326 				j += 2 - isize;
327 			} else
328 #endif
329 			unichar = sic_c2uni(inls, uc);	/* Get the UNICODE */
330 
331 			/*
332 			 * This code is currently also used for UDF formatting.
333 			 * Do not enforce silly Microsoft limitations in case
334 			 * that we only create UDF extensions.
335 			 */
336 			if (!use_Joliet)
337 				goto all_chars;
338 
339 			if (unichar <= 0x1f || unichar == 0x7f)
340 				unichar = '\0';	/* control char */
341 
342 			switch (unichar) {	/* test special characters */
343 
344 			case '*':
345 			case '/':
346 			case ':':
347 			case ';':
348 			case '?':
349 			case '\\':
350 			case '\0':		/* illegal char mark */
351 				/*
352 				 * Even Joliet has some standards as to what is
353 				 * allowed in a pathname. Pretty tame in
354 				 * comparison to what DOS restricts you to.
355 				 */
356 				unichar = '_';
357 			}
358 		all_chars:
359 				if (unichar == 0)
360 					unichar = '_';
361 			;
362 		}
363 		buffer[i] = unichar >> 8 & 0xFF; /* final UNICODE */
364 		buffer[i + 1] = unichar & 0xFF;	/* conversion */
365 	}
366 
367 	if (size & 1) {	/* beautification */
368 		buffer[size - 1] = 0;
369 	}
370 	if (source == NULL) {
371 		free(tmpbuf);
372 	}
373 }
374 
375 /*
376  * Function:	joliet_strlen
377  *
378  * Purpose:	Return length in bytes of string after conversion to unicode.
379  *
380  * Notes:	This is provided mainly as a convenience so that when more
381  * 		intelligent Unicode conversion for either Multibyte or 8-bit
382  *		codes is available that we can easily adapt.
383  */
384 #ifdef	UDF
385 EXPORT int
386 #else
387 LOCAL int
388 #endif
joliet_strlen(string,maxlen,inls)389 joliet_strlen(string, maxlen, inls)
390 	const char	*string;
391 	size_t		maxlen;
392 	siconvt_t	*inls;
393 {
394 	int	rtn = 0;
395 
396 #ifdef	USE_ICONV
397 	if (use_iconv(inls)) {
398 		int	j = 0;
399 
400 		while (string[j] != '\0') {
401 			Uchar		ob[2];
402 			__IC_CONST char	*inbuf = (char *)&string[j];
403 			size_t	isize = 3;
404 			char	*obuf = (char *)ob;
405 			size_t	osize = 2;
406 
407 			/*
408 			 * iconv() from glibc ignores osize and thus
409 			 * may try to access more than a single multi
410 			 * byte character from the input and read from
411 			 * non-existent memory.
412 			 *
413 			 * Note that iconv() returns -1 and sets errno
414 			 * to E2BIG if there is not enough room in the
415 			 * target location, but correctly converts the
416 			 * characters before.
417 			 */
418 			if (iconv(inls->sic_cd2uni, &inbuf, &isize,
419 						&obuf, &osize) == -1) {
420 				int	err = geterrno();
421 
422 				if ((err == EINVAL || err == EILSEQ) &&
423 				    isize == 3) {
424 					ob[0] = ob[1] = 0;
425 					isize--;
426 				}
427 			}
428 			j += 3 - isize;
429 			rtn += 2;
430 		}
431 	} else
432 #endif
433 	rtn = strlen(string) << 1;
434 
435 	/*
436 	 * We do clamp the maximum length of a Joliet or UDF string to be the
437 	 * maximum path size.
438 	 */
439 	if (rtn > 2*maxlen) {
440 		rtn = 2*maxlen;
441 	}
442 	return (rtn);
443 }
444 
445 /*
446  * Function:		get_joliet_vol_desc
447  *
448  * Purpose:		generate a Joliet compatible volume desc.
449  *
450  * Notes:		Assume that we have the non-joliet vol desc
451  *			already present in the buffer.  Just modifiy the
452  *			appropriate fields.
453  */
454 LOCAL void
get_joliet_vol_desc(jvol_desc)455 get_joliet_vol_desc(jvol_desc)
456 	struct iso_primary_descriptor	*jvol_desc;
457 {
458 	jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
459 	jvol_desc->version[0] = 1;
460 	jvol_desc->file_structure_version[0] = 1;
461 	/*
462 	 * For now, always do Unicode level 3.
463 	 * I don't really know what 1 and 2 are - perhaps a more limited
464 	 * Unicode set.
465 	 * FIXME(eric) - how does Romeo fit in here?
466 	 */
467 	sprintf(jvol_desc->escape_sequences, "%%/%c", ucs_codes[ucs_level]);
468 
469 	/* Until we have Unicode path tables, leave these unset. */
470 	set_733((char *)jvol_desc->path_table_size, jpath_table_size);
471 	set_731(jvol_desc->type_l_path_table, jpath_table[0]);
472 	set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
473 	set_732(jvol_desc->type_m_path_table, jpath_table[2]);
474 	set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
475 
476 	/* Set this one up. */
477 	memcpy(jvol_desc->root_directory_record, &jroot_record,
478 		offsetof(struct iso_directory_record, name[0]) + 1);
479 
480 	/*
481 	 * Finally, we have a bunch of strings to convert to Unicode.
482 	 * FIXME(eric) - I don't know how to do this in general,
483 	 * so we will just be really lazy and do a char -> short conversion.
484 	 *  We probably will want to filter any characters >= 0x80.
485 	 */
486 	convert_to_unicode((Uchar *)jvol_desc->system_id,
487 			sizeof (jvol_desc->system_id), NULL, in_nls);
488 	convert_to_unicode((Uchar *)jvol_desc->volume_id,
489 			sizeof (jvol_desc->volume_id), NULL, in_nls);
490 	convert_to_unicode((Uchar *)jvol_desc->volume_set_id,
491 			sizeof (jvol_desc->volume_set_id), NULL, in_nls);
492 	convert_to_unicode((Uchar *)jvol_desc->publisher_id,
493 			sizeof (jvol_desc->publisher_id), NULL, in_nls);
494 	convert_to_unicode((Uchar *)jvol_desc->preparer_id,
495 			sizeof (jvol_desc->preparer_id), NULL, in_nls);
496 	convert_to_unicode((Uchar *)jvol_desc->application_id,
497 			sizeof (jvol_desc->application_id), NULL, in_nls);
498 	convert_to_unicode((Uchar *)jvol_desc->copyright_file_id,
499 			sizeof (jvol_desc->copyright_file_id), NULL, in_nls);
500 	convert_to_unicode((Uchar *)jvol_desc->abstract_file_id,
501 			sizeof (jvol_desc->abstract_file_id), NULL, in_nls);
502 	convert_to_unicode((Uchar *)jvol_desc->bibliographic_file_id,
503 			sizeof (jvol_desc->bibliographic_file_id), NULL, in_nls);
504 }
505 
506 /*
507  * Asssign Joliet & UDF addresses
508  * We ignore all files that are neither in the Joliet nor in the UDF tree
509  */
510 LOCAL void
assign_joliet_directory_addresses(node)511 assign_joliet_directory_addresses(node)
512 	struct directory	*node;
513 {
514 	int		dir_size;
515 	struct directory *dpnt;
516 
517 	dpnt = node;
518 
519 	while (dpnt) {
520 		if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
521 			/*
522 			 * If we already have an extent for this
523 			 * (i.e. it came from a multisession disc), then
524 			 * don't reassign a new extent.
525 			 */
526 			dpnt->jpath_index = next_jpath_index++;
527 			if (dpnt->jextent == 0) {
528 				dpnt->jextent = last_extent;
529 				dir_size = ISO_BLOCKS(dpnt->jsize);
530 				last_extent += dir_size;
531 			}
532 		}
533 		/* skip if hidden - but not for the rr_moved dir */
534 		if (dpnt->subdir &&
535 		    ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ||
536 		    dpnt == reloc_dir)) {
537 			assign_joliet_directory_addresses(dpnt->subdir);
538 		}
539 		dpnt = dpnt->next;
540 	}
541 }
542 
543 LOCAL void
build_jpathlist(node)544 build_jpathlist(node)
545 	struct directory	*node;
546 {
547 	struct directory	*dpnt;
548 
549 	dpnt = node;
550 
551 	while (dpnt) {
552 		if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
553 			jpathlist[dpnt->jpath_index] = dpnt;
554 		}
555 		if (dpnt->subdir)
556 			build_jpathlist(dpnt->subdir);
557 		dpnt = dpnt->next;
558 	}
559 } /* build_jpathlist(... */
560 
561 LOCAL int
joliet_compare_paths(r,l)562 joliet_compare_paths(r, l)
563 	void const	*r;
564 	void const	*l;
565 {
566 	struct directory const *ll = *(struct directory * const *) l;
567 	struct directory const *rr = *(struct directory * const *) r;
568 	int		rparent,
569 			lparent;
570 	char		*rpnt,
571 			*lpnt;
572 	unsigned char	rtmp[2],
573 			ltmp[2];
574 	siconvt_t	*rinls, *linls;
575 
576 	/* make sure root directory is first */
577 	if (rr == root)
578 		return (-1);
579 
580 	if (ll == root)
581 		return (1);
582 
583 	rparent = rr->parent->jpath_index;
584 	lparent = ll->parent->jpath_index;
585 	if (rr->parent == reloc_dir) {
586 		rparent = rr->self->parent_rec->filedir->jpath_index;
587 	}
588 	if (ll->parent == reloc_dir) {
589 		lparent = ll->self->parent_rec->filedir->jpath_index;
590 	}
591 	if (rparent < lparent) {
592 		return (-1);
593 	}
594 	if (rparent > lparent) {
595 		return (1);
596 	}
597 #ifdef APPLE_HYB
598 	/*
599 	 * we may be using the HFS name - so select the correct input
600 	 * charset
601 	 */
602 	if (USE_MAC_NAME(rr->self)) {
603 		rpnt = rr->self->hfs_ent->name;
604 		rinls = hfs_inls;
605 	} else {
606 		rpnt = rr->self->name;
607 		rinls = in_nls;
608 	}
609 
610 	if (USE_MAC_NAME(ll->self)) {
611 		lpnt = ll->self->hfs_ent->name;
612 		linls = hfs_inls;
613 	} else {
614 		lpnt = ll->self->name;
615 		linls = in_nls;
616 	}
617 #else
618 	rpnt = rr->self->name;
619 	lpnt = ll->self->name;
620 	linls = rinls = in_nls;
621 #endif	/* APPLE_HYB */
622 
623 	/* compare the Unicode names */
624 
625 	while (*rpnt && *lpnt) {
626 		convert_to_unicode(rtmp, 2, rpnt, rinls);
627 		convert_to_unicode(ltmp, 2, lpnt, linls);
628 
629 		if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
630 			return (-1);
631 		if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
632 			return (1);
633 
634 		rpnt++;
635 		lpnt++;
636 	}
637 
638 	if (*rpnt)
639 		return (1);
640 	if (*lpnt)
641 		return (-1);
642 
643 	return (0);
644 
645 } /* compare_paths(... */
646 
647 LOCAL int
generate_joliet_path_tables()648 generate_joliet_path_tables()
649 {
650 	struct directory_entry *de;
651 	struct directory *dpnt;
652 	int		fix;
653 	int		j;
654 	int		namelen;
655 	char		*npnt;
656 	char		*npnt1;
657 	int		tablesize;
658 	unsigned int	jpindex;
659 
660 	/* First allocate memory for the tables and initialize the memory */
661 	tablesize = jpath_blocks << 11;
662 	jpath_table_m = (char *)e_malloc(tablesize);
663 	jpath_table_l = (char *)e_malloc(tablesize);
664 	memset(jpath_table_l, 0, tablesize);
665 	memset(jpath_table_m, 0, tablesize);
666 
667 	/* Now start filling in the path tables.  Start with root directory */
668 	jpath_table_index = 0;
669 	jpathlist = (struct directory **)e_malloc(sizeof (struct directory *)
670 		* next_jpath_index);
671 	memset(jpathlist, 0, sizeof (struct directory *) * next_jpath_index);
672 	build_jpathlist(root);
673 
674 	do {
675 		fix = 0;
676 #ifdef	PROTOTYPES
677 		qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
678 			(int (*) (const void *, const void *)) joliet_compare_paths);
679 #else
680 		qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
681 			joliet_compare_paths);
682 #endif
683 
684 		for (j = 1; j < next_jpath_index; j++) {
685 			if (jpathlist[j]->jpath_index != j) {
686 				jpathlist[j]->jpath_index = j;
687 				fix++;
688 			}
689 		}
690 	} while (fix);
691 
692 	for (j = 1; j < next_jpath_index; j++) {
693 		dpnt = jpathlist[j];
694 		if (!dpnt) {
695 			comerrno(EX_BAD, _("Entry %d not in path tables\n"), j);
696 		}
697 		npnt = dpnt->de_name;
698 
699 		npnt1 = strrchr(npnt, PATH_SEPARATOR);
700 		if (npnt1) {
701 			npnt = npnt1 + 1;
702 		}
703 		de = dpnt->self;
704 		if (!de) {
705 			comerrno(EX_BAD,
706 			_("Fatal Joliet goof - directory has amnesia\n"));
707 		}
708 #ifdef APPLE_HYB
709 		if (USE_MAC_NAME(de))
710 			namelen = joliet_strlen(de->hfs_ent->name, jlen, hfs_inls);
711 		else
712 #endif	/* APPLE_HYB */
713 			namelen = joliet_strlen(de->name, jlen, in_nls);
714 
715 		if (dpnt == root) {
716 			jpath_table_l[jpath_table_index] = 1;
717 			jpath_table_m[jpath_table_index] = 1;
718 		} else {
719 			jpath_table_l[jpath_table_index] = namelen;
720 			jpath_table_m[jpath_table_index] = namelen;
721 		}
722 		jpath_table_index += 2;
723 
724 		set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
725 		set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
726 		jpath_table_index += 4;
727 
728 
729 		if (dpnt->parent != reloc_dir) {
730 			set_721(jpath_table_l + jpath_table_index,
731 				dpnt->parent->jpath_index);
732 			set_722(jpath_table_m + jpath_table_index,
733 				dpnt->parent->jpath_index);
734 			jpindex = dpnt->parent->jpath_index;
735 		} else {
736 			set_721(jpath_table_l + jpath_table_index,
737 				dpnt->self->parent_rec->filedir->jpath_index);
738 			set_722(jpath_table_m + jpath_table_index,
739 				dpnt->self->parent_rec->filedir->jpath_index);
740 			jpindex = dpnt->self->parent_rec->filedir->jpath_index;
741 		}
742 
743 		if (jpindex > 0xffff) {
744 			static int warned = 0;
745 
746 			if (!warned) {
747 				warned++;
748 				errmsgno(EX_BAD,
749 			_("Unable to generate sane Joliet path tables - too many directories (%u)\n"),
750 					jpindex);
751 				if (!nolimitpathtables)
752 					errmsgno(EX_BAD,
753 					_("Try to use the option -no-limit-pathtables\n"));
754 			}
755 			if (!nolimitpathtables)
756 				exit(EX_BAD);
757 			/*
758 			 * Let it point to the root directory instead.
759 			 */
760 			set_721(jpath_table_l + jpath_table_index, 1);
761 			set_722(jpath_table_m + jpath_table_index, 1);
762 		}
763 
764 		jpath_table_index += 2;
765 
766 		/*
767 		 * The root directory is still represented in non-unicode
768 		 * fashion.
769 		 */
770 		if (dpnt == root) {
771 			jpath_table_l[jpath_table_index] = 0;
772 			jpath_table_m[jpath_table_index] = 0;
773 			jpath_table_index++;
774 		} else {
775 #ifdef APPLE_HYB
776 			if (USE_MAC_NAME(de)) {
777 				convert_to_unicode((Uchar *) jpath_table_l +
778 					jpath_table_index,
779 					namelen, de->hfs_ent->name, hfs_inls);
780 				convert_to_unicode((Uchar *) jpath_table_m +
781 					jpath_table_index,
782 					namelen, de->hfs_ent->name, hfs_inls);
783 			} else {
784 #endif	/* APPLE_HYB */
785 				convert_to_unicode((Uchar *) jpath_table_l +
786 					jpath_table_index,
787 					namelen, de->name, in_nls);
788 				convert_to_unicode((Uchar *) jpath_table_m +
789 					jpath_table_index,
790 					namelen, de->name, in_nls);
791 #ifdef APPLE_HYB
792 			}
793 #endif	/* APPLE_HYB */
794 
795 			jpath_table_index += namelen;
796 		}
797 
798 		if (jpath_table_index & 1) {
799 			jpath_table_index++;	/* For odd lengths we pad */
800 		}
801 	}
802 
803 	free(jpathlist);
804 	if (jpath_table_index != jpath_table_size) {
805 		errmsgno(EX_BAD,
806 		_("Joliet path table lengths do not match %d expected: %d\n"),
807 			jpath_table_index,
808 			jpath_table_size);
809 	}
810 	return (0);
811 } /* generate_path_tables(... */
812 
813 LOCAL void
generate_one_joliet_directory(dpnt,outfile)814 generate_one_joliet_directory(dpnt, outfile)
815 	struct directory	*dpnt;
816 	FILE			*outfile;
817 {
818 	unsigned int		dir_index;
819 	char			*directory_buffer;
820 	int			new_reclen;
821 	struct directory_entry *s_entry;
822 	struct directory_entry *s_entry1;
823 	struct iso_directory_record jrec;
824 	unsigned int	total_size;
825 	int			cvt_len;
826 	struct directory	*finddir;
827 
828 	total_size = ISO_ROUND_UP(dpnt->jsize);
829 	directory_buffer = (char *)e_malloc(total_size);
830 	memset(directory_buffer, 0, total_size);
831 	dir_index = 0;
832 
833 	s_entry = dpnt->jcontents;
834 	while (s_entry) {
835 		if (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
836 			s_entry = s_entry->jnext;
837 			continue;
838 		}
839 		/*
840 		 * If this entry was a directory that was relocated,
841 		 * we have a bit of trouble here.  We need to dig out the real
842 		 * thing and put it back here.  In the Joliet tree, there is
843 		 * no relocated rock ridge, as there are no depth limits to a
844 		 * directory tree.
845 		 */
846 		if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
847 			for (s_entry1 = reloc_dir->contents; s_entry1;
848 						s_entry1 = s_entry1->next) {
849 				if (s_entry1->parent_rec == s_entry) {
850 					break;
851 				}
852 			}
853 			if (s_entry1 == NULL) {
854 				/* We got trouble. */
855 				comerrno(EX_BAD,
856 				_("Unable to locate relocated directory\n"));
857 			}
858 		} else {
859 			s_entry1 = s_entry;
860 		}
861 
862 		/*
863 		 * We do not allow directory entries to cross sector
864 		 * boundaries. Simply pad, and then start the next entry at
865 		 * the next sector
866 		 */
867 		new_reclen = s_entry1->jreclen;
868 		if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) {
869 			dir_index = ISO_ROUND_UP(dir_index);
870 		}
871 		memcpy(&jrec, &s_entry1->isorec, offsetof(struct iso_directory_record, name[0]));
872 
873 #ifdef APPLE_HYB
874 		/* Use the HFS name if it exists */
875 		if (USE_MAC_NAME(s_entry1))
876 			cvt_len = joliet_strlen(s_entry1->hfs_ent->name, jlen, hfs_inls);
877 		else
878 #endif	/* APPLE_HYB */
879 			cvt_len = joliet_strlen(s_entry1->name, jlen, in_nls);
880 
881 		/*
882 		 * Fix the record length
883 		 * - this was the non-Joliet version we were seeing.
884 		 */
885 		jrec.name_len[0] = cvt_len;
886 		jrec.length[0] = s_entry1->jreclen;
887 
888 		/*
889 		 * If this is a directory,
890 		 * fix the correct size and extent number.
891 		 */
892 		if ((jrec.flags[0] & ISO_DIRECTORY) != 0) {
893 			if (strcmp(s_entry1->name, ".") == 0) {
894 				jrec.name_len[0] = 1;
895 				set_733((char *)jrec.extent, dpnt->jextent);
896 				set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->jsize));
897 			} else if (strcmp(s_entry1->name, "..") == 0) {
898 				jrec.name_len[0] = 1;
899 				if (dpnt->parent == reloc_dir) {
900 					set_733((char *)jrec.extent, dpnt->self->parent_rec->filedir->jextent);
901 					set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
902 				} else {
903 					set_733((char *)jrec.extent, dpnt->parent->jextent);
904 					set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->parent->jsize));
905 				}
906 			} else {
907 				if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
908 					finddir = reloc_dir->subdir;
909 				} else {
910 					finddir = dpnt->subdir;
911 				}
912 				while (finddir && finddir->self != s_entry1) {
913 					finddir = finddir->next;
914 				}
915 				if (!finddir) {
916 					comerrno(EX_BAD,
917 						_("Fatal goof - unable to find directory location\n"));
918 				}
919 				set_733((char *)jrec.extent, finddir->jextent);
920 				set_733((char *)jrec.size,
921 						ISO_ROUND_UP(finddir->jsize));
922 			}
923 		}
924 		memcpy(directory_buffer + dir_index, &jrec,
925 			offsetof(struct iso_directory_record, name[0]));
926 
927 		dir_index += offsetof(struct iso_directory_record, name[0]);
928 
929 		/*
930 		 * Finally dump the Unicode version of the filename.
931 		 * Note - . and .. are the same as with non-Joliet discs.
932 		 */
933 		if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
934 			strcmp(s_entry1->name, ".") == 0) {
935 			directory_buffer[dir_index++] = 0;
936 		} else if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
937 			strcmp(s_entry1->name, "..") == 0) {
938 			directory_buffer[dir_index++] = 1;
939 		} else {
940 #ifdef APPLE_HYB
941 			if (USE_MAC_NAME(s_entry1)) {
942 				/* Use the HFS name if it exists */
943 				convert_to_unicode(
944 					(Uchar *) directory_buffer+dir_index,
945 					cvt_len,
946 					s_entry1->hfs_ent->name, hfs_inls);
947 			} else
948 #endif	/* APPLE_HYB */
949 			{
950 				convert_to_unicode(
951 					(Uchar *) directory_buffer+dir_index,
952 					cvt_len,
953 					s_entry1->name, in_nls);
954 			}
955 			dir_index += cvt_len;
956 		}
957 
958 		if (dir_index & 1) {
959 			directory_buffer[dir_index++] = 0;
960 		}
961 		s_entry = s_entry->jnext;
962 	}
963 
964 	if (dpnt->jsize != dir_index) {
965 		errmsgno(EX_BAD,
966 		_("Unexpected joliet directory length %d expected: %d '%s'\n"),
967 			dpnt->jsize,
968 			dir_index, dpnt->de_name);
969 	}
970 	xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
971 	last_extent_written += total_size >> 11;
972 	free(directory_buffer);
973 } /* generate_one_joliet_directory(... */
974 
975 LOCAL int
joliet_sort_n_finish(this_dir)976 joliet_sort_n_finish(this_dir)
977 	struct directory	*this_dir;
978 {
979 	struct directory_entry	*s_entry;
980 	int			status = 0;
981 
982 	/*
983 	 * don't want to skip this directory if it's the reloc_dir
984 	 * at the moment
985 	 */
986 	if (this_dir != reloc_dir &&
987 				this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
988 		return (0);
989 	}
990 	for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
991 		/* skip hidden entries */
992 		if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
993 			continue;
994 		}
995 		/*
996 		 * First update the path table sizes for directories.
997 		 *
998 		 * Finally, set the length of the directory entry if Joliet is
999 		 * used. The name is longer, but no Rock Ridge is ever used
1000 		 * here, so depending upon the options the entry size might
1001 		 * turn out to be about the same.  The Unicode name is always
1002 		 * a multiple of 2 bytes, so we always add 1 to make it an
1003 		 * even number.
1004 		 */
1005 		if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1006 			if (strcmp(s_entry->name, ".") != 0 &&
1007 					strcmp(s_entry->name, "..") != 0) {
1008 #ifdef APPLE_HYB
1009 				if (USE_MAC_NAME(s_entry))
1010 					/* Use the HFS name if it exists */
1011 					jpath_table_size +=
1012 						joliet_strlen(s_entry->hfs_ent->name, jlen, hfs_inls) +
1013 						offsetof(struct iso_path_table, name[0]);
1014 				else
1015 #endif	/* APPLE_HYB */
1016 					jpath_table_size +=
1017 						joliet_strlen(s_entry->name, jlen, in_nls) +
1018 						offsetof(struct iso_path_table, name[0]);
1019 				if (jpath_table_size & 1) {
1020 					jpath_table_size++;
1021 				}
1022 			} else {
1023 				if (this_dir == root &&
1024 						strlen(s_entry->name) == 1) {
1025 
1026 					jpath_table_size += 1 + offsetof(struct iso_path_table, name[0]);
1027 					if (jpath_table_size & 1)
1028 						jpath_table_size++;
1029 				}
1030 			}
1031 		}
1032 		if (strcmp(s_entry->name, ".") != 0 &&
1033 					strcmp(s_entry->name, "..") != 0) {
1034 #ifdef APPLE_HYB
1035 			if (USE_MAC_NAME(s_entry))
1036 				/* Use the HFS name if it exists */
1037 				s_entry->jreclen =
1038 				offsetof(struct iso_directory_record, name[0])
1039 					+ joliet_strlen(s_entry->hfs_ent->name, jlen, hfs_inls)
1040 					+ 1;
1041 			else
1042 #endif	/* APPLE_HYB */
1043 				s_entry->jreclen =
1044 				offsetof(struct iso_directory_record, name[0])
1045 					+ joliet_strlen(s_entry->name, jlen, in_nls)
1046 					+ 1;
1047 		} else {
1048 			/*
1049 			 * Special - for '.' and '..' we generate the same
1050 			 * records we did for non-Joliet discs.
1051 			 */
1052 			s_entry->jreclen =
1053 			offsetof(struct iso_directory_record, name[0])
1054 				+ 1;
1055 		}
1056 
1057 
1058 	}
1059 
1060 	if ((this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1061 		return (0);
1062 	}
1063 	this_dir->jcontents = this_dir->contents;
1064 	status = joliet_sort_directory(&this_dir->jcontents);
1065 
1066 	/*
1067 	 * Now go through the directory and figure out how large this one will
1068 	 * be. Do not split a directory entry across a sector boundary
1069 	 */
1070 	s_entry = this_dir->jcontents;
1071 	/*
1072 	 * XXX Is it ok to comment this out?
1073 	 */
1074 /*XXX JS  this_dir->ce_bytes = 0;*/
1075 	for (s_entry = this_dir->jcontents; s_entry;
1076 						s_entry = s_entry->jnext) {
1077 		int	jreclen;
1078 
1079 		if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1080 			continue;
1081 		}
1082 		jreclen = s_entry->jreclen;
1083 
1084 		if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >=
1085 								SECTOR_SIZE) {
1086 			this_dir->jsize = ISO_ROUND_UP(this_dir->jsize);
1087 		}
1088 		this_dir->jsize += jreclen;
1089 	}
1090 	return (status);
1091 }
1092 
1093 /*
1094  * Similar to the iso9660 case,
1095  * except here we perform a full sort based upon the
1096  * regular name of the file, not the 8.3 version.
1097  */
1098 LOCAL int
joliet_compare_dirs(rr,ll)1099 joliet_compare_dirs(rr, ll)
1100 	const void	*rr;
1101 	const void	*ll;
1102 {
1103 	char		*rpnt,
1104 			*lpnt;
1105 	struct directory_entry **r,
1106 			**l;
1107 	unsigned char	rtmp[2],
1108 			ltmp[2];
1109 	siconvt_t	*linls, *rinls;
1110 
1111 	r = (struct directory_entry **)rr;
1112 	l = (struct directory_entry **)ll;
1113 
1114 #ifdef APPLE_HYB
1115 	/*
1116 	 * we may be using the HFS name - so select the correct input
1117 	 * charset
1118 	 */
1119 	if (USE_MAC_NAME(*r)) {
1120 		rpnt = (*r)->hfs_ent->name;
1121 		rinls = hfs_inls;
1122 	} else {
1123 		rpnt = (*r)->name;
1124 		rinls = in_nls;
1125 	}
1126 
1127 	if (USE_MAC_NAME(*l)) {
1128 		lpnt = (*l)->hfs_ent->name;
1129 		linls = hfs_inls;
1130 	} else {
1131 		lpnt = (*l)->name;
1132 		linls = in_nls;
1133 	}
1134 #else
1135 	rpnt = (*r)->name;
1136 	lpnt = (*l)->name;
1137 	rinls = linls = in_nls;
1138 #endif	/* APPLE_HYB */
1139 
1140 	/*
1141 	 * If the entries are the same, this is an error.
1142 	 * Joliet specs allow for a maximum of 64 characters.
1143 	 * If we see different multi extent parts, it is OK to
1144 	 * have the same name more than once.
1145 	 */
1146 	if (strncmp(rpnt, lpnt, jlen) == 0) {
1147 #ifdef USE_LARGEFILES
1148 		if ((*r)->mxpart == (*l)->mxpart)
1149 #endif
1150 		{
1151 			errmsgno(EX_BAD,
1152 				_("Error: %s and %s have the same Joliet name\n"),
1153 				(*r)->whole_name, (*l)->whole_name);
1154 			jsort_goof++;
1155 			{
1156 				char	*p1 = rpnt;
1157 				char	*p2 = lpnt;
1158 				int	len = 0;
1159 
1160 				for (; *p1 == *p2; p1++, p2++, len++) {
1161 					if (*p1 == '\0')
1162 						break;
1163 				}
1164 				if (len > jsort_glen)
1165 					jsort_glen = len;
1166 			}
1167 		}
1168 	}
1169 	/*
1170 	 * Put the '.' and '..' entries on the head of the sorted list.
1171 	 * For normal ASCII, this always happens to be the case, but out of
1172 	 * band characters cause this not to be the case sometimes.
1173 	 */
1174 	if (strcmp(rpnt, ".") == 0)
1175 		return (-1);
1176 	if (strcmp(lpnt, ".") == 0)
1177 		return (1);
1178 
1179 	if (strcmp(rpnt, "..") == 0)
1180 		return (-1);
1181 	if (strcmp(lpnt, "..") == 0)
1182 		return (1);
1183 
1184 #ifdef DVD_AUD_VID
1185 	/*
1186 	 * There're rumors claiming that some players assume VIDEO_TS.IFO
1187 	 * to be the first file in VIDEO_TS/ catalog. Well, it's basically
1188 	 * the only file a player has to actually look for, as the whole
1189 	 * video content can be "rolled down" from this file alone.
1190 	 *				<appro@fy.chalmers.se>
1191 	 */
1192 	/*
1193 	 * XXX This code has to be moved from the Joliet implementation
1194 	 * XXX to the UDF implementation if we implement decent UDF support
1195 	 * XXX with a separate name space for the UDF file tree.
1196 	 */
1197 	if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
1198 		if (strcmp(rpnt, "VIDEO_TS.IFO") == 0)
1199 			return (-1);
1200 		if (strcmp(lpnt, "VIDEO_TS.IFO") == 0)
1201 			return (1);
1202 	}
1203 #endif
1204 
1205 	while (*rpnt && *lpnt) {
1206 		if (*rpnt == ';' && *lpnt != ';')
1207 			return (-1);
1208 		if (*rpnt != ';' && *lpnt == ';')
1209 			return (1);
1210 
1211 		if (*rpnt == ';' && *lpnt == ';')
1212 			return (0);
1213 
1214 		/*
1215 		 * Extensions are not special here.
1216 		 * Don't treat the dot as something that must be bumped to
1217 		 * the start of the list.
1218 		 */
1219 #if 0
1220 		if (*rpnt == '.' && *lpnt != '.')
1221 			return (-1);
1222 		if (*rpnt != '.' && *lpnt == '.')
1223 			return (1);
1224 #endif
1225 
1226 		convert_to_unicode(rtmp, 2, rpnt, rinls);
1227 		convert_to_unicode(ltmp, 2, lpnt, linls);
1228 
1229 		if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
1230 			return (-1);
1231 		if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
1232 			return (1);
1233 
1234 		rpnt++;
1235 		lpnt++;
1236 	}
1237 	if (*rpnt)
1238 		return (1);
1239 	if (*lpnt)
1240 		return (-1);
1241 #ifdef USE_LARGEFILES
1242 	/*
1243 	 * (*r)->mxpart == (*l)->mxpart cannot happen here
1244 	 */
1245 	if ((*r)->mxpart < (*l)->mxpart)
1246 		return (-1);
1247 	else if ((*r)->mxpart > (*l)->mxpart)
1248 		return (1);
1249 #endif
1250 	return (0);
1251 }
1252 
1253 
1254 /*
1255  * Function:		sort_directory
1256  *
1257  * Purpose:		Sort the directory in the appropriate ISO9660
1258  *			order.
1259  *
1260  * Notes:		Returns 0 if OK, returns > 0 if an error occurred.
1261  */
1262 LOCAL int
joliet_sort_directory(sort_dir)1263 joliet_sort_directory(sort_dir)
1264 	struct directory_entry	**sort_dir;
1265 {
1266 	int			dcount = 0;
1267 	int			i;
1268 	struct directory_entry	*s_entry;
1269 	struct directory_entry	**sortlist;
1270 
1271 	s_entry = *sort_dir;
1272 	while (s_entry) {
1273 		/*
1274 		 * only colletc non-hidden entries
1275 		 */
1276 		if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1277 					(INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY))
1278 			dcount++;
1279 		s_entry = s_entry->next;
1280 	}
1281 
1282 	/* OK, now we know how many there are.  Build a vector for sorting. */
1283 	sortlist = (struct directory_entry **)
1284 		e_malloc(sizeof (struct directory_entry *) * dcount);
1285 
1286 	dcount = 0;
1287 	s_entry = *sort_dir;
1288 	while (s_entry) {
1289 		/*
1290 		 * only collect non-hidden entries
1291 		 */
1292 		if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1293 					(INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) {
1294 			sortlist[dcount] = s_entry;
1295 			dcount++;
1296 		}
1297 		s_entry = s_entry->next;
1298 	}
1299 
1300 	jsort_goof = 0;
1301 	jsort_glen = 0;
1302 #ifdef	PROTOTYPES
1303 	qsort(sortlist, dcount, sizeof (struct directory_entry *),
1304 		(int (*) (const void *, const void *)) joliet_compare_dirs);
1305 #else
1306 	qsort(sortlist, dcount, sizeof (struct directory_entry *),
1307 		joliet_compare_dirs);
1308 #endif
1309 
1310 	if (jsort_goof) {
1311 		errmsgno(EX_BAD,
1312 			_("Joliet file names differ after %d chars\n"),
1313 			jsort_glen);
1314 		if (jsort_glen > JLONGMAX) {
1315 			errmsgno(EX_BAD,
1316 			_("Cannot use Joliet, please remove -J from the option list.\n"));
1317 		} else if (jsort_glen > JMAX) {
1318 			errmsgno(EX_BAD,
1319 			_("Try to use the option -joliet-long\n"));
1320 		}
1321 	}
1322 
1323 	/* Now reassemble the linked list in the proper sorted order */
1324 	for (i = 0; i < dcount - 1; i++) {
1325 		sortlist[i]->jnext = sortlist[i + 1];
1326 	}
1327 
1328 	sortlist[dcount - 1]->jnext = NULL;
1329 	*sort_dir = sortlist[0];
1330 
1331 	free(sortlist);
1332 	return (jsort_goof);
1333 }
1334 
1335 EXPORT int
joliet_sort_tree(node)1336 joliet_sort_tree(node)
1337 	struct directory	*node;
1338 {
1339 	struct directory	*dpnt;
1340 	int			ret = 0;
1341 
1342 	dpnt = node;
1343 
1344 	while (dpnt) {
1345 		ret = joliet_sort_n_finish(dpnt);
1346 		if (ret) {
1347 			break;
1348 		}
1349 		if (dpnt->subdir)
1350 			ret = joliet_sort_tree(dpnt->subdir);
1351 		if (ret) {
1352 			break;
1353 		}
1354 		dpnt = dpnt->next;
1355 	}
1356 	return (ret);
1357 }
1358 
1359 LOCAL void
generate_joliet_directories(node,outfile)1360 generate_joliet_directories(node, outfile)
1361 	struct directory	*node;
1362 	FILE			*outfile;
1363 {
1364 	struct directory *dpnt;
1365 
1366 	dpnt = node;
1367 
1368 	while (dpnt) {
1369 		if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
1370 			/*
1371 			 * In theory we should never reuse a directory, so this
1372 			 * doesn't make much sense.
1373 			 */
1374 			if (dpnt->jextent > session_start) {
1375 				generate_one_joliet_directory(dpnt, outfile);
1376 			}
1377 		}
1378 		/* skip if hidden - but not for the rr_moved dir */
1379 		if (dpnt->subdir &&
1380 		    (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
1381 		    dpnt == reloc_dir)) {
1382 			generate_joliet_directories(dpnt->subdir, outfile);
1383 		}
1384 		dpnt = dpnt->next;
1385 	}
1386 }
1387 
1388 
1389 /*
1390  * Function to write the EVD for the disc.
1391  */
1392 LOCAL int
jpathtab_write(outfile)1393 jpathtab_write(outfile)
1394 	FILE	*outfile;
1395 {
1396 	/* Next we write the path tables */
1397 	xfwrite(jpath_table_l, jpath_blocks << 11, 1, outfile, 0, FALSE);
1398 	xfwrite(jpath_table_m, jpath_blocks << 11, 1, outfile, 0, FALSE);
1399 	last_extent_written += 2 * jpath_blocks;
1400 	free(jpath_table_l);
1401 	free(jpath_table_m);
1402 	jpath_table_l = NULL;
1403 	jpath_table_m = NULL;
1404 	return (0);
1405 }
1406 
1407 LOCAL int
jdirtree_size(starting_extent)1408 jdirtree_size(starting_extent)
1409 	UInt32_t	starting_extent;
1410 {
1411 	assign_joliet_directory_addresses(root);
1412 	return (0);
1413 }
1414 
1415 LOCAL int
jroot_gen()1416 jroot_gen()
1417 {
1418 	jroot_record.length[0] =
1419 			1 + offsetof(struct iso_directory_record, name[0]);
1420 	jroot_record.ext_attr_length[0] = 0;
1421 	set_733((char *)jroot_record.extent, root->jextent);
1422 	set_733((char *)jroot_record.size, ISO_ROUND_UP(root->jsize));
1423 	iso9660_date(jroot_record.date, root_statbuf.st_mtime);
1424 	jroot_record.flags[0] = ISO_DIRECTORY;
1425 	jroot_record.file_unit_size[0] = 0;
1426 	jroot_record.interleave[0] = 0;
1427 	set_723(jroot_record.volume_sequence_number, volume_sequence_number);
1428 	jroot_record.name_len[0] = 1;
1429 	return (0);
1430 }
1431 
1432 LOCAL int
jdirtree_write(outfile)1433 jdirtree_write(outfile)
1434 	FILE	*outfile;
1435 {
1436 	generate_joliet_directories(root, outfile);
1437 	return (0);
1438 }
1439 
1440 /*
1441  * Function to write the EVD for the disc.
1442  */
1443 LOCAL int
jvd_write(outfile)1444 jvd_write(outfile)
1445 	FILE	*outfile;
1446 {
1447 	struct iso_primary_descriptor jvol_desc;
1448 
1449 	/* Next we write out the boot volume descriptor for the disc */
1450 	jvol_desc = vol_desc;
1451 	get_joliet_vol_desc(&jvol_desc);
1452 	xfwrite(&jvol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
1453 	last_extent_written++;
1454 	return (0);
1455 }
1456 
1457 /*
1458  * Functions to describe padding block at the start of the disc.
1459  */
1460 LOCAL int
jpathtab_size(starting_extent)1461 jpathtab_size(starting_extent)
1462 	UInt32_t	starting_extent;
1463 {
1464 	jpath_table[0] = starting_extent;
1465 	jpath_table[1] = 0;
1466 	jpath_table[2] = jpath_table[0] + jpath_blocks;
1467 	jpath_table[3] = 0;
1468 
1469 	last_extent += 2 * jpath_blocks;
1470 	return (0);
1471 }
1472 
1473 struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen, jvd_write, "Joliet Volume Descriptor" };
1474 struct output_fragment jpathtable_desc = {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write, "Joliet path table" };
1475 struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write, "Joliet directory tree" };
1476