1231200Smm/*-
2232153Smm * Copyright (c) 2009-2012 Michihiro NAKAJIMA
3231200Smm * All rights reserved.
4231200Smm *
5231200Smm * Redistribution and use in source and binary forms, with or without
6231200Smm * modification, are permitted provided that the following conditions
7231200Smm * are met:
8231200Smm * 1. Redistributions of source code must retain the above copyright
9231200Smm *    notice, this list of conditions and the following disclaimer.
10231200Smm * 2. Redistributions in binary form must reproduce the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer in the
12231200Smm *    documentation and/or other materials provided with the distribution.
13231200Smm *
14231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24231200Smm */
25231200Smm
26231200Smm#include "archive_platform.h"
27231200Smm
28231200Smm#ifdef HAVE_SYS_TYPES_H
29231200Smm#include <sys/types.h>
30231200Smm#endif
31231200Smm#ifdef HAVE_SYS_UTSNAME_H
32231200Smm#include <sys/utsname.h>
33231200Smm#endif
34231200Smm#ifdef HAVE_ERRNO_H
35231200Smm#include <errno.h>
36231200Smm#endif
37231200Smm#ifdef HAVE_LIMITS_H
38231200Smm#include <limits.h>
39231200Smm#endif
40231200Smm#include <stdio.h>
41231200Smm#include <stdarg.h>
42231200Smm#ifdef HAVE_STDLIB_H
43231200Smm#include <stdlib.h>
44231200Smm#endif
45231200Smm#include <time.h>
46231200Smm#ifdef HAVE_UNISTD_H
47231200Smm#include <unistd.h>
48231200Smm#endif
49231200Smm#ifdef HAVE_ZLIB_H
50231200Smm#include <zlib.h>
51231200Smm#endif
52231200Smm
53231200Smm#include "archive.h"
54231200Smm#include "archive_endian.h"
55231200Smm#include "archive_entry.h"
56231200Smm#include "archive_entry_locale.h"
57231200Smm#include "archive_private.h"
58231200Smm#include "archive_rb.h"
59231200Smm#include "archive_write_private.h"
60231200Smm
61231200Smm#if defined(_WIN32) && !defined(__CYGWIN__)
62231200Smm#define getuid()			0
63231200Smm#define getgid()			0
64231200Smm#endif
65231200Smm
66231200Smm/*#define DEBUG 1*/
67231200Smm#ifdef DEBUG
68231200Smm/* To compare to the ISO image file made by mkisofs. */
69231200Smm#define COMPAT_MKISOFS		1
70231200Smm#endif
71231200Smm
72231200Smm#define LOGICAL_BLOCK_BITS			11
73231200Smm#define LOGICAL_BLOCK_SIZE			2048
74231200Smm#define PATH_TABLE_BLOCK_SIZE			4096
75231200Smm
76231200Smm#define SYSTEM_AREA_BLOCK			16
77231200Smm#define PRIMARY_VOLUME_DESCRIPTOR_BLOCK 	1
78231200Smm#define SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK 	1
79231200Smm#define BOOT_RECORD_DESCRIPTOR_BLOCK	 	1
80231200Smm#define VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK	1
81231200Smm#define NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK	1
82231200Smm#define RRIP_ER_BLOCK				1
83231200Smm#define PADDING_BLOCK				150
84231200Smm
85231200Smm#define FD_1_2M_SIZE		(1024 * 1200)
86231200Smm#define FD_1_44M_SIZE		(1024 * 1440)
87231200Smm#define FD_2_88M_SIZE		(1024 * 2880)
88231200Smm#define MULTI_EXTENT_SIZE	(ARCHIVE_LITERAL_LL(1) << 32)	/* 4Gi bytes. */
89231200Smm#define MAX_DEPTH		8
90231200Smm#define RR_CE_SIZE		28		/* SUSP "CE" extension size */
91231200Smm
92231200Smm#define FILE_FLAG_EXISTENCE	0x01
93231200Smm#define FILE_FLAG_DIRECTORY	0x02
94231200Smm#define FILE_FLAG_ASSOCIATED	0x04
95231200Smm#define FILE_FLAG_RECORD	0x08
96231200Smm#define FILE_FLAG_PROTECTION	0x10
97231200Smm#define FILE_FLAG_MULTI_EXTENT	0x80
98231200Smm
99231200Smmstatic const char rrip_identifier[] =
100231200Smm	"RRIP_1991A";
101231200Smmstatic const char rrip_descriptor[] =
102231200Smm	"THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR "
103231200Smm	"POSIX FILE SYSTEM SEMANTICS";
104231200Smmstatic const char rrip_source[] =
105231200Smm	"PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  "
106231200Smm	"SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR "
107231200Smm	"CONTACT INFORMATION.";
108231200Smm#define RRIP_ER_ID_SIZE		(sizeof(rrip_identifier)-1)
109231200Smm#define RRIP_ER_DSC_SIZE	(sizeof(rrip_descriptor)-1)
110231200Smm#define RRIP_ER_SRC_SIZE	(sizeof(rrip_source)-1)
111231200Smm#define RRIP_ER_SIZE		(8 + RRIP_ER_ID_SIZE + \
112231200Smm				RRIP_ER_DSC_SIZE + RRIP_ER_SRC_SIZE)
113231200Smm
114231200Smmstatic const unsigned char zisofs_magic[8] = {
115231200Smm	0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
116231200Smm};
117231200Smm
118231200Smm#define ZF_HEADER_SIZE	16	/* zisofs header size. */
119231200Smm#define ZF_LOG2_BS	15	/* log2 block size; 32K bytes. */
120231200Smm#define ZF_BLOCK_SIZE	(1UL << ZF_LOG2_BS)
121231200Smm
122231200Smm/*
123231200Smm * Manage extra records.
124231200Smm */
125231200Smmstruct extr_rec {
126231200Smm	int		 location;
127231200Smm	int		 offset;
128231200Smm	unsigned char	 buf[LOGICAL_BLOCK_SIZE];
129231200Smm	struct extr_rec	*next;
130231200Smm};
131231200Smm
132231200Smmstruct ctl_extr_rec {
133231200Smm	int		 use_extr;
134231200Smm	unsigned char	*bp;
135231200Smm	struct isoent	*isoent;
136231200Smm	unsigned char	*ce_ptr;
137231200Smm	int		 cur_len;
138231200Smm	int		 dr_len;
139231200Smm	int		 limit;
140231200Smm	int		 extr_off;
141231200Smm	int		 extr_loc;
142231200Smm};
143231200Smm#define DR_SAFETY	RR_CE_SIZE
144231200Smm#define DR_LIMIT	(254 - DR_SAFETY)
145231200Smm
146231200Smm/*
147231200Smm * The relation of struct isofile and isoent and archive_entry.
148231200Smm *
149231200Smm * Primary volume tree  --> struct isoent
150231200Smm *                                |
151231200Smm *                                v
152231200Smm *                          struct isofile --> archive_entry
153231200Smm *                                ^
154231200Smm *                                |
155231200Smm * Joliet volume tree   --> struct isoent
156231200Smm *
157231200Smm * struct isoent has specific information for volume.
158231200Smm */
159231200Smm
160231200Smmstruct isofile {
161231200Smm	/* Used for managing struct isofile list. */
162231200Smm	struct isofile		*allnext;
163231200Smm	struct isofile		*datanext;
164313571Smm	/* Used for managing a hardlinked struct isofile list. */
165231200Smm	struct isofile		*hlnext;
166231200Smm	struct isofile		*hardlink_target;
167231200Smm
168231200Smm	struct archive_entry	*entry;
169231200Smm
170231200Smm	/*
171231200Smm	 * Used for making a directory tree.
172231200Smm	 */
173231200Smm	struct archive_string	 parentdir;
174231200Smm	struct archive_string	 basename;
175231200Smm	struct archive_string	 basename_utf16;
176231200Smm	struct archive_string	 symlink;
177231200Smm	int			 dircnt;	/* The number of elements of
178231200Smm						 * its parent directory */
179231200Smm
180231200Smm	/*
181231200Smm	 * Used for a Directory Record.
182231200Smm	 */
183231200Smm	struct content {
184231200Smm		int64_t		 offset_of_temp;
185231200Smm		int64_t		 size;
186231200Smm		int		 blocks;
187231200Smm		uint32_t 	 location;
188231200Smm		/*
189231200Smm		 * One extent equals one content.
190231200Smm		 * If this entry has multi extent, `next' variable points
191231200Smm		 * next content data.
192231200Smm		 */
193231200Smm		struct content	*next;		/* next content	*/
194231200Smm	} content, *cur_content;
195231200Smm	int			 write_content;
196231200Smm
197231200Smm	enum {
198231200Smm		NO = 0,
199231200Smm		BOOT_CATALOG,
200302001Smm		BOOT_IMAGE
201231200Smm	} boot;
202231200Smm
203231200Smm	/*
204231200Smm	 * Used for a zisofs.
205231200Smm	 */
206231200Smm	struct {
207231200Smm		unsigned char	 header_size;
208231200Smm		unsigned char	 log2_bs;
209231200Smm		uint32_t	 uncompressed_size;
210231200Smm	} zisofs;
211231200Smm};
212231200Smm
213231200Smmstruct isoent {
214231200Smm	/* Keep `rbnode' at the first member of struct isoent. */
215231200Smm	struct archive_rb_node	 rbnode;
216231200Smm
217231200Smm	struct isofile		*file;
218231200Smm
219231200Smm	struct isoent		*parent;
220231200Smm	/* A list of children.(use chnext) */
221231200Smm	struct {
222231200Smm		struct isoent	*first;
223231200Smm		struct isoent	**last;
224231200Smm		int		 cnt;
225231200Smm	}			 children;
226231200Smm	struct archive_rb_tree	 rbtree;
227231200Smm
228231200Smm	/* A list of sub directories.(use drnext) */
229231200Smm	struct {
230231200Smm		struct isoent	*first;
231231200Smm		struct isoent	**last;
232231200Smm		int		 cnt;
233231200Smm	}			 subdirs;
234231200Smm	/* A sorted list of sub directories. */
235231200Smm	struct isoent		**children_sorted;
236231200Smm	/* Used for managing struct isoent list. */
237231200Smm	struct isoent		*chnext;
238231200Smm	struct isoent		*drnext;
239231200Smm	struct isoent		*ptnext;
240231200Smm
241231200Smm	/*
242231200Smm	 * Used for making a Directory Record.
243231200Smm	 */
244231200Smm	int			 dir_number;
245231200Smm	struct {
246231200Smm		int		 vd;
247231200Smm		int		 self;
248231200Smm		int		 parent;
249231200Smm		int		 normal;
250231200Smm	}			 dr_len;
251231200Smm	uint32_t 		 dir_location;
252231200Smm	int			 dir_block;
253231200Smm
254231200Smm	/*
255231200Smm	 * Identifier:
256231200Smm	 *   on primary, ISO9660 file/directory name.
257231200Smm	 *   on joliet, UCS2 file/directory name.
258231200Smm	 * ext_off   : offset of identifier extension.
259231200Smm	 * ext_len   : length of identifier extension.
260231200Smm	 * id_len    : byte size of identifier.
261231200Smm	 *   on primary, this is ext_off + ext_len + version length.
262231200Smm	 *   on joliet, this is ext_off + ext_len.
263231200Smm	 * mb_len    : length of multibyte-character of identifier.
264231200Smm	 *   on primary, mb_len and id_len are always the same.
265231200Smm	 *   on joliet, mb_len and id_len are different.
266231200Smm	 */
267231200Smm	char			*identifier;
268231200Smm	int			 ext_off;
269231200Smm	int			 ext_len;
270231200Smm	int			 id_len;
271231200Smm	int			 mb_len;
272231200Smm
273231200Smm	/*
274231200Smm	 * Used for making a Rockridge extension.
275231200Smm	 * This is a part of Directory Records.
276231200Smm	 */
277231200Smm	struct isoent		*rr_parent;
278231200Smm	struct isoent		*rr_child;
279231200Smm
280231200Smm	/* Extra Record.(which we call in this source file)
281231200Smm	 * A maximum size of the Directory Record is 254.
282231200Smm	 * so, if generated RRIP data of a file cannot into a Directory
283231200Smm	 * Record because of its size, that surplus data relocate this
284231200Smm	 * Extra Record.
285231200Smm	 */
286231200Smm	struct {
287231200Smm		struct extr_rec	*first;
288231200Smm		struct extr_rec	**last;
289231200Smm		struct extr_rec	*current;
290231200Smm	}			 extr_rec_list;
291231200Smm
292358090Smm	signed int		 virtual:1;
293231200Smm	/* If set to one, this file type is a directory.
294231200Smm	 * A convenience flag to be used as
295231200Smm	 * "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".
296231200Smm	 */
297358090Smm	signed int		 dir:1;
298231200Smm};
299231200Smm
300231200Smmstruct hardlink {
301231200Smm	struct archive_rb_node	 rbnode;
302231200Smm	int			 nlink;
303231200Smm	struct {
304231200Smm		struct isofile	*first;
305231200Smm		struct isofile	**last;
306231200Smm	}			 file_list;
307231200Smm};
308231200Smm
309231200Smm/*
310231200Smm * ISO writer options
311231200Smm */
312231200Smmstruct iso_option {
313231200Smm	/*
314231200Smm	 * Usage  : abstract-file=<value>
315231200Smm	 * Type   : string, max 37 bytes
316231200Smm	 * Default: Not specified
317231200Smm	 * COMPAT : mkisofs -abstract <value>
318231200Smm	 *
319231200Smm	 * Specifies Abstract Filename.
320231200Smm	 * This file shall be described in the Root Directory
321231200Smm	 * and containing a abstract statement.
322231200Smm	 */
323231200Smm	unsigned int	 abstract_file:1;
324231200Smm#define OPT_ABSTRACT_FILE_DEFAULT	0	/* Not specified */
325231200Smm#define ABSTRACT_FILE_SIZE		37
326231200Smm
327231200Smm	/*
328231200Smm	 * Usage  : application-id=<value>
329231200Smm	 * Type   : string, max 128 bytes
330231200Smm	 * Default: Not specified
331231200Smm	 * COMPAT : mkisofs -A/-appid <value>.
332231200Smm	 *
333231200Smm	 * Specifies Application Identifier.
334231200Smm	 * If the first byte is set to '_'(5F), the remaining
335231200Smm	 * bytes of this option shall specify an identifier
336231200Smm	 * for a file containing the identification of the
337231200Smm	 * application.
338231200Smm	 * This file shall be described in the Root Directory.
339231200Smm	 */
340231200Smm	unsigned int	 application_id:1;
341231200Smm#define OPT_APPLICATION_ID_DEFAULT	0	/* Use default identifier */
342231200Smm#define APPLICATION_IDENTIFIER_SIZE	128
343231200Smm
344231200Smm	/*
345231200Smm	 * Usage : !allow-vernum
346231200Smm	 * Type  : boolean
347231200Smm	 * Default: Enabled
348231200Smm	 *	  : Violates the ISO9660 standard if disable.
349231200Smm	 * COMPAT: mkisofs -N
350231200Smm	 *
351231200Smm	 * Allow filenames to use version numbers.
352231200Smm	 */
353231200Smm	unsigned int	 allow_vernum:1;
354231200Smm#define OPT_ALLOW_VERNUM_DEFAULT	1	/* Enabled */
355231200Smm
356231200Smm	/*
357231200Smm	 * Usage  : biblio-file=<value>
358231200Smm	 * Type   : string, max 37 bytes
359231200Smm	 * Default: Not specified
360231200Smm	 * COMPAT : mkisofs -biblio <value>
361231200Smm	 *
362231200Smm	 * Specifies Bibliographic Filename.
363231200Smm	 * This file shall be described in the Root Directory
364231200Smm	 * and containing bibliographic records.
365231200Smm	 */
366231200Smm	unsigned int	 biblio_file:1;
367231200Smm#define OPT_BIBLIO_FILE_DEFAULT		0	/* Not specified */
368231200Smm#define BIBLIO_FILE_SIZE		37
369231200Smm
370231200Smm	/*
371231200Smm	 * Usage  : boot=<value>
372231200Smm	 * Type   : string
373231200Smm	 * Default: Not specified
374231200Smm	 * COMPAT : mkisofs -b/-eltorito-boot <value>
375231200Smm	 *
376231200Smm	 * Specifies "El Torito" boot image file to make
377231200Smm	 * a bootable CD.
378231200Smm	 */
379231200Smm	unsigned int	 boot:1;
380231200Smm#define OPT_BOOT_DEFAULT		0	/* Not specified */
381231200Smm
382231200Smm	/*
383231200Smm	 * Usage  : boot-catalog=<value>
384231200Smm	 * Type   : string
385231200Smm	 * Default: "boot.catalog"
386231200Smm	 * COMPAT : mkisofs -c/-eltorito-catalog <value>
387231200Smm	 *
388231200Smm	 * Specifies a fullpath of El Torito boot catalog.
389231200Smm	 */
390231200Smm	unsigned int	 boot_catalog:1;
391231200Smm#define OPT_BOOT_CATALOG_DEFAULT	0	/* Not specified */
392231200Smm
393231200Smm	/*
394231200Smm	 * Usage  : boot-info-table
395231200Smm	 * Type   : boolean
396231200Smm	 * Default: Disabled
397231200Smm	 * COMPAT : mkisofs -boot-info-table
398231200Smm	 *
399231200Smm	 * Modify the boot image file specified by `boot'
400231200Smm	 * option; ISO writer stores boot file information
401231200Smm	 * into the boot file in ISO image at offset 8
402231200Smm	 * through offset 64.
403231200Smm	 */
404231200Smm	unsigned int	 boot_info_table:1;
405231200Smm#define OPT_BOOT_INFO_TABLE_DEFAULT	0	/* Disabled */
406231200Smm
407231200Smm	/*
408231200Smm	 * Usage  : boot-load-seg=<value>
409231200Smm	 * Type   : hexadecimal
410231200Smm	 * Default: Not specified
411231200Smm	 * COMPAT : mkisofs -boot-load-seg <value>
412231200Smm	 *
413231200Smm	 * Specifies a load segment for boot image.
414231200Smm	 * This is used with no-emulation mode.
415231200Smm	 */
416231200Smm	unsigned int	 boot_load_seg:1;
417231200Smm#define OPT_BOOT_LOAD_SEG_DEFAULT	0	/* Not specified */
418231200Smm
419231200Smm	/*
420231200Smm	 * Usage  : boot-load-size=<value>
421231200Smm	 * Type   : decimal
422231200Smm	 * Default: Not specified
423231200Smm	 * COMPAT : mkisofs -boot-load-size <value>
424231200Smm	 *
425231200Smm	 * Specifies a sector count for boot image.
426231200Smm	 * This is used with no-emulation mode.
427231200Smm	 */
428231200Smm	unsigned int	 boot_load_size:1;
429231200Smm#define OPT_BOOT_LOAD_SIZE_DEFAULT	0	/* Not specified */
430231200Smm
431231200Smm	/*
432231200Smm	 * Usage  : boot-type=<boot-media-type>
433231200Smm	 *        : 'no-emulation' : 'no emulation' image
434231200Smm	 *        :           'fd' : floppy disk image
435231200Smm	 *        :    'hard-disk' : hard disk image
436231200Smm	 * Type   : string
437231200Smm	 * Default: Auto detect
438231200Smm	 *        : We check a size of boot image;
439305192Smm	 *        : If the size is just 1.22M/1.44M/2.88M,
440231200Smm	 *        : we assume boot_type is 'fd';
441231200Smm	 *        : otherwise boot_type is 'no-emulation'.
442231200Smm	 * COMPAT :
443231200Smm	 *    boot=no-emulation
444231200Smm	 *	mkisofs -no-emul-boot
445231200Smm	 *    boot=fd
446231200Smm	 *	This is a default on the mkisofs.
447231200Smm	 *    boot=hard-disk
448231200Smm	 *	mkisofs -hard-disk-boot
449231200Smm	 *
450231200Smm	 * Specifies a type of "El Torito" boot image.
451231200Smm	 */
452231200Smm	unsigned int	 boot_type:2;
453231200Smm#define OPT_BOOT_TYPE_AUTO		0	/* auto detect		  */
454231200Smm#define OPT_BOOT_TYPE_NO_EMU		1	/* ``no emulation'' image */
455231200Smm#define OPT_BOOT_TYPE_FD		2	/* floppy disk image	  */
456231200Smm#define OPT_BOOT_TYPE_HARD_DISK		3	/* hard disk image	  */
457231200Smm#define OPT_BOOT_TYPE_DEFAULT		OPT_BOOT_TYPE_AUTO
458231200Smm
459231200Smm	/*
460231200Smm	 * Usage  : compression-level=<value>
461231200Smm	 * Type   : decimal
462231200Smm	 * Default: Not specified
463231200Smm	 * COMPAT : NONE
464231200Smm	 *
465231200Smm	 * Specifies compression level for option zisofs=direct.
466231200Smm	 */
467231200Smm	unsigned int	 compression_level:1;
468231200Smm#define OPT_COMPRESSION_LEVEL_DEFAULT	0	/* Not specified */
469231200Smm
470231200Smm	/*
471231200Smm	 * Usage  : copyright-file=<value>
472231200Smm	 * Type   : string, max 37 bytes
473231200Smm	 * Default: Not specified
474231200Smm	 * COMPAT : mkisofs -copyright <value>
475231200Smm	 *
476231200Smm	 * Specifies Copyright Filename.
477231200Smm	 * This file shall be described in the Root Directory
478231200Smm	 * and containing a copyright statement.
479231200Smm	 */
480231200Smm	unsigned int	 copyright_file:1;
481231200Smm#define OPT_COPYRIGHT_FILE_DEFAULT	0	/* Not specified */
482231200Smm#define COPYRIGHT_FILE_SIZE		37
483231200Smm
484231200Smm	/*
485231200Smm	 * Usage  : gid=<value>
486231200Smm	 * Type   : decimal
487231200Smm	 * Default: Not specified
488231200Smm	 * COMPAT : mkisofs -gid <value>
489231200Smm	 *
490231200Smm	 * Specifies a group id to rewrite the group id of all files.
491231200Smm	 */
492231200Smm	unsigned int	 gid:1;
493231200Smm#define OPT_GID_DEFAULT			0	/* Not specified */
494231200Smm
495231200Smm	/*
496231200Smm	 * Usage  : iso-level=[1234]
497231200Smm	 * Type   : decimal
498231200Smm	 * Default: 1
499231200Smm	 * COMPAT : mkisofs -iso-level <value>
500231200Smm	 *
501231200Smm	 * Specifies ISO9600 Level.
502231200Smm	 * Level 1: [DEFAULT]
503231200Smm	 *   - limits each file size less than 4Gi bytes;
504231200Smm	 *   - a File Name shall not contain more than eight
505231200Smm	 *     d-characters or eight d1-characters;
506231200Smm	 *   - a File Name Extension shall not contain more than
507231200Smm	 *     three d-characters or three d1-characters;
508231200Smm	 *   - a Directory Identifier shall not contain more
509231200Smm	 *     than eight d-characters or eight d1-characters.
510231200Smm	 * Level 2:
511231200Smm	 *   - limits each file size less than 4Giga bytes;
512231200Smm	 *   - a File Name shall not contain more than thirty
513231200Smm	 *     d-characters or thirty d1-characters;
514231200Smm	 *   - a File Name Extension shall not contain more than
515231200Smm	 *     thirty d-characters or thirty d1-characters;
516231200Smm	 *   - a Directory Identifier shall not contain more
517231200Smm	 *     than thirty-one d-characters or thirty-one
518231200Smm	 *     d1-characters.
519231200Smm	 * Level 3:
520231200Smm	 *   - no limit of file size; use multi extent.
521231200Smm	 * Level 4:
522231200Smm	 *   - this level 4 simulates mkisofs option
523231200Smm	 *     '-iso-level 4';
524231200Smm	 *   - crate a enhanced volume as mkisofs doing;
525231200Smm	 *   - allow a File Name to have leading dot;
526231200Smm	 *   - allow a File Name to have all ASCII letters;
527231200Smm	 *   - allow a File Name to have multiple dots;
528231200Smm	 *   - allow more then 8 depths of directory trees;
529231200Smm	 *   - disable a version number to a File Name;
530231200Smm	 *   - disable a forced period to the tail of a File Name;
531313571Smm	 *   - the maximum length of files and directories is raised to 193.
532231200Smm	 *     if rockridge option is disabled, raised to 207.
533231200Smm	 */
534231200Smm	unsigned int	 iso_level:3;
535231200Smm#define OPT_ISO_LEVEL_DEFAULT		1	/* ISO Level 1 */
536231200Smm
537231200Smm	/*
538231200Smm	 * Usage  : joliet[=long]
539231200Smm	 *        : !joliet
540231200Smm	 *        :   Do not generate Joliet Volume and Records.
541231200Smm	 *        : joliet [DEFAULT]
542231200Smm	 *        :   Generates Joliet Volume and Directory Records.
543231200Smm	 *        :   [COMPAT: mkisofs -J/-joliet]
544231200Smm	 *        : joliet=long
545231200Smm	 *        :   The joliet filenames are up to 103 Unicode
546231200Smm	 *        :   characters.
547231200Smm	 *        :   This option breaks the Joliet specification.
548231200Smm	 *        :   [COMPAT: mkisofs -J -joliet-long]
549231200Smm	 * Type   : boolean/string
550231200Smm	 * Default: Enabled
551231200Smm	 * COMPAT : mkisofs -J / -joliet-long
552231200Smm	 *
553231200Smm	 * Generates Joliet Volume and Directory Records.
554231200Smm	 */
555231200Smm	unsigned int	 joliet:2;
556231200Smm#define OPT_JOLIET_DISABLE		0	/* Not generate Joliet Records. */
557231200Smm#define OPT_JOLIET_ENABLE		1	/* Generate Joliet Records.  */
558231200Smm#define OPT_JOLIET_LONGNAME		2	/* Use long joliet filenames.*/
559231200Smm#define OPT_JOLIET_DEFAULT		OPT_JOLIET_ENABLE
560231200Smm
561231200Smm	/*
562231200Smm	 * Usage  : !limit-depth
563231200Smm	 * Type   : boolean
564231200Smm	 * Default: Enabled
565231200Smm	 *	  : Violates the ISO9660 standard if disable.
566231200Smm	 * COMPAT : mkisofs -D/-disable-deep-relocation
567231200Smm	 *
568231200Smm	 * The number of levels in hierarchy cannot exceed eight.
569231200Smm	 */
570231200Smm	unsigned int	 limit_depth:1;
571231200Smm#define OPT_LIMIT_DEPTH_DEFAULT		1	/* Enabled */
572231200Smm
573231200Smm	/*
574231200Smm	 * Usage  : !limit-dirs
575231200Smm	 * Type   : boolean
576231200Smm	 * Default: Enabled
577231200Smm	 *	  : Violates the ISO9660 standard if disable.
578231200Smm	 * COMPAT : mkisofs -no-limit-pathtables
579231200Smm	 *
580231200Smm	 * Limits the number of directories less than 65536 due
581231200Smm	 * to the size of the Parent Directory Number of Path
582231200Smm	 * Table.
583231200Smm	 */
584231200Smm	unsigned int	 limit_dirs:1;
585231200Smm#define OPT_LIMIT_DIRS_DEFAULT		1	/* Enabled */
586231200Smm
587231200Smm	/*
588231200Smm	 * Usage  : !pad
589231200Smm	 * Type   : boolean
590231200Smm	 * Default: Enabled
591231200Smm	 * COMPAT : -pad/-no-pad
592231200Smm	 *
593231200Smm	 * Pads the end of the ISO image by null of 300Ki bytes.
594231200Smm	 */
595231200Smm	unsigned int	 pad:1;
596231200Smm#define OPT_PAD_DEFAULT			1	/* Enabled */
597231200Smm
598231200Smm	/*
599231200Smm	 * Usage  : publisher=<value>
600231200Smm	 * Type   : string, max 128 bytes
601231200Smm	 * Default: Not specified
602231200Smm	 * COMPAT : mkisofs -publisher <value>
603231200Smm	 *
604231200Smm	 * Specifies Publisher Identifier.
605231200Smm	 * If the first byte is set to '_'(5F), the remaining
606231200Smm	 * bytes of this option shall specify an identifier
607231200Smm	 * for a file containing the identification of the user.
608231200Smm	 * This file shall be described in the Root Directory.
609231200Smm	 */
610231200Smm	unsigned int	 publisher:1;
611231200Smm#define OPT_PUBLISHER_DEFAULT		0	/* Not specified */
612231200Smm#define PUBLISHER_IDENTIFIER_SIZE	128
613231200Smm
614231200Smm	/*
615231200Smm	 * Usage  : rockridge
616231200Smm	 *        : !rockridge
617231200Smm	 *        :    disable to generate SUSP and RR records.
618231200Smm	 *        : rockridge
619231200Smm	 *        :    the same as 'rockridge=useful'.
620231200Smm	 *        : rockridge=strict
621231200Smm	 *        :    generate SUSP and RR records.
622231200Smm	 *        :    [COMPAT: mkisofs -R]
623231200Smm	 *        : rockridge=useful [DEFAULT]
624231200Smm	 *        :    generate SUSP and RR records.
625231200Smm	 *        :    [COMPAT: mkisofs -r]
626231200Smm	 *        :    NOTE  Our rockridge=useful option does not set a zero
627231200Smm	 *        :          to uid and gid, you should use application
628231200Smm	 *        :          option such as --gid,--gname,--uid and --uname
629313571Smm	 *        :          bsdtar options instead.
630231200Smm	 * Type   : boolean/string
631231200Smm	 * Default: Enabled as rockridge=useful
632231200Smm	 * COMPAT : mkisofs -r / -R
633231200Smm	 *
634231200Smm	 * Generates SUSP and RR records.
635231200Smm	 */
636231200Smm	unsigned int	 rr:2;
637231200Smm#define OPT_RR_DISABLED			0
638231200Smm#define OPT_RR_STRICT			1
639231200Smm#define OPT_RR_USEFUL			2
640231200Smm#define OPT_RR_DEFAULT			OPT_RR_USEFUL
641231200Smm
642231200Smm	/*
643231200Smm	 * Usage  : volume-id=<value>
644231200Smm	 * Type   : string, max 32 bytes
645231200Smm	 * Default: Not specified
646231200Smm	 * COMPAT : mkisofs -V <value>
647231200Smm	 *
648231200Smm	 * Specifies Volume Identifier.
649231200Smm	 */
650231200Smm	unsigned int	 volume_id:1;
651231200Smm#define OPT_VOLUME_ID_DEFAULT		0	/* Use default identifier */
652231200Smm#define VOLUME_IDENTIFIER_SIZE		32
653231200Smm
654231200Smm	/*
655231200Smm	 * Usage  : !zisofs [DEFAULT]
656231200Smm	 *        :    Disable to generate RRIP 'ZF' extension.
657231200Smm	 *        : zisofs
658231200Smm	 *        :    Make files zisofs file and generate RRIP 'ZF'
659231200Smm 	 *        :    extension. So you do not need mkzftree utility
660231200Smm	 *        :    for making zisofs.
661231200Smm	 *        :    When the file size is less than one Logical Block
662231200Smm	 *        :    size, that file will not zisofs'ed since it does
663313571Smm	 *        :    reduce an ISO-image size.
664231200Smm	 *        :
665231200Smm	 *        :    When you specify option 'boot=<boot-image>', that
666231200Smm	 *        :    'boot-image' file won't be converted to zisofs file.
667231200Smm	 * Type   : boolean
668231200Smm	 * Default: Disabled
669231200Smm	 *
670231200Smm	 * Generates RRIP 'ZF' System Use Entry.
671231200Smm	 */
672231200Smm	unsigned int	 zisofs:1;
673231200Smm#define OPT_ZISOFS_DISABLED		0
674231200Smm#define OPT_ZISOFS_DIRECT		1
675231200Smm#define OPT_ZISOFS_DEFAULT		OPT_ZISOFS_DISABLED
676231200Smm
677231200Smm};
678231200Smm
679231200Smmstruct iso9660 {
680231200Smm	/* The creation time of ISO image. */
681231200Smm	time_t			 birth_time;
682231200Smm	/* A file stream of a temporary file, which file contents
683311042Smm	 * save to until ISO image can be created. */
684231200Smm	int			 temp_fd;
685231200Smm
686231200Smm	struct isofile		*cur_file;
687231200Smm	struct isoent		*cur_dirent;
688231200Smm	struct archive_string	 cur_dirstr;
689231200Smm	uint64_t		 bytes_remaining;
690231200Smm	int			 need_multi_extent;
691231200Smm
692231200Smm	/* Temporary string buffer for Joliet extension. */
693231200Smm	struct archive_string	 utf16be;
694231200Smm	struct archive_string	 mbs;
695231200Smm
696231200Smm	struct archive_string_conv *sconv_to_utf16be;
697231200Smm	struct archive_string_conv *sconv_from_utf16be;
698231200Smm
699231200Smm	/* A list of all of struct isofile entries. */
700231200Smm	struct {
701231200Smm		struct isofile	*first;
702231200Smm		struct isofile	**last;
703231200Smm	}			 all_file_list;
704231200Smm
705231200Smm	/* A list of struct isofile entries which have its
706313571Smm	 * contents and are not a directory, a hardlinked file
707231200Smm	 * and a symlink file. */
708231200Smm	struct {
709231200Smm		struct isofile	*first;
710231200Smm		struct isofile	**last;
711231200Smm	}			 data_file_list;
712231200Smm
713231200Smm	/* Used for managing to find hardlinking files. */
714231200Smm	struct archive_rb_tree	 hardlink_rbtree;
715231200Smm
716231200Smm	/* Used for making the Path Table Record. */
717231200Smm	struct vdd {
718231200Smm		/* the root of entry tree. */
719231200Smm		struct isoent	*rootent;
720231200Smm		enum vdd_type {
721231200Smm			VDD_PRIMARY,
722231200Smm			VDD_JOLIET,
723231200Smm			VDD_ENHANCED
724231200Smm		} vdd_type;
725231200Smm
726231200Smm		struct path_table {
727231200Smm			struct isoent		*first;
728231200Smm			struct isoent		**last;
729231200Smm			struct isoent		**sorted;
730231200Smm			int			 cnt;
731231200Smm		} *pathtbl;
732231200Smm		int				 max_depth;
733231200Smm
734231200Smm		int		 path_table_block;
735231200Smm		int		 path_table_size;
736231200Smm		int		 location_type_L_path_table;
737231200Smm		int		 location_type_M_path_table;
738231200Smm		int		 total_dir_block;
739231200Smm	} primary, joliet;
740231200Smm
741231200Smm	/* Used for making a Volume Descriptor. */
742231200Smm	int			 volume_space_size;
743231200Smm	int			 volume_sequence_number;
744231200Smm	int			 total_file_block;
745231200Smm	struct archive_string	 volume_identifier;
746231200Smm	struct archive_string	 publisher_identifier;
747231200Smm	struct archive_string	 data_preparer_identifier;
748231200Smm	struct archive_string	 application_identifier;
749231200Smm	struct archive_string	 copyright_file_identifier;
750231200Smm	struct archive_string	 abstract_file_identifier;
751231200Smm	struct archive_string	 bibliographic_file_identifier;
752231200Smm
753231200Smm	/* Used for making rockridge extensions. */
754231200Smm	int			 location_rrip_er;
755231200Smm
756231200Smm	/* Used for making zisofs. */
757231200Smm	struct {
758358090Smm		signed int	 detect_magic:1;
759358090Smm		signed int	 making:1;
760358090Smm		signed int	 allzero:1;
761231200Smm		unsigned char	 magic_buffer[64];
762231200Smm		int		 magic_cnt;
763231200Smm
764231200Smm#ifdef HAVE_ZLIB_H
765231200Smm		/*
766231200Smm		 * Copy a compressed file to iso9660.zisofs.temp_fd
767231200Smm		 * and also copy a uncompressed file(original file) to
768231200Smm		 * iso9660.temp_fd . If the number of logical block
769231200Smm		 * of the compressed file is less than the number of
770231200Smm		 * logical block of the uncompressed file, use it and
771231200Smm		 * remove the copy of the uncompressed file.
772231200Smm		 * but if not, we use uncompressed file and remove
773231200Smm		 * the copy of the compressed file.
774231200Smm		 */
775231200Smm		uint32_t	*block_pointers;
776231200Smm		size_t		 block_pointers_allocated;
777231200Smm		int		 block_pointers_cnt;
778231200Smm		int		 block_pointers_idx;
779231200Smm		int64_t		 total_size;
780231200Smm		int64_t		 block_offset;
781231200Smm
782231200Smm		z_stream	 stream;
783231200Smm		int		 stream_valid;
784231200Smm		int64_t		 remaining;
785231200Smm		int		 compression_level;
786231200Smm#endif
787231200Smm	} zisofs;
788231200Smm
789231200Smm	struct isoent		*directories_too_deep;
790231200Smm	int			 dircnt_max;
791231200Smm
792231200Smm	/* Write buffer. */
793231200Smm#define wb_buffmax()	(LOGICAL_BLOCK_SIZE * 32)
794231200Smm#define wb_remaining(a)	(((struct iso9660 *)(a)->format_data)->wbuff_remaining)
795231200Smm#define wb_offset(a)	(((struct iso9660 *)(a)->format_data)->wbuff_offset \
796231200Smm		+ wb_buffmax() - wb_remaining(a))
797231200Smm	unsigned char		 wbuff[LOGICAL_BLOCK_SIZE * 32];
798231200Smm	size_t			 wbuff_remaining;
799231200Smm	enum {
800231200Smm		WB_TO_STREAM,
801231200Smm		WB_TO_TEMP
802231200Smm	} 			 wbuff_type;
803231200Smm	int64_t			 wbuff_offset;
804231200Smm	int64_t			 wbuff_written;
805231200Smm	int64_t			 wbuff_tail;
806231200Smm
807231200Smm	/* 'El Torito' boot data. */
808231200Smm	struct {
809231200Smm		/* boot catalog file */
810231200Smm		struct archive_string	 catalog_filename;
811231200Smm		struct isoent		*catalog;
812231200Smm		/* boot image file */
813231200Smm		struct archive_string	 boot_filename;
814231200Smm		struct isoent		*boot;
815231200Smm
816231200Smm		unsigned char		 platform_id;
817231200Smm#define BOOT_PLATFORM_X86	0
818231200Smm#define BOOT_PLATFORM_PPC	1
819231200Smm#define BOOT_PLATFORM_MAC	2
820231200Smm		struct archive_string	 id;
821231200Smm		unsigned char		 media_type;
822231200Smm#define BOOT_MEDIA_NO_EMULATION		0
823231200Smm#define BOOT_MEDIA_1_2M_DISKETTE	1
824231200Smm#define BOOT_MEDIA_1_44M_DISKETTE	2
825231200Smm#define BOOT_MEDIA_2_88M_DISKETTE	3
826231200Smm#define BOOT_MEDIA_HARD_DISK		4
827231200Smm		unsigned char		 system_type;
828231200Smm		uint16_t		 boot_load_seg;
829231200Smm		uint16_t		 boot_load_size;
830231200Smm#define BOOT_LOAD_SIZE		4
831231200Smm	} el_torito;
832231200Smm
833231200Smm	struct iso_option	 opt;
834231200Smm};
835231200Smm
836231200Smm/*
837231200Smm * Types of Volume Descriptor
838231200Smm */
839231200Smmenum VD_type {
840231200Smm	VDT_BOOT_RECORD=0,	/* Boot Record Volume Descriptor 	*/
841231200Smm	VDT_PRIMARY=1,		/* Primary Volume Descriptor		*/
842231200Smm	VDT_SUPPLEMENTARY=2,	/* Supplementary Volume Descriptor	*/
843231200Smm	VDT_TERMINATOR=255	/* Volume Descriptor Set Terminator	*/
844231200Smm};
845231200Smm
846231200Smm/*
847231200Smm * Types of Directory Record
848231200Smm */
849231200Smmenum dir_rec_type {
850231200Smm	DIR_REC_VD,		/* Stored in Volume Descriptor.	*/
851231200Smm	DIR_REC_SELF,		/* Stored as Current Directory.	*/
852231200Smm	DIR_REC_PARENT,		/* Stored as Parent Directory.	*/
853302001Smm	DIR_REC_NORMAL 		/* Stored as Child.		*/
854231200Smm};
855231200Smm
856231200Smm/*
857231200Smm * Kinds of Volume Descriptor Character
858231200Smm */
859231200Smmenum vdc {
860231200Smm	VDC_STD,
861231200Smm	VDC_LOWERCASE,
862231200Smm	VDC_UCS2,
863302001Smm	VDC_UCS2_DIRECT
864231200Smm};
865231200Smm
866231200Smm/*
867231200Smm * IDentifier Resolver.
868231200Smm * Used for resolving duplicated filenames.
869231200Smm */
870231200Smmstruct idr {
871231200Smm	struct idrent {
872231200Smm		struct archive_rb_node	rbnode;
873231200Smm		/* Used in wait_list. */
874231200Smm		struct idrent		*wnext;
875231200Smm		struct idrent		*avail;
876231200Smm
877231200Smm		struct isoent		*isoent;
878231200Smm		int			 weight;
879231200Smm		int			 noff;
880231200Smm		int			 rename_num;
881231200Smm	} *idrent_pool;
882231200Smm
883231200Smm	struct archive_rb_tree		 rbtree;
884231200Smm
885231200Smm	struct {
886231200Smm		struct idrent		*first;
887231200Smm		struct idrent		**last;
888231200Smm	} wait_list;
889231200Smm
890231200Smm	int				 pool_size;
891231200Smm	int				 pool_idx;
892231200Smm	int				 num_size;
893231200Smm	int				 null_size;
894231200Smm
895231200Smm	char				 char_map[0x80];
896231200Smm};
897231200Smm
898231200Smmenum char_type {
899231200Smm	A_CHAR,
900302001Smm	D_CHAR
901231200Smm};
902231200Smm
903231200Smm
904231200Smmstatic int	iso9660_options(struct archive_write *,
905231200Smm		    const char *, const char *);
906231200Smmstatic int	iso9660_write_header(struct archive_write *,
907231200Smm		    struct archive_entry *);
908231200Smmstatic ssize_t	iso9660_write_data(struct archive_write *,
909231200Smm		    const void *, size_t);
910231200Smmstatic int	iso9660_finish_entry(struct archive_write *);
911231200Smmstatic int	iso9660_close(struct archive_write *);
912231200Smmstatic int	iso9660_free(struct archive_write *);
913231200Smm
914231200Smmstatic void	get_system_identitier(char *, size_t);
915231200Smmstatic void	set_str(unsigned char *, const char *, size_t, char,
916231200Smm		    const char *);
917231200Smmstatic inline int joliet_allowed_char(unsigned char, unsigned char);
918231200Smmstatic int	set_str_utf16be(struct archive_write *, unsigned char *,
919231200Smm			const char *, size_t, uint16_t, enum vdc);
920231200Smmstatic int	set_str_a_characters_bp(struct archive_write *,
921231200Smm			unsigned char *, int, int, const char *, enum vdc);
922231200Smmstatic int	set_str_d_characters_bp(struct archive_write *,
923231200Smm			unsigned char *, int, int, const char *, enum  vdc);
924231200Smmstatic void	set_VD_bp(unsigned char *, enum VD_type, unsigned char);
925231200Smmstatic inline void set_unused_field_bp(unsigned char *, int, int);
926231200Smm
927231200Smmstatic unsigned char *extra_open_record(unsigned char *, int,
928231200Smm		    struct isoent *, struct ctl_extr_rec *);
929231200Smmstatic void	extra_close_record(struct ctl_extr_rec *, int);
930231200Smmstatic unsigned char * extra_next_record(struct ctl_extr_rec *, int);
931231200Smmstatic unsigned char *extra_get_record(struct isoent *, int *, int *, int *);
932231200Smmstatic void	extra_tell_used_size(struct ctl_extr_rec *, int);
933231200Smmstatic int	extra_setup_location(struct isoent *, int);
934231200Smmstatic int	set_directory_record_rr(unsigned char *, int,
935231200Smm		    struct isoent *, struct iso9660 *, enum dir_rec_type);
936231200Smmstatic int	set_directory_record(unsigned char *, size_t,
937231200Smm		    struct isoent *, struct iso9660 *, enum dir_rec_type,
938231200Smm		    enum vdd_type);
939231200Smmstatic inline int get_dir_rec_size(struct iso9660 *, struct isoent *,
940231200Smm		    enum dir_rec_type, enum vdd_type);
941231200Smmstatic inline unsigned char *wb_buffptr(struct archive_write *);
942231200Smmstatic int	wb_write_out(struct archive_write *);
943231200Smmstatic int	wb_consume(struct archive_write *, size_t);
944231200Smm#ifdef HAVE_ZLIB_H
945231200Smmstatic int	wb_set_offset(struct archive_write *, int64_t);
946231200Smm#endif
947231200Smmstatic int	write_null(struct archive_write *, size_t);
948231200Smmstatic int	write_VD_terminator(struct archive_write *);
949231200Smmstatic int	set_file_identifier(unsigned char *, int, int, enum vdc,
950231200Smm		    struct archive_write *, struct vdd *,
951231200Smm		    struct archive_string *, const char *, int,
952231200Smm		    enum char_type);
953231200Smmstatic int	write_VD(struct archive_write *, struct vdd *);
954231200Smmstatic int	write_VD_boot_record(struct archive_write *);
955231200Smmstatic int	write_information_block(struct archive_write *);
956231200Smmstatic int	write_path_table(struct archive_write *, int,
957231200Smm		    struct vdd *);
958231200Smmstatic int	write_directory_descriptors(struct archive_write *,
959231200Smm		    struct vdd *);
960231200Smmstatic int	write_file_descriptors(struct archive_write *);
961231200Smmstatic int	write_rr_ER(struct archive_write *);
962231200Smmstatic void	calculate_path_table_size(struct vdd *);
963231200Smm
964231200Smmstatic void	isofile_init_entry_list(struct iso9660 *);
965231200Smmstatic void	isofile_add_entry(struct iso9660 *, struct isofile *);
966231200Smmstatic void	isofile_free_all_entries(struct iso9660 *);
967231200Smmstatic void	isofile_init_entry_data_file_list(struct iso9660 *);
968231200Smmstatic void	isofile_add_data_file(struct iso9660 *, struct isofile *);
969231200Smmstatic struct isofile * isofile_new(struct archive_write *,
970231200Smm		    struct archive_entry *);
971231200Smmstatic void	isofile_free(struct isofile *);
972231200Smmstatic int	isofile_gen_utility_names(struct archive_write *,
973231200Smm		    struct isofile *);
974231200Smmstatic int	isofile_register_hardlink(struct archive_write *,
975231200Smm		    struct isofile *);
976231200Smmstatic void	isofile_connect_hardlink_files(struct iso9660 *);
977231200Smmstatic void	isofile_init_hardlinks(struct iso9660 *);
978231200Smmstatic void	isofile_free_hardlinks(struct iso9660 *);
979231200Smm
980231200Smmstatic struct isoent *isoent_new(struct isofile *);
981231200Smmstatic int	isoent_clone_tree(struct archive_write *,
982231200Smm		    struct isoent **, struct isoent *);
983231200Smmstatic void	_isoent_free(struct isoent *isoent);
984231200Smmstatic void	isoent_free_all(struct isoent *);
985231200Smmstatic struct isoent * isoent_create_virtual_dir(struct archive_write *,
986231200Smm		    struct iso9660 *, const char *);
987231200Smmstatic int	isoent_cmp_node(const struct archive_rb_node *,
988231200Smm		    const struct archive_rb_node *);
989231200Smmstatic int	isoent_cmp_key(const struct archive_rb_node *,
990231200Smm		    const void *);
991231200Smmstatic int	isoent_add_child_head(struct isoent *, struct isoent *);
992231200Smmstatic int	isoent_add_child_tail(struct isoent *, struct isoent *);
993231200Smmstatic void	isoent_remove_child(struct isoent *, struct isoent *);
994231200Smmstatic void	isoent_setup_directory_location(struct iso9660 *,
995231200Smm		    int, struct vdd *);
996231200Smmstatic void	isoent_setup_file_location(struct iso9660 *, int);
997248616Smmstatic int	get_path_component(char *, size_t, const char *);
998231200Smmstatic int	isoent_tree(struct archive_write *, struct isoent **);
999231200Smmstatic struct isoent *isoent_find_child(struct isoent *, const char *);
1000231200Smmstatic struct isoent *isoent_find_entry(struct isoent *, const char *);
1001231200Smmstatic void	idr_relaxed_filenames(char *);
1002231200Smmstatic void	idr_init(struct iso9660 *, struct vdd *, struct idr *);
1003231200Smmstatic void	idr_cleanup(struct idr *);
1004231200Smmstatic int	idr_ensure_poolsize(struct archive_write *, struct idr *,
1005231200Smm		    int);
1006231200Smmstatic int	idr_start(struct archive_write *, struct idr *,
1007231200Smm		    int, int, int, int, const struct archive_rb_tree_ops *);
1008231200Smmstatic void	idr_register(struct idr *, struct isoent *, int,
1009231200Smm		    int);
1010231200Smmstatic void	idr_extend_identifier(struct idrent *, int, int);
1011231200Smmstatic void	idr_resolve(struct idr *, void (*)(unsigned char *, int));
1012231200Smmstatic void	idr_set_num(unsigned char *, int);
1013231200Smmstatic void	idr_set_num_beutf16(unsigned char *, int);
1014231200Smmstatic int	isoent_gen_iso9660_identifier(struct archive_write *,
1015231200Smm		    struct isoent *, struct idr *);
1016231200Smmstatic int	isoent_gen_joliet_identifier(struct archive_write *,
1017231200Smm		    struct isoent *, struct idr *);
1018231200Smmstatic int	isoent_cmp_iso9660_identifier(const struct isoent *,
1019231200Smm		    const struct isoent *);
1020231200Smmstatic int	isoent_cmp_node_iso9660(const struct archive_rb_node *,
1021231200Smm		    const struct archive_rb_node *);
1022231200Smmstatic int	isoent_cmp_key_iso9660(const struct archive_rb_node *,
1023231200Smm		    const void *);
1024231200Smmstatic int	isoent_cmp_joliet_identifier(const struct isoent *,
1025231200Smm		    const struct isoent *);
1026231200Smmstatic int	isoent_cmp_node_joliet(const struct archive_rb_node *,
1027231200Smm		    const struct archive_rb_node *);
1028231200Smmstatic int	isoent_cmp_key_joliet(const struct archive_rb_node *,
1029231200Smm		    const void *);
1030231200Smmstatic inline void path_table_add_entry(struct path_table *, struct isoent *);
1031231200Smmstatic inline struct isoent * path_table_last_entry(struct path_table *);
1032231200Smmstatic int	isoent_make_path_table(struct archive_write *);
1033231200Smmstatic int	isoent_find_out_boot_file(struct archive_write *,
1034231200Smm		    struct isoent *);
1035231200Smmstatic int	isoent_create_boot_catalog(struct archive_write *,
1036231200Smm		    struct isoent *);
1037231200Smmstatic size_t	fd_boot_image_size(int);
1038231200Smmstatic int	make_boot_catalog(struct archive_write *);
1039231200Smmstatic int	setup_boot_information(struct archive_write *);
1040231200Smm
1041231200Smmstatic int	zisofs_init(struct archive_write *, struct isofile *);
1042231200Smmstatic void	zisofs_detect_magic(struct archive_write *,
1043231200Smm		    const void *, size_t);
1044231200Smmstatic int	zisofs_write_to_temp(struct archive_write *,
1045231200Smm		    const void *, size_t);
1046231200Smmstatic int	zisofs_finish_entry(struct archive_write *);
1047231200Smmstatic int	zisofs_rewind_boot_file(struct archive_write *);
1048231200Smmstatic int	zisofs_free(struct archive_write *);
1049231200Smm
1050231200Smmint
1051231200Smmarchive_write_set_format_iso9660(struct archive *_a)
1052231200Smm{
1053231200Smm	struct archive_write *a = (struct archive_write *)_a;
1054231200Smm	struct iso9660 *iso9660;
1055231200Smm
1056231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
1057231200Smm	    ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");
1058231200Smm
1059231200Smm	/* If another format was already registered, unregister it. */
1060231200Smm	if (a->format_free != NULL)
1061231200Smm		(a->format_free)(a);
1062231200Smm
1063231200Smm	iso9660 = calloc(1, sizeof(*iso9660));
1064231200Smm	if (iso9660 == NULL) {
1065231200Smm		archive_set_error(&a->archive, ENOMEM,
1066231200Smm		    "Can't allocate iso9660 data");
1067231200Smm		return (ARCHIVE_FATAL);
1068231200Smm	}
1069231200Smm	iso9660->birth_time = 0;
1070231200Smm	iso9660->temp_fd = -1;
1071231200Smm	iso9660->cur_file = NULL;
1072231200Smm	iso9660->primary.max_depth = 0;
1073231200Smm	iso9660->primary.vdd_type = VDD_PRIMARY;
1074231200Smm	iso9660->primary.pathtbl = NULL;
1075231200Smm	iso9660->joliet.rootent = NULL;
1076231200Smm	iso9660->joliet.max_depth = 0;
1077231200Smm	iso9660->joliet.vdd_type = VDD_JOLIET;
1078231200Smm	iso9660->joliet.pathtbl = NULL;
1079231200Smm	isofile_init_entry_list(iso9660);
1080231200Smm	isofile_init_entry_data_file_list(iso9660);
1081231200Smm	isofile_init_hardlinks(iso9660);
1082231200Smm	iso9660->directories_too_deep = NULL;
1083231200Smm	iso9660->dircnt_max = 1;
1084231200Smm	iso9660->wbuff_remaining = wb_buffmax();
1085231200Smm	iso9660->wbuff_type = WB_TO_TEMP;
1086231200Smm	iso9660->wbuff_offset = 0;
1087231200Smm	iso9660->wbuff_written = 0;
1088231200Smm	iso9660->wbuff_tail = 0;
1089231200Smm	archive_string_init(&(iso9660->utf16be));
1090231200Smm	archive_string_init(&(iso9660->mbs));
1091231200Smm
1092231200Smm	/*
1093231200Smm	 * Init Identifiers used for PVD and SVD.
1094231200Smm	 */
1095231200Smm	archive_string_init(&(iso9660->volume_identifier));
1096231200Smm	archive_strcpy(&(iso9660->volume_identifier), "CDROM");
1097231200Smm	archive_string_init(&(iso9660->publisher_identifier));
1098231200Smm	archive_string_init(&(iso9660->data_preparer_identifier));
1099231200Smm	archive_string_init(&(iso9660->application_identifier));
1100231200Smm	archive_strcpy(&(iso9660->application_identifier),
1101231200Smm	    archive_version_string());
1102231200Smm	archive_string_init(&(iso9660->copyright_file_identifier));
1103231200Smm	archive_string_init(&(iso9660->abstract_file_identifier));
1104231200Smm	archive_string_init(&(iso9660->bibliographic_file_identifier));
1105231200Smm
1106231200Smm	/*
1107231200Smm	 * Init El Torito bootable CD variables.
1108231200Smm	 */
1109231200Smm	archive_string_init(&(iso9660->el_torito.catalog_filename));
1110231200Smm	iso9660->el_torito.catalog = NULL;
1111231200Smm	/* Set default file name of boot catalog  */
1112231200Smm	archive_strcpy(&(iso9660->el_torito.catalog_filename),
1113231200Smm	    "boot.catalog");
1114231200Smm	archive_string_init(&(iso9660->el_torito.boot_filename));
1115231200Smm	iso9660->el_torito.boot = NULL;
1116231200Smm	iso9660->el_torito.platform_id = BOOT_PLATFORM_X86;
1117231200Smm	archive_string_init(&(iso9660->el_torito.id));
1118231200Smm	iso9660->el_torito.boot_load_seg = 0;
1119231200Smm	iso9660->el_torito.boot_load_size = BOOT_LOAD_SIZE;
1120231200Smm
1121231200Smm	/*
1122231200Smm	 * Init zisofs variables.
1123231200Smm	 */
1124231200Smm#ifdef HAVE_ZLIB_H
1125231200Smm	iso9660->zisofs.block_pointers = NULL;
1126231200Smm	iso9660->zisofs.block_pointers_allocated = 0;
1127231200Smm	iso9660->zisofs.stream_valid = 0;
1128231200Smm	iso9660->zisofs.compression_level = 9;
1129231200Smm	memset(&(iso9660->zisofs.stream), 0,
1130231200Smm	    sizeof(iso9660->zisofs.stream));
1131231200Smm#endif
1132231200Smm
1133231200Smm	/*
1134231200Smm	 * Set default value of iso9660 options.
1135231200Smm	 */
1136231200Smm	iso9660->opt.abstract_file = OPT_ABSTRACT_FILE_DEFAULT;
1137231200Smm	iso9660->opt.application_id = OPT_APPLICATION_ID_DEFAULT;
1138231200Smm	iso9660->opt.allow_vernum = OPT_ALLOW_VERNUM_DEFAULT;
1139231200Smm	iso9660->opt.biblio_file = OPT_BIBLIO_FILE_DEFAULT;
1140231200Smm	iso9660->opt.boot = OPT_BOOT_DEFAULT;
1141231200Smm	iso9660->opt.boot_catalog = OPT_BOOT_CATALOG_DEFAULT;
1142231200Smm	iso9660->opt.boot_info_table = OPT_BOOT_INFO_TABLE_DEFAULT;
1143231200Smm	iso9660->opt.boot_load_seg = OPT_BOOT_LOAD_SEG_DEFAULT;
1144231200Smm	iso9660->opt.boot_load_size = OPT_BOOT_LOAD_SIZE_DEFAULT;
1145231200Smm	iso9660->opt.boot_type = OPT_BOOT_TYPE_DEFAULT;
1146231200Smm	iso9660->opt.compression_level = OPT_COMPRESSION_LEVEL_DEFAULT;
1147231200Smm	iso9660->opt.copyright_file = OPT_COPYRIGHT_FILE_DEFAULT;
1148231200Smm	iso9660->opt.iso_level = OPT_ISO_LEVEL_DEFAULT;
1149231200Smm	iso9660->opt.joliet = OPT_JOLIET_DEFAULT;
1150231200Smm	iso9660->opt.limit_depth = OPT_LIMIT_DEPTH_DEFAULT;
1151231200Smm	iso9660->opt.limit_dirs = OPT_LIMIT_DIRS_DEFAULT;
1152231200Smm	iso9660->opt.pad = OPT_PAD_DEFAULT;
1153231200Smm	iso9660->opt.publisher = OPT_PUBLISHER_DEFAULT;
1154231200Smm	iso9660->opt.rr = OPT_RR_DEFAULT;
1155231200Smm	iso9660->opt.volume_id = OPT_VOLUME_ID_DEFAULT;
1156231200Smm	iso9660->opt.zisofs = OPT_ZISOFS_DEFAULT;
1157231200Smm
1158231200Smm	/* Create the root directory. */
1159231200Smm	iso9660->primary.rootent =
1160231200Smm	    isoent_create_virtual_dir(a, iso9660, "");
1161231200Smm	if (iso9660->primary.rootent == NULL) {
1162231200Smm		free(iso9660);
1163231200Smm		archive_set_error(&a->archive, ENOMEM,
1164231200Smm		    "Can't allocate memory");
1165231200Smm		return (ARCHIVE_FATAL);
1166231200Smm	}
1167231200Smm	iso9660->primary.rootent->parent = iso9660->primary.rootent;
1168231200Smm	iso9660->cur_dirent = iso9660->primary.rootent;
1169231200Smm	archive_string_init(&(iso9660->cur_dirstr));
1170231200Smm	archive_string_ensure(&(iso9660->cur_dirstr), 1);
1171231200Smm	iso9660->cur_dirstr.s[0] = 0;
1172231200Smm	iso9660->sconv_to_utf16be = NULL;
1173231200Smm	iso9660->sconv_from_utf16be = NULL;
1174231200Smm
1175231200Smm	a->format_data = iso9660;
1176231200Smm	a->format_name = "iso9660";
1177231200Smm	a->format_options = iso9660_options;
1178231200Smm	a->format_write_header = iso9660_write_header;
1179231200Smm	a->format_write_data = iso9660_write_data;
1180231200Smm	a->format_finish_entry = iso9660_finish_entry;
1181231200Smm	a->format_close = iso9660_close;
1182231200Smm	a->format_free = iso9660_free;
1183231200Smm	a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
1184231200Smm	a->archive.archive_format_name = "ISO9660";
1185231200Smm
1186231200Smm	return (ARCHIVE_OK);
1187231200Smm}
1188231200Smm
1189231200Smmstatic int
1190231200Smmget_str_opt(struct archive_write *a, struct archive_string *s,
1191231200Smm    size_t maxsize, const char *key, const char *value)
1192231200Smm{
1193231200Smm
1194231200Smm	if (strlen(value) > maxsize) {
1195231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1196231200Smm		    "Value is longer than %zu characters "
1197231200Smm		    "for option ``%s''", maxsize, key);
1198231200Smm		return (ARCHIVE_FATAL);
1199231200Smm	}
1200231200Smm	archive_strcpy(s, value);
1201231200Smm	return (ARCHIVE_OK);
1202231200Smm}
1203231200Smm
1204231200Smmstatic int
1205231200Smmget_num_opt(struct archive_write *a, int *num, int high, int low,
1206231200Smm    const char *key, const char *value)
1207231200Smm{
1208231200Smm	const char *p = value;
1209231200Smm	int data = 0;
1210231200Smm	int neg = 0;
1211231200Smm
1212231200Smm	if (p == NULL) {
1213231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1214231200Smm		    "Invalid value(empty) for option ``%s''", key);
1215231200Smm		return (ARCHIVE_FATAL);
1216231200Smm	}
1217231200Smm	if (*p == '-') {
1218231200Smm		neg = 1;
1219231200Smm		p++;
1220231200Smm	}
1221231200Smm	while (*p) {
1222231200Smm		if (*p >= '0' && *p <= '9')
1223231200Smm			data = data * 10 + *p - '0';
1224231200Smm		else {
1225231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1226231200Smm			    "Invalid value for option ``%s''", key);
1227231200Smm			return (ARCHIVE_FATAL);
1228231200Smm		}
1229231200Smm		if (data > high) {
1230231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1231231200Smm			    "Invalid value(over %d) for "
1232231200Smm			    "option ``%s''", high, key);
1233231200Smm			return (ARCHIVE_FATAL);
1234231200Smm		}
1235231200Smm		if (data < low) {
1236231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1237231200Smm			    "Invalid value(under %d) for "
1238231200Smm			    "option ``%s''", low, key);
1239231200Smm			return (ARCHIVE_FATAL);
1240231200Smm		}
1241231200Smm		p++;
1242231200Smm	}
1243231200Smm	if (neg)
1244231200Smm		data *= -1;
1245231200Smm	*num = data;
1246231200Smm
1247231200Smm	return (ARCHIVE_OK);
1248231200Smm}
1249231200Smm
1250231200Smmstatic int
1251231200Smmiso9660_options(struct archive_write *a, const char *key, const char *value)
1252231200Smm{
1253231200Smm	struct iso9660 *iso9660 = a->format_data;
1254231200Smm	const char *p;
1255231200Smm	int r;
1256231200Smm
1257231200Smm	switch (key[0]) {
1258231200Smm	case 'a':
1259231200Smm		if (strcmp(key, "abstract-file") == 0) {
1260231200Smm			r = get_str_opt(a,
1261231200Smm			    &(iso9660->abstract_file_identifier),
1262231200Smm			    ABSTRACT_FILE_SIZE, key, value);
1263231200Smm			iso9660->opt.abstract_file = r == ARCHIVE_OK;
1264231200Smm			return (r);
1265231200Smm		}
1266231200Smm		if (strcmp(key, "application-id") == 0) {
1267231200Smm			r = get_str_opt(a,
1268231200Smm			    &(iso9660->application_identifier),
1269231200Smm			    APPLICATION_IDENTIFIER_SIZE, key, value);
1270231200Smm			iso9660->opt.application_id = r == ARCHIVE_OK;
1271231200Smm			return (r);
1272231200Smm		}
1273231200Smm		if (strcmp(key, "allow-vernum") == 0) {
1274231200Smm			iso9660->opt.allow_vernum = value != NULL;
1275231200Smm			return (ARCHIVE_OK);
1276231200Smm		}
1277231200Smm		break;
1278231200Smm	case 'b':
1279231200Smm		if (strcmp(key, "biblio-file") == 0) {
1280231200Smm			r = get_str_opt(a,
1281231200Smm			    &(iso9660->bibliographic_file_identifier),
1282231200Smm			    BIBLIO_FILE_SIZE, key, value);
1283231200Smm			iso9660->opt.biblio_file = r == ARCHIVE_OK;
1284231200Smm			return (r);
1285231200Smm		}
1286231200Smm		if (strcmp(key, "boot") == 0) {
1287231200Smm			if (value == NULL)
1288231200Smm				iso9660->opt.boot = 0;
1289231200Smm			else {
1290231200Smm				iso9660->opt.boot = 1;
1291231200Smm				archive_strcpy(
1292231200Smm				    &(iso9660->el_torito.boot_filename),
1293231200Smm				    value);
1294231200Smm			}
1295231200Smm			return (ARCHIVE_OK);
1296231200Smm		}
1297231200Smm		if (strcmp(key, "boot-catalog") == 0) {
1298231200Smm			r = get_str_opt(a,
1299231200Smm			    &(iso9660->el_torito.catalog_filename),
1300231200Smm			    1024, key, value);
1301231200Smm			iso9660->opt.boot_catalog = r == ARCHIVE_OK;
1302231200Smm			return (r);
1303231200Smm		}
1304231200Smm		if (strcmp(key, "boot-info-table") == 0) {
1305231200Smm			iso9660->opt.boot_info_table = value != NULL;
1306231200Smm			return (ARCHIVE_OK);
1307231200Smm		}
1308231200Smm		if (strcmp(key, "boot-load-seg") == 0) {
1309231200Smm			uint32_t seg;
1310231200Smm
1311231200Smm			iso9660->opt.boot_load_seg = 0;
1312231200Smm			if (value == NULL)
1313231200Smm				goto invalid_value;
1314231200Smm			seg = 0;
1315231200Smm			p = value;
1316231200Smm			if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
1317231200Smm				p += 2;
1318231200Smm			while (*p) {
1319231200Smm				if (seg)
1320231200Smm					seg <<= 4;
1321231200Smm				if (*p >= 'A' && *p <= 'F')
1322231200Smm					seg += *p - 'A' + 0x0a;
1323231200Smm				else if (*p >= 'a' && *p <= 'f')
1324231200Smm					seg += *p - 'a' + 0x0a;
1325231200Smm				else if (*p >= '0' && *p <= '9')
1326231200Smm					seg += *p - '0';
1327231200Smm				else
1328231200Smm					goto invalid_value;
1329231200Smm				if (seg > 0xffff) {
1330231200Smm					archive_set_error(&a->archive,
1331231200Smm					    ARCHIVE_ERRNO_MISC,
1332231200Smm					    "Invalid value(over 0xffff) for "
1333231200Smm					    "option ``%s''", key);
1334231200Smm					return (ARCHIVE_FATAL);
1335231200Smm				}
1336231200Smm				p++;
1337231200Smm			}
1338231200Smm			iso9660->el_torito.boot_load_seg = (uint16_t)seg;
1339231200Smm			iso9660->opt.boot_load_seg = 1;
1340231200Smm			return (ARCHIVE_OK);
1341231200Smm		}
1342231200Smm		if (strcmp(key, "boot-load-size") == 0) {
1343231200Smm			int num = 0;
1344231200Smm			r = get_num_opt(a, &num, 0xffff, 1, key, value);
1345231200Smm			iso9660->opt.boot_load_size = r == ARCHIVE_OK;
1346231200Smm			if (r != ARCHIVE_OK)
1347231200Smm				return (ARCHIVE_FATAL);
1348231200Smm			iso9660->el_torito.boot_load_size = (uint16_t)num;
1349231200Smm			return (ARCHIVE_OK);
1350231200Smm		}
1351231200Smm		if (strcmp(key, "boot-type") == 0) {
1352231200Smm			if (value == NULL)
1353231200Smm				goto invalid_value;
1354231200Smm			if (strcmp(value, "no-emulation") == 0)
1355231200Smm				iso9660->opt.boot_type = OPT_BOOT_TYPE_NO_EMU;
1356231200Smm			else if (strcmp(value, "fd") == 0)
1357231200Smm				iso9660->opt.boot_type = OPT_BOOT_TYPE_FD;
1358231200Smm			else if (strcmp(value, "hard-disk") == 0)
1359231200Smm				iso9660->opt.boot_type = OPT_BOOT_TYPE_HARD_DISK;
1360231200Smm			else
1361231200Smm				goto invalid_value;
1362231200Smm			return (ARCHIVE_OK);
1363231200Smm		}
1364231200Smm		break;
1365231200Smm	case 'c':
1366231200Smm		if (strcmp(key, "compression-level") == 0) {
1367231200Smm#ifdef HAVE_ZLIB_H
1368231200Smm			if (value == NULL ||
1369231200Smm			    !(value[0] >= '0' && value[0] <= '9') ||
1370231200Smm			    value[1] != '\0')
1371231200Smm				goto invalid_value;
1372231200Smm                	iso9660->zisofs.compression_level = value[0] - '0';
1373231200Smm			iso9660->opt.compression_level = 1;
1374231200Smm                	return (ARCHIVE_OK);
1375231200Smm#else
1376231200Smm			archive_set_error(&a->archive,
1377231200Smm			    ARCHIVE_ERRNO_MISC,
1378231200Smm			    "Option ``%s'' "
1379231200Smm			    "is not supported on this platform.", key);
1380231200Smm			return (ARCHIVE_FATAL);
1381231200Smm#endif
1382231200Smm		}
1383231200Smm		if (strcmp(key, "copyright-file") == 0) {
1384231200Smm			r = get_str_opt(a,
1385231200Smm			    &(iso9660->copyright_file_identifier),
1386231200Smm			    COPYRIGHT_FILE_SIZE, key, value);
1387231200Smm			iso9660->opt.copyright_file = r == ARCHIVE_OK;
1388231200Smm			return (r);
1389231200Smm		}
1390231200Smm#ifdef DEBUG
1391231200Smm		/* Specifies Volume creation date and time;
1392231200Smm		 * year(4),month(2),day(2),hour(2),minute(2),second(2).
1393231200Smm		 * e.g. "20090929033757"
1394231200Smm		 */
1395231200Smm		if (strcmp(key, "creation") == 0) {
1396231200Smm			struct tm tm;
1397231200Smm			char buf[5];
1398231200Smm
1399231200Smm			p = value;
1400231200Smm			if (p == NULL || strlen(p) < 14)
1401231200Smm				goto invalid_value;
1402231200Smm			memset(&tm, 0, sizeof(tm));
1403231200Smm			memcpy(buf, p, 4); buf[4] = '\0'; p += 4;
1404231200Smm			tm.tm_year = strtol(buf, NULL, 10) - 1900;
1405231200Smm			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1406231200Smm			tm.tm_mon = strtol(buf, NULL, 10) - 1;
1407231200Smm			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1408231200Smm			tm.tm_mday = strtol(buf, NULL, 10);
1409231200Smm			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1410231200Smm			tm.tm_hour = strtol(buf, NULL, 10);
1411231200Smm			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1412231200Smm			tm.tm_min = strtol(buf, NULL, 10);
1413231200Smm			memcpy(buf, p, 2); buf[2] = '\0';
1414231200Smm			tm.tm_sec = strtol(buf, NULL, 10);
1415231200Smm			iso9660->birth_time = mktime(&tm);
1416231200Smm			return (ARCHIVE_OK);
1417231200Smm		}
1418231200Smm#endif
1419231200Smm		break;
1420231200Smm	case 'i':
1421231200Smm		if (strcmp(key, "iso-level") == 0) {
1422231200Smm			if (value != NULL && value[1] == '\0' &&
1423231200Smm			    (value[0] >= '1' && value[0] <= '4')) {
1424231200Smm				iso9660->opt.iso_level = value[0]-'0';
1425231200Smm				return (ARCHIVE_OK);
1426231200Smm			}
1427231200Smm			goto invalid_value;
1428231200Smm		}
1429231200Smm		break;
1430231200Smm	case 'j':
1431231200Smm		if (strcmp(key, "joliet") == 0) {
1432231200Smm			if (value == NULL)
1433231200Smm				iso9660->opt.joliet = OPT_JOLIET_DISABLE;
1434231200Smm			else if (strcmp(value, "1") == 0)
1435231200Smm				iso9660->opt.joliet = OPT_JOLIET_ENABLE;
1436231200Smm			else if (strcmp(value, "long") == 0)
1437231200Smm				iso9660->opt.joliet = OPT_JOLIET_LONGNAME;
1438231200Smm			else
1439231200Smm				goto invalid_value;
1440231200Smm			return (ARCHIVE_OK);
1441231200Smm		}
1442231200Smm		break;
1443231200Smm	case 'l':
1444231200Smm		if (strcmp(key, "limit-depth") == 0) {
1445231200Smm			iso9660->opt.limit_depth = value != NULL;
1446231200Smm			return (ARCHIVE_OK);
1447231200Smm		}
1448231200Smm		if (strcmp(key, "limit-dirs") == 0) {
1449231200Smm			iso9660->opt.limit_dirs = value != NULL;
1450231200Smm			return (ARCHIVE_OK);
1451231200Smm		}
1452231200Smm		break;
1453231200Smm	case 'p':
1454231200Smm		if (strcmp(key, "pad") == 0) {
1455231200Smm			iso9660->opt.pad = value != NULL;
1456231200Smm			return (ARCHIVE_OK);
1457231200Smm		}
1458231200Smm		if (strcmp(key, "publisher") == 0) {
1459231200Smm			r = get_str_opt(a,
1460231200Smm			    &(iso9660->publisher_identifier),
1461231200Smm			    PUBLISHER_IDENTIFIER_SIZE, key, value);
1462231200Smm			iso9660->opt.publisher = r == ARCHIVE_OK;
1463231200Smm			return (r);
1464231200Smm		}
1465231200Smm		break;
1466231200Smm	case 'r':
1467231200Smm		if (strcmp(key, "rockridge") == 0 ||
1468231200Smm		    strcmp(key, "Rockridge") == 0) {
1469231200Smm			if (value == NULL)
1470231200Smm				iso9660->opt.rr = OPT_RR_DISABLED;
1471231200Smm			else if (strcmp(value, "1") == 0)
1472231200Smm				iso9660->opt.rr = OPT_RR_USEFUL;
1473231200Smm			else if (strcmp(value, "strict") == 0)
1474231200Smm				iso9660->opt.rr = OPT_RR_STRICT;
1475231200Smm			else if (strcmp(value, "useful") == 0)
1476231200Smm				iso9660->opt.rr = OPT_RR_USEFUL;
1477231200Smm			else
1478231200Smm				goto invalid_value;
1479231200Smm			return (ARCHIVE_OK);
1480231200Smm		}
1481231200Smm		break;
1482231200Smm	case 'v':
1483231200Smm		if (strcmp(key, "volume-id") == 0) {
1484231200Smm			r = get_str_opt(a, &(iso9660->volume_identifier),
1485231200Smm			    VOLUME_IDENTIFIER_SIZE, key, value);
1486231200Smm			iso9660->opt.volume_id = r == ARCHIVE_OK;
1487231200Smm			return (r);
1488231200Smm		}
1489231200Smm		break;
1490231200Smm	case 'z':
1491231200Smm		if (strcmp(key, "zisofs") == 0) {
1492231200Smm			if (value == NULL)
1493231200Smm				iso9660->opt.zisofs = OPT_ZISOFS_DISABLED;
1494231200Smm			else {
1495231200Smm#ifdef HAVE_ZLIB_H
1496231200Smm				iso9660->opt.zisofs = OPT_ZISOFS_DIRECT;
1497231200Smm#else
1498231200Smm				archive_set_error(&a->archive,
1499231200Smm				    ARCHIVE_ERRNO_MISC,
1500231200Smm				    "``zisofs'' "
1501231200Smm				    "is not supported on this platform.");
1502231200Smm				return (ARCHIVE_FATAL);
1503231200Smm#endif
1504231200Smm			}
1505231200Smm			return (ARCHIVE_OK);
1506231200Smm		}
1507231200Smm		break;
1508231200Smm	}
1509231200Smm
1510232153Smm	/* Note: The "warn" return is just to inform the options
1511232153Smm	 * supervisor that we didn't handle it.  It will generate
1512232153Smm	 * a suitable error if no one used this option. */
1513232153Smm	return (ARCHIVE_WARN);
1514232153Smm
1515231200Smminvalid_value:
1516231200Smm	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1517231200Smm	    "Invalid value for option ``%s''", key);
1518231200Smm	return (ARCHIVE_FAILED);
1519231200Smm}
1520231200Smm
1521231200Smmstatic int
1522231200Smmiso9660_write_header(struct archive_write *a, struct archive_entry *entry)
1523231200Smm{
1524231200Smm	struct iso9660 *iso9660;
1525231200Smm	struct isofile *file;
1526231200Smm	struct isoent *isoent;
1527231200Smm	int r, ret = ARCHIVE_OK;
1528231200Smm
1529231200Smm	iso9660 = a->format_data;
1530231200Smm
1531231200Smm	iso9660->cur_file = NULL;
1532231200Smm	iso9660->bytes_remaining = 0;
1533231200Smm	iso9660->need_multi_extent = 0;
1534231200Smm	if (archive_entry_filetype(entry) == AE_IFLNK
1535231200Smm	    && iso9660->opt.rr == OPT_RR_DISABLED) {
1536231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1537231200Smm		    "Ignore symlink file.");
1538231200Smm		iso9660->cur_file = NULL;
1539231200Smm		return (ARCHIVE_WARN);
1540231200Smm	}
1541231200Smm	if (archive_entry_filetype(entry) == AE_IFREG &&
1542231200Smm	    archive_entry_size(entry) >= MULTI_EXTENT_SIZE) {
1543231200Smm		if (iso9660->opt.iso_level < 3) {
1544231200Smm			archive_set_error(&a->archive,
1545231200Smm			    ARCHIVE_ERRNO_MISC,
1546231200Smm			    "Ignore over %lld bytes file. "
1547231200Smm			    "This file too large.",
1548231200Smm			    MULTI_EXTENT_SIZE);
1549231200Smm				iso9660->cur_file = NULL;
1550231200Smm			return (ARCHIVE_WARN);
1551231200Smm		}
1552231200Smm		iso9660->need_multi_extent = 1;
1553231200Smm	}
1554231200Smm
1555231200Smm	file = isofile_new(a, entry);
1556231200Smm	if (file == NULL) {
1557231200Smm		archive_set_error(&a->archive, ENOMEM,
1558231200Smm		    "Can't allocate data");
1559231200Smm		return (ARCHIVE_FATAL);
1560231200Smm	}
1561231200Smm	r = isofile_gen_utility_names(a, file);
1562231200Smm	if (r < ARCHIVE_WARN) {
1563231200Smm		isofile_free(file);
1564231200Smm		return (r);
1565231200Smm	}
1566231200Smm	else if (r < ret)
1567231200Smm		ret = r;
1568231200Smm
1569231200Smm	/*
1570231200Smm	 * Ignore a path which looks like the top of directory name
1571231200Smm	 * since we have already made the root directory of an ISO image.
1572231200Smm	 */
1573231200Smm	if (archive_strlen(&(file->parentdir)) == 0 &&
1574231200Smm	    archive_strlen(&(file->basename)) == 0) {
1575231200Smm		isofile_free(file);
1576231200Smm		return (r);
1577231200Smm	}
1578231200Smm
1579231200Smm	isofile_add_entry(iso9660, file);
1580231200Smm	isoent = isoent_new(file);
1581231200Smm	if (isoent == NULL) {
1582231200Smm		archive_set_error(&a->archive, ENOMEM,
1583231200Smm		    "Can't allocate data");
1584231200Smm		return (ARCHIVE_FATAL);
1585231200Smm	}
1586231200Smm	if (isoent->file->dircnt > iso9660->dircnt_max)
1587231200Smm		iso9660->dircnt_max = isoent->file->dircnt;
1588231200Smm
1589231200Smm	/* Add the current file into tree */
1590231200Smm	r = isoent_tree(a, &isoent);
1591231200Smm	if (r != ARCHIVE_OK)
1592231200Smm		return (r);
1593231200Smm
1594231200Smm	/* If there is the same file in tree and
1595231200Smm	 * the current file is older than the file in tree.
1596231200Smm	 * So we don't need the current file data anymore. */
1597231200Smm	if (isoent->file != file)
1598231200Smm		return (ARCHIVE_OK);
1599231200Smm
1600231200Smm	/* Non regular files contents are unneeded to be saved to
1601231200Smm	 * temporary files. */
1602231200Smm	if (archive_entry_filetype(file->entry) != AE_IFREG)
1603231200Smm		return (ret);
1604231200Smm
1605231200Smm	/*
1606231200Smm	 * Set the current file to cur_file to read its contents.
1607231200Smm	 */
1608231200Smm	iso9660->cur_file = file;
1609231200Smm
1610231200Smm	if (archive_entry_nlink(file->entry) > 1) {
1611231200Smm		r = isofile_register_hardlink(a, file);
1612231200Smm		if (r != ARCHIVE_OK)
1613231200Smm			return (ARCHIVE_FATAL);
1614231200Smm	}
1615231200Smm
1616231200Smm	/*
1617231200Smm	 * Prepare to save the contents of the file.
1618231200Smm	 */
1619231200Smm	if (iso9660->temp_fd < 0) {
1620231200Smm		iso9660->temp_fd = __archive_mktemp(NULL);
1621231200Smm		if (iso9660->temp_fd < 0) {
1622231200Smm			archive_set_error(&a->archive, errno,
1623231200Smm			    "Couldn't create temporary file");
1624231200Smm			return (ARCHIVE_FATAL);
1625231200Smm		}
1626231200Smm	}
1627231200Smm
1628231200Smm	/* Save an offset of current file in temporary file. */
1629231200Smm	file->content.offset_of_temp = wb_offset(a);
1630231200Smm	file->cur_content = &(file->content);
1631231200Smm	r = zisofs_init(a, file);
1632231200Smm	if (r < ret)
1633231200Smm		ret = r;
1634231200Smm	iso9660->bytes_remaining =  archive_entry_size(file->entry);
1635231200Smm
1636231200Smm	return (ret);
1637231200Smm}
1638231200Smm
1639231200Smmstatic int
1640231200Smmwrite_to_temp(struct archive_write *a, const void *buff, size_t s)
1641231200Smm{
1642231200Smm	struct iso9660 *iso9660 = a->format_data;
1643231200Smm	ssize_t written;
1644231200Smm	const unsigned char *b;
1645231200Smm
1646231200Smm	b = (const unsigned char *)buff;
1647231200Smm	while (s) {
1648231200Smm		written = write(iso9660->temp_fd, b, s);
1649231200Smm		if (written < 0) {
1650231200Smm			archive_set_error(&a->archive, errno,
1651231200Smm			    "Can't write to temporary file");
1652231200Smm			return (ARCHIVE_FATAL);
1653231200Smm		}
1654231200Smm		s -= written;
1655231200Smm		b += written;
1656231200Smm	}
1657231200Smm	return (ARCHIVE_OK);
1658231200Smm}
1659231200Smm
1660231200Smmstatic int
1661231200Smmwb_write_to_temp(struct archive_write *a, const void *buff, size_t s)
1662231200Smm{
1663231200Smm	const char *xp = buff;
1664231200Smm	size_t xs = s;
1665231200Smm
1666231200Smm	/*
1667231200Smm	 * If a written data size is big enough to use system-call
1668231200Smm	 * and there is no waiting data, this calls write_to_temp() in
1669231200Smm	 * order to reduce a extra memory copy.
1670231200Smm	 */
1671231200Smm	if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {
1672231200Smm		struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
1673231200Smm		xs = s % LOGICAL_BLOCK_SIZE;
1674231200Smm		iso9660->wbuff_offset += s - xs;
1675231200Smm		if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)
1676231200Smm			return (ARCHIVE_FATAL);
1677231200Smm		if (xs == 0)
1678231200Smm			return (ARCHIVE_OK);
1679231200Smm		xp += s - xs;
1680231200Smm	}
1681231200Smm
1682231200Smm	while (xs) {
1683231200Smm		size_t size = xs;
1684231200Smm		if (size > wb_remaining(a))
1685231200Smm			size = wb_remaining(a);
1686231200Smm		memcpy(wb_buffptr(a), xp, size);
1687231200Smm		if (wb_consume(a, size) != ARCHIVE_OK)
1688231200Smm			return (ARCHIVE_FATAL);
1689231200Smm		xs -= size;
1690231200Smm		xp += size;
1691231200Smm	}
1692231200Smm	return (ARCHIVE_OK);
1693231200Smm}
1694231200Smm
1695231200Smmstatic int
1696231200Smmwb_write_padding_to_temp(struct archive_write *a, int64_t csize)
1697231200Smm{
1698231200Smm	size_t ns;
1699231200Smm	int ret;
1700231200Smm
1701238856Smm	ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);
1702231200Smm	if (ns != 0)
1703231200Smm		ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);
1704231200Smm	else
1705231200Smm		ret = ARCHIVE_OK;
1706231200Smm	return (ret);
1707231200Smm}
1708231200Smm
1709231200Smmstatic ssize_t
1710231200Smmwrite_iso9660_data(struct archive_write *a, const void *buff, size_t s)
1711231200Smm{
1712231200Smm	struct iso9660 *iso9660 = a->format_data;
1713231200Smm	size_t ws;
1714231200Smm
1715231200Smm	if (iso9660->temp_fd < 0) {
1716231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1717231200Smm		    "Couldn't create temporary file");
1718231200Smm		return (ARCHIVE_FATAL);
1719231200Smm	}
1720231200Smm
1721231200Smm	ws = s;
1722231200Smm	if (iso9660->need_multi_extent &&
1723231200Smm	    (iso9660->cur_file->cur_content->size + ws) >=
1724231200Smm	      (MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE)) {
1725231200Smm		struct content *con;
1726231200Smm		size_t ts;
1727231200Smm
1728238856Smm		ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
1729238856Smm		    iso9660->cur_file->cur_content->size);
1730231200Smm
1731231200Smm		if (iso9660->zisofs.detect_magic)
1732231200Smm			zisofs_detect_magic(a, buff, ts);
1733231200Smm
1734231200Smm		if (iso9660->zisofs.making) {
1735231200Smm			if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK)
1736231200Smm				return (ARCHIVE_FATAL);
1737231200Smm		} else {
1738231200Smm			if (wb_write_to_temp(a, buff, ts) != ARCHIVE_OK)
1739231200Smm				return (ARCHIVE_FATAL);
1740231200Smm			iso9660->cur_file->cur_content->size += ts;
1741231200Smm		}
1742231200Smm
1743231200Smm		/* Write padding. */
1744231200Smm		if (wb_write_padding_to_temp(a,
1745231200Smm		    iso9660->cur_file->cur_content->size) != ARCHIVE_OK)
1746231200Smm			return (ARCHIVE_FATAL);
1747231200Smm
1748231200Smm		/* Compute the logical block number. */
1749238856Smm		iso9660->cur_file->cur_content->blocks = (int)
1750238856Smm		    ((iso9660->cur_file->cur_content->size
1751238856Smm		     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
1752231200Smm
1753231200Smm		/*
1754231200Smm		 * Make next extent.
1755231200Smm		 */
1756231200Smm		ws -= ts;
1757231200Smm		buff = (const void *)(((const unsigned char *)buff) + ts);
1758231200Smm		/* Make a content for next extent. */
1759231200Smm		con = calloc(1, sizeof(*con));
1760231200Smm		if (con == NULL) {
1761231200Smm			archive_set_error(&a->archive, ENOMEM,
1762231200Smm			    "Can't allocate content data");
1763231200Smm			return (ARCHIVE_FATAL);
1764231200Smm		}
1765231200Smm		con->offset_of_temp = wb_offset(a);
1766231200Smm		iso9660->cur_file->cur_content->next = con;
1767231200Smm		iso9660->cur_file->cur_content = con;
1768231200Smm#ifdef HAVE_ZLIB_H
1769231200Smm		iso9660->zisofs.block_offset = 0;
1770231200Smm#endif
1771231200Smm	}
1772231200Smm
1773231200Smm	if (iso9660->zisofs.detect_magic)
1774231200Smm		zisofs_detect_magic(a, buff, ws);
1775231200Smm
1776231200Smm	if (iso9660->zisofs.making) {
1777231200Smm		if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK)
1778231200Smm			return (ARCHIVE_FATAL);
1779231200Smm	} else {
1780231200Smm		if (wb_write_to_temp(a, buff, ws) != ARCHIVE_OK)
1781231200Smm			return (ARCHIVE_FATAL);
1782231200Smm		iso9660->cur_file->cur_content->size += ws;
1783231200Smm	}
1784231200Smm
1785231200Smm	return (s);
1786231200Smm}
1787231200Smm
1788231200Smmstatic ssize_t
1789231200Smmiso9660_write_data(struct archive_write *a, const void *buff, size_t s)
1790231200Smm{
1791231200Smm	struct iso9660 *iso9660 = a->format_data;
1792231200Smm	ssize_t r;
1793231200Smm
1794231200Smm	if (iso9660->cur_file == NULL)
1795231200Smm		return (0);
1796231200Smm	if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
1797231200Smm		return (0);
1798231200Smm	if (s > iso9660->bytes_remaining)
1799238856Smm		s = (size_t)iso9660->bytes_remaining;
1800231200Smm	if (s == 0)
1801231200Smm		return (0);
1802231200Smm
1803231200Smm	r = write_iso9660_data(a, buff, s);
1804231200Smm	if (r > 0)
1805231200Smm		iso9660->bytes_remaining -= r;
1806231200Smm	return (r);
1807231200Smm}
1808231200Smm
1809231200Smmstatic int
1810231200Smmiso9660_finish_entry(struct archive_write *a)
1811231200Smm{
1812231200Smm	struct iso9660 *iso9660 = a->format_data;
1813231200Smm
1814231200Smm	if (iso9660->cur_file == NULL)
1815231200Smm		return (ARCHIVE_OK);
1816231200Smm	if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
1817231200Smm		return (ARCHIVE_OK);
1818231200Smm	if (iso9660->cur_file->content.size == 0)
1819231200Smm		return (ARCHIVE_OK);
1820231200Smm
1821231200Smm	/* If there are unwritten data, write null data instead. */
1822231200Smm	while (iso9660->bytes_remaining > 0) {
1823231200Smm		size_t s;
1824231200Smm
1825231200Smm		s = (iso9660->bytes_remaining > a->null_length)?
1826231200Smm		    a->null_length: (size_t)iso9660->bytes_remaining;
1827231200Smm		if (write_iso9660_data(a, a->nulls, s) < 0)
1828231200Smm			return (ARCHIVE_FATAL);
1829231200Smm		iso9660->bytes_remaining -= s;
1830231200Smm	}
1831231200Smm
1832231200Smm	if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK)
1833231200Smm		return (ARCHIVE_FATAL);
1834231200Smm
1835231200Smm	/* Write padding. */
1836231200Smm	if (wb_write_padding_to_temp(a, iso9660->cur_file->cur_content->size)
1837231200Smm	    != ARCHIVE_OK)
1838231200Smm		return (ARCHIVE_FATAL);
1839231200Smm
1840231200Smm	/* Compute the logical block number. */
1841238856Smm	iso9660->cur_file->cur_content->blocks = (int)
1842238856Smm	    ((iso9660->cur_file->cur_content->size
1843238856Smm	     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
1844231200Smm
1845231200Smm	/* Add the current file to data file list. */
1846231200Smm	isofile_add_data_file(iso9660, iso9660->cur_file);
1847231200Smm
1848231200Smm	return (ARCHIVE_OK);
1849231200Smm}
1850231200Smm
1851231200Smmstatic int
1852231200Smmiso9660_close(struct archive_write *a)
1853231200Smm{
1854231200Smm	struct iso9660 *iso9660;
1855231200Smm	int ret, blocks;
1856231200Smm
1857231200Smm	iso9660 = a->format_data;
1858231200Smm
1859231200Smm	/*
1860231200Smm	 * Write remaining data out to the temporary file.
1861231200Smm	 */
1862231200Smm	if (wb_remaining(a) > 0) {
1863231200Smm		ret = wb_write_out(a);
1864231200Smm		if (ret < 0)
1865231200Smm			return (ret);
1866231200Smm	}
1867231200Smm
1868231200Smm	/*
1869231200Smm	 * Preparations...
1870231200Smm	 */
1871231200Smm#ifdef DEBUG
1872231200Smm	if (iso9660->birth_time == 0)
1873231200Smm#endif
1874231200Smm		time(&(iso9660->birth_time));
1875231200Smm
1876231200Smm	/*
1877231200Smm	 * Prepare a bootable ISO image.
1878231200Smm	 */
1879231200Smm	if (iso9660->opt.boot) {
1880231200Smm		/* Find out the boot file entry. */
1881231200Smm		ret = isoent_find_out_boot_file(a, iso9660->primary.rootent);
1882231200Smm		if (ret < 0)
1883231200Smm			return (ret);
1884231200Smm		/* Reconvert the boot file from zisofs'ed form to
1885231200Smm		 * plain form. */
1886231200Smm		ret = zisofs_rewind_boot_file(a);
1887231200Smm		if (ret < 0)
1888231200Smm			return (ret);
1889231200Smm		/* Write remaining data out to the temporary file. */
1890231200Smm		if (wb_remaining(a) > 0) {
1891231200Smm			ret = wb_write_out(a);
1892231200Smm			if (ret < 0)
1893231200Smm				return (ret);
1894231200Smm		}
1895231200Smm		/* Create the boot catalog. */
1896231200Smm		ret = isoent_create_boot_catalog(a, iso9660->primary.rootent);
1897231200Smm		if (ret < 0)
1898231200Smm			return (ret);
1899231200Smm	}
1900231200Smm
1901231200Smm	/*
1902231200Smm	 * Prepare joliet extensions.
1903231200Smm	 */
1904231200Smm	if (iso9660->opt.joliet) {
1905231200Smm		/* Make a new tree for joliet. */
1906231200Smm		ret = isoent_clone_tree(a, &(iso9660->joliet.rootent),
1907231200Smm		    iso9660->primary.rootent);
1908231200Smm		if (ret < 0)
1909231200Smm			return (ret);
1910313571Smm		/* Make sure we have UTF-16BE converters.
1911313571Smm		 * if there is no file entry, converters are still
1912313571Smm		 * uninitialized. */
1913231200Smm		if (iso9660->sconv_to_utf16be == NULL) {
1914231200Smm			iso9660->sconv_to_utf16be =
1915231200Smm			    archive_string_conversion_to_charset(
1916231200Smm				&(a->archive), "UTF-16BE", 1);
1917231200Smm			if (iso9660->sconv_to_utf16be == NULL)
1918231200Smm				/* Couldn't allocate memory */
1919231200Smm				return (ARCHIVE_FATAL);
1920231200Smm			iso9660->sconv_from_utf16be =
1921231200Smm			    archive_string_conversion_from_charset(
1922231200Smm				&(a->archive), "UTF-16BE", 1);
1923231200Smm			if (iso9660->sconv_from_utf16be == NULL)
1924231200Smm				/* Couldn't allocate memory */
1925231200Smm				return (ARCHIVE_FATAL);
1926231200Smm		}
1927231200Smm	}
1928231200Smm
1929231200Smm	/*
1930231200Smm	 * Make Path Tables.
1931231200Smm	 */
1932231200Smm	ret = isoent_make_path_table(a);
1933231200Smm	if (ret < 0)
1934231200Smm		return (ret);
1935231200Smm
1936231200Smm	/*
1937231200Smm	 * Calculate a total volume size and setup all locations of
1938231200Smm	 * contents of an iso9660 image.
1939231200Smm	 */
1940231200Smm	blocks = SYSTEM_AREA_BLOCK
1941231200Smm		+ PRIMARY_VOLUME_DESCRIPTOR_BLOCK
1942231200Smm		+ VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK
1943231200Smm		+ NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
1944231200Smm	if (iso9660->opt.boot)
1945231200Smm		blocks += BOOT_RECORD_DESCRIPTOR_BLOCK;
1946231200Smm	if (iso9660->opt.joliet)
1947231200Smm		blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
1948231200Smm	if (iso9660->opt.iso_level == 4)
1949231200Smm		blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
1950231200Smm
1951231200Smm	/* Setup the locations of Path Table. */
1952231200Smm	iso9660->primary.location_type_L_path_table = blocks;
1953231200Smm	blocks += iso9660->primary.path_table_block;
1954231200Smm	iso9660->primary.location_type_M_path_table = blocks;
1955231200Smm	blocks += iso9660->primary.path_table_block;
1956231200Smm	if (iso9660->opt.joliet) {
1957231200Smm		iso9660->joliet.location_type_L_path_table = blocks;
1958231200Smm		blocks += iso9660->joliet.path_table_block;
1959231200Smm		iso9660->joliet.location_type_M_path_table = blocks;
1960231200Smm		blocks += iso9660->joliet.path_table_block;
1961231200Smm	}
1962231200Smm
1963231200Smm	/* Setup the locations of directories. */
1964231200Smm	isoent_setup_directory_location(iso9660, blocks,
1965231200Smm	    &(iso9660->primary));
1966231200Smm	blocks += iso9660->primary.total_dir_block;
1967231200Smm	if (iso9660->opt.joliet) {
1968231200Smm		isoent_setup_directory_location(iso9660, blocks,
1969231200Smm		    &(iso9660->joliet));
1970231200Smm		blocks += iso9660->joliet.total_dir_block;
1971231200Smm	}
1972231200Smm
1973231200Smm	if (iso9660->opt.rr) {
1974231200Smm		iso9660->location_rrip_er = blocks;
1975231200Smm		blocks += RRIP_ER_BLOCK;
1976231200Smm	}
1977231200Smm
1978231200Smm	/* Setup the locations of all file contents. */
1979231200Smm 	isoent_setup_file_location(iso9660, blocks);
1980231200Smm	blocks += iso9660->total_file_block;
1981231200Smm	if (iso9660->opt.boot && iso9660->opt.boot_info_table) {
1982231200Smm		ret = setup_boot_information(a);
1983231200Smm		if (ret < 0)
1984231200Smm			return (ret);
1985231200Smm	}
1986231200Smm
1987231200Smm	/* Now we have a total volume size. */
1988231200Smm	iso9660->volume_space_size = blocks;
1989231200Smm	if (iso9660->opt.pad)
1990231200Smm		iso9660->volume_space_size += PADDING_BLOCK;
1991231200Smm	iso9660->volume_sequence_number = 1;
1992231200Smm
1993231200Smm
1994231200Smm	/*
1995231200Smm	 * Write an ISO 9660 image.
1996231200Smm	 */
1997231200Smm
1998311042Smm	/* Switch to start using wbuff as file buffer. */
1999231200Smm	iso9660->wbuff_remaining = wb_buffmax();
2000231200Smm	iso9660->wbuff_type = WB_TO_STREAM;
2001231200Smm	iso9660->wbuff_offset = 0;
2002231200Smm	iso9660->wbuff_written = 0;
2003231200Smm	iso9660->wbuff_tail = 0;
2004231200Smm
2005231200Smm	/* Write The System Area */
2006231200Smm	ret = write_null(a, SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE);
2007231200Smm	if (ret != ARCHIVE_OK)
2008231200Smm		return (ARCHIVE_FATAL);
2009231200Smm
2010231200Smm	/* Write Primary Volume Descriptor */
2011231200Smm	ret = write_VD(a, &(iso9660->primary));
2012231200Smm	if (ret != ARCHIVE_OK)
2013231200Smm		return (ARCHIVE_FATAL);
2014231200Smm
2015231200Smm	if (iso9660->opt.boot) {
2016231200Smm		/* Write Boot Record Volume Descriptor */
2017231200Smm		ret = write_VD_boot_record(a);
2018231200Smm		if (ret != ARCHIVE_OK)
2019231200Smm			return (ARCHIVE_FATAL);
2020231200Smm	}
2021231200Smm
2022231200Smm	if (iso9660->opt.iso_level == 4) {
2023231200Smm		/* Write Enhanced Volume Descriptor */
2024231200Smm		iso9660->primary.vdd_type = VDD_ENHANCED;
2025231200Smm		ret = write_VD(a, &(iso9660->primary));
2026231200Smm		iso9660->primary.vdd_type = VDD_PRIMARY;
2027231200Smm		if (ret != ARCHIVE_OK)
2028231200Smm			return (ARCHIVE_FATAL);
2029231200Smm	}
2030231200Smm
2031231200Smm	if (iso9660->opt.joliet) {
2032231200Smm		ret = write_VD(a, &(iso9660->joliet));
2033231200Smm		if (ret != ARCHIVE_OK)
2034231200Smm			return (ARCHIVE_FATAL);
2035231200Smm	}
2036231200Smm
2037231200Smm	/* Write Volume Descriptor Set Terminator */
2038231200Smm	ret = write_VD_terminator(a);
2039231200Smm	if (ret != ARCHIVE_OK)
2040231200Smm		return (ARCHIVE_FATAL);
2041231200Smm
2042231200Smm	/* Write Non-ISO File System Information */
2043231200Smm	ret = write_information_block(a);
2044231200Smm	if (ret != ARCHIVE_OK)
2045231200Smm		return (ARCHIVE_FATAL);
2046231200Smm
2047231200Smm	/* Write Type L Path Table */
2048231200Smm	ret = write_path_table(a, 0, &(iso9660->primary));
2049231200Smm	if (ret != ARCHIVE_OK)
2050231200Smm		return (ARCHIVE_FATAL);
2051231200Smm
2052231200Smm	/* Write Type M Path Table */
2053231200Smm	ret = write_path_table(a, 1, &(iso9660->primary));
2054231200Smm	if (ret != ARCHIVE_OK)
2055231200Smm		return (ARCHIVE_FATAL);
2056231200Smm
2057231200Smm	if (iso9660->opt.joliet) {
2058231200Smm		/* Write Type L Path Table */
2059231200Smm		ret = write_path_table(a, 0, &(iso9660->joliet));
2060231200Smm		if (ret != ARCHIVE_OK)
2061231200Smm			return (ARCHIVE_FATAL);
2062231200Smm
2063231200Smm		/* Write Type M Path Table */
2064231200Smm		ret = write_path_table(a, 1, &(iso9660->joliet));
2065231200Smm		if (ret != ARCHIVE_OK)
2066231200Smm			return (ARCHIVE_FATAL);
2067231200Smm	}
2068231200Smm
2069231200Smm	/* Write Directory Descriptors */
2070231200Smm	ret = write_directory_descriptors(a, &(iso9660->primary));
2071231200Smm	if (ret != ARCHIVE_OK)
2072231200Smm		return (ARCHIVE_FATAL);
2073231200Smm
2074231200Smm	if (iso9660->opt.joliet) {
2075231200Smm		ret = write_directory_descriptors(a, &(iso9660->joliet));
2076231200Smm		if (ret != ARCHIVE_OK)
2077231200Smm			return (ARCHIVE_FATAL);
2078231200Smm	}
2079231200Smm
2080231200Smm	if (iso9660->opt.rr) {
2081231200Smm		/* Write Rockridge ER(Extensions Reference) */
2082231200Smm		ret = write_rr_ER(a);
2083231200Smm		if (ret != ARCHIVE_OK)
2084231200Smm			return (ARCHIVE_FATAL);
2085231200Smm	}
2086231200Smm
2087231200Smm	/* Write File Descriptors */
2088231200Smm	ret = write_file_descriptors(a);
2089231200Smm	if (ret != ARCHIVE_OK)
2090231200Smm		return (ARCHIVE_FATAL);
2091231200Smm
2092231200Smm	/* Write Padding  */
2093231200Smm	if (iso9660->opt.pad) {
2094231200Smm		ret = write_null(a, PADDING_BLOCK * LOGICAL_BLOCK_SIZE);
2095231200Smm		if (ret != ARCHIVE_OK)
2096231200Smm			return (ARCHIVE_FATAL);
2097231200Smm	}
2098231200Smm
2099231200Smm	if (iso9660->directories_too_deep != NULL) {
2100231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2101231200Smm		    "%s: Directories too deep.",
2102231200Smm		    archive_entry_pathname(
2103231200Smm			iso9660->directories_too_deep->file->entry));
2104231200Smm		return (ARCHIVE_WARN);
2105231200Smm	}
2106231200Smm
2107231200Smm	/* Write remaining data out. */
2108231200Smm	ret = wb_write_out(a);
2109231200Smm
2110231200Smm	return (ret);
2111231200Smm}
2112231200Smm
2113231200Smmstatic int
2114231200Smmiso9660_free(struct archive_write *a)
2115231200Smm{
2116231200Smm	struct iso9660 *iso9660;
2117231200Smm	int i, ret;
2118231200Smm
2119231200Smm	iso9660 = a->format_data;
2120231200Smm
2121231200Smm	/* Close the temporary file. */
2122231200Smm	if (iso9660->temp_fd >= 0)
2123231200Smm		close(iso9660->temp_fd);
2124231200Smm
2125231200Smm	/* Free some stuff for zisofs operations. */
2126231200Smm	ret = zisofs_free(a);
2127231200Smm
2128231200Smm	/* Remove directory entries in tree which includes file entries. */
2129231200Smm	isoent_free_all(iso9660->primary.rootent);
2130231200Smm	for (i = 0; i < iso9660->primary.max_depth; i++)
2131231200Smm		free(iso9660->primary.pathtbl[i].sorted);
2132231200Smm	free(iso9660->primary.pathtbl);
2133231200Smm
2134231200Smm	if (iso9660->opt.joliet) {
2135231200Smm		isoent_free_all(iso9660->joliet.rootent);
2136231200Smm		for (i = 0; i < iso9660->joliet.max_depth; i++)
2137231200Smm			free(iso9660->joliet.pathtbl[i].sorted);
2138231200Smm		free(iso9660->joliet.pathtbl);
2139231200Smm	}
2140231200Smm
2141231200Smm	/* Remove isofile entries. */
2142231200Smm	isofile_free_all_entries(iso9660);
2143231200Smm	isofile_free_hardlinks(iso9660);
2144231200Smm
2145231200Smm	archive_string_free(&(iso9660->cur_dirstr));
2146231200Smm	archive_string_free(&(iso9660->volume_identifier));
2147231200Smm	archive_string_free(&(iso9660->publisher_identifier));
2148231200Smm	archive_string_free(&(iso9660->data_preparer_identifier));
2149231200Smm	archive_string_free(&(iso9660->application_identifier));
2150231200Smm	archive_string_free(&(iso9660->copyright_file_identifier));
2151231200Smm	archive_string_free(&(iso9660->abstract_file_identifier));
2152231200Smm	archive_string_free(&(iso9660->bibliographic_file_identifier));
2153231200Smm	archive_string_free(&(iso9660->el_torito.catalog_filename));
2154231200Smm	archive_string_free(&(iso9660->el_torito.boot_filename));
2155231200Smm	archive_string_free(&(iso9660->el_torito.id));
2156231200Smm	archive_string_free(&(iso9660->utf16be));
2157231200Smm	archive_string_free(&(iso9660->mbs));
2158231200Smm
2159231200Smm	free(iso9660);
2160231200Smm	a->format_data = NULL;
2161231200Smm
2162231200Smm	return (ret);
2163231200Smm}
2164231200Smm
2165231200Smm/*
2166231200Smm * Get the System Identifier
2167231200Smm */
2168231200Smmstatic void
2169231200Smmget_system_identitier(char *system_id, size_t size)
2170231200Smm{
2171231200Smm#if defined(HAVE_SYS_UTSNAME_H)
2172231200Smm	struct utsname u;
2173231200Smm
2174231200Smm	uname(&u);
2175231200Smm	strncpy(system_id, u.sysname, size-1);
2176231200Smm	system_id[size-1] = '\0';
2177231200Smm#elif defined(_WIN32) && !defined(__CYGWIN__)
2178231200Smm	strncpy(system_id, "Windows", size-1);
2179231200Smm	system_id[size-1] = '\0';
2180231200Smm#else
2181368708Smm	strncpy(system_id, "Unknown", size-1);
2182368708Smm	system_id[size-1] = '\0';
2183231200Smm#endif
2184231200Smm}
2185231200Smm
2186231200Smmstatic void
2187231200Smmset_str(unsigned char *p, const char *s, size_t l, char f, const char *map)
2188231200Smm{
2189231200Smm	unsigned char c;
2190231200Smm
2191231200Smm	if (s == NULL)
2192231200Smm		s = "";
2193231200Smm	while ((c = *s++) != 0 && l > 0) {
2194231200Smm		if (c >= 0x80 || map[c] == 0)
2195231200Smm		 {
2196231200Smm			/* illegal character */
2197231200Smm			if (c >= 'a' && c <= 'z') {
2198231200Smm				/* convert c from a-z to A-Z */
2199231200Smm				c -= 0x20;
2200231200Smm			} else
2201231200Smm				c = 0x5f;
2202231200Smm		}
2203231200Smm		*p++ = c;
2204231200Smm		l--;
2205231200Smm	}
2206231200Smm	/* If l isn't zero, fill p buffer by the character
2207231200Smm	 * which indicated by f. */
2208231200Smm	if (l > 0)
2209231200Smm		memset(p , f, l);
2210231200Smm}
2211231200Smm
2212231200Smmstatic inline int
2213231200Smmjoliet_allowed_char(unsigned char high, unsigned char low)
2214231200Smm{
2215231200Smm	int utf16 = (high << 8) | low;
2216231200Smm
2217231200Smm	if (utf16 <= 0x001F)
2218231200Smm		return (0);
2219231200Smm
2220231200Smm	switch (utf16) {
2221231200Smm	case 0x002A: /* '*' */
2222231200Smm	case 0x002F: /* '/' */
2223231200Smm	case 0x003A: /* ':' */
2224231200Smm	case 0x003B: /* ';' */
2225231200Smm	case 0x003F: /* '?' */
2226231200Smm	case 0x005C: /* '\' */
2227231200Smm		return (0);/* Not allowed. */
2228231200Smm	}
2229231200Smm	return (1);
2230231200Smm}
2231231200Smm
2232231200Smmstatic int
2233231200Smmset_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,
2234231200Smm    size_t l, uint16_t uf, enum vdc vdc)
2235231200Smm{
2236231200Smm	size_t size, i;
2237231200Smm	int onepad;
2238231200Smm
2239231200Smm	if (s == NULL)
2240231200Smm		s = "";
2241231200Smm	if (l & 0x01) {
2242231200Smm		onepad = 1;
2243231200Smm		l &= ~1;
2244231200Smm	} else
2245231200Smm		onepad = 0;
2246231200Smm	if (vdc == VDC_UCS2) {
2247231200Smm		struct iso9660 *iso9660 = a->format_data;
2248238856Smm		if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),
2249231200Smm		    iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {
2250231200Smm			archive_set_error(&a->archive, ENOMEM,
2251231200Smm			    "Can't allocate memory for UTF-16BE");
2252231200Smm			return (ARCHIVE_FATAL);
2253231200Smm		}
2254231200Smm		size = iso9660->utf16be.length;
2255231200Smm		if (size > l)
2256231200Smm			size = l;
2257231200Smm		memcpy(p, iso9660->utf16be.s, size);
2258231200Smm	} else {
2259231200Smm		const uint16_t *u16 = (const uint16_t *)s;
2260231200Smm
2261231200Smm		size = 0;
2262231200Smm		while (*u16++)
2263231200Smm			size += 2;
2264231200Smm		if (size > l)
2265231200Smm			size = l;
2266231200Smm		memcpy(p, s, size);
2267231200Smm	}
2268231200Smm	for (i = 0; i < size; i += 2, p += 2) {
2269231200Smm		if (!joliet_allowed_char(p[0], p[1]))
2270231200Smm			archive_be16enc(p, 0x005F);/* '_' */
2271231200Smm	}
2272231200Smm	l -= size;
2273231200Smm	while (l > 0) {
2274231200Smm		archive_be16enc(p, uf);
2275231200Smm		p += 2;
2276231200Smm		l -= 2;
2277231200Smm	}
2278231200Smm	if (onepad)
2279231200Smm		*p = 0;
2280231200Smm	return (ARCHIVE_OK);
2281231200Smm}
2282231200Smm
2283231200Smmstatic const char a_characters_map[0x80] = {
2284231200Smm/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2285231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2286231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2287231200Smm    1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
2288231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
2289231200Smm    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2290231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2291231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
2292231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
2293231200Smm};
2294231200Smm
2295231200Smmstatic const char a1_characters_map[0x80] = {
2296231200Smm/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2297231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2298231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2299231200Smm    1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
2300231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
2301231200Smm    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2302231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2303231200Smm    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
2304231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
2305231200Smm};
2306231200Smm
2307231200Smmstatic const char d_characters_map[0x80] = {
2308231200Smm/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2309231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2310231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2311231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
2312231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
2313231200Smm    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2314231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2315231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
2316231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
2317231200Smm};
2318231200Smm
2319231200Smmstatic const char d1_characters_map[0x80] = {
2320231200Smm/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2321231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2322231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2323231200Smm    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
2324231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
2325231200Smm    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2326231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2327231200Smm    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
2328231200Smm    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
2329231200Smm};
2330231200Smm
2331231200Smmstatic int
2332231200Smmset_str_a_characters_bp(struct archive_write *a, unsigned char *bp,
2333231200Smm    int from, int to, const char *s, enum vdc vdc)
2334231200Smm{
2335231200Smm	int r;
2336231200Smm
2337231200Smm	switch (vdc) {
2338231200Smm	case VDC_STD:
2339231200Smm		set_str(bp+from, s, to - from + 1, 0x20,
2340231200Smm		    a_characters_map);
2341231200Smm		r = ARCHIVE_OK;
2342231200Smm		break;
2343231200Smm	case VDC_LOWERCASE:
2344231200Smm		set_str(bp+from, s, to - from + 1, 0x20,
2345231200Smm		    a1_characters_map);
2346231200Smm		r = ARCHIVE_OK;
2347231200Smm		break;
2348231200Smm	case VDC_UCS2:
2349231200Smm	case VDC_UCS2_DIRECT:
2350231200Smm		r = set_str_utf16be(a, bp+from, s, to - from + 1,
2351231200Smm		    0x0020, vdc);
2352231200Smm		break;
2353231200Smm	default:
2354231200Smm		r = ARCHIVE_FATAL;
2355231200Smm	}
2356231200Smm	return (r);
2357231200Smm}
2358231200Smm
2359231200Smmstatic int
2360231200Smmset_str_d_characters_bp(struct archive_write *a, unsigned char *bp,
2361231200Smm    int from, int to, const char *s, enum  vdc vdc)
2362231200Smm{
2363231200Smm	int r;
2364231200Smm
2365231200Smm	switch (vdc) {
2366231200Smm	case VDC_STD:
2367231200Smm		set_str(bp+from, s, to - from + 1, 0x20,
2368231200Smm		    d_characters_map);
2369231200Smm		r = ARCHIVE_OK;
2370231200Smm		break;
2371231200Smm	case VDC_LOWERCASE:
2372231200Smm		set_str(bp+from, s, to - from + 1, 0x20,
2373231200Smm		    d1_characters_map);
2374231200Smm		r = ARCHIVE_OK;
2375231200Smm		break;
2376231200Smm	case VDC_UCS2:
2377231200Smm	case VDC_UCS2_DIRECT:
2378231200Smm		r = set_str_utf16be(a, bp+from, s, to - from + 1,
2379231200Smm		    0x0020, vdc);
2380231200Smm		break;
2381231200Smm	default:
2382231200Smm		r = ARCHIVE_FATAL;
2383231200Smm	}
2384231200Smm	return (r);
2385231200Smm}
2386231200Smm
2387231200Smmstatic void
2388231200Smmset_VD_bp(unsigned char *bp, enum VD_type type, unsigned char ver)
2389231200Smm{
2390231200Smm
2391231200Smm	/* Volume Descriptor Type */
2392231200Smm	bp[1] = (unsigned char)type;
2393231200Smm	/* Standard Identifier */
2394231200Smm	memcpy(bp + 2, "CD001", 5);
2395231200Smm	/* Volume Descriptor Version */
2396231200Smm	bp[7] = ver;
2397231200Smm}
2398231200Smm
2399231200Smmstatic inline void
2400231200Smmset_unused_field_bp(unsigned char *bp, int from, int to)
2401231200Smm{
2402231200Smm	memset(bp + from, 0, to - from + 1);
2403231200Smm}
2404231200Smm
2405231200Smm/*
2406231200Smm * 8-bit unsigned numerical values.
2407231200Smm * ISO9660 Standard 7.1.1
2408231200Smm */
2409231200Smmstatic inline void
2410231200Smmset_num_711(unsigned char *p, unsigned char value)
2411231200Smm{
2412231200Smm	*p = value;
2413231200Smm}
2414231200Smm
2415231200Smm/*
2416231200Smm * 8-bit signed numerical values.
2417231200Smm * ISO9660 Standard 7.1.2
2418231200Smm */
2419231200Smmstatic inline void
2420231200Smmset_num_712(unsigned char *p, char value)
2421231200Smm{
2422231200Smm	*((char *)p) = value;
2423231200Smm}
2424231200Smm
2425231200Smm/*
2426231200Smm * Least significant byte first.
2427231200Smm * ISO9660 Standard 7.2.1
2428231200Smm */
2429231200Smmstatic inline void
2430231200Smmset_num_721(unsigned char *p, uint16_t value)
2431231200Smm{
2432231200Smm	archive_le16enc(p, value);
2433231200Smm}
2434231200Smm
2435231200Smm/*
2436231200Smm * Most significant byte first.
2437231200Smm * ISO9660 Standard 7.2.2
2438231200Smm */
2439231200Smmstatic inline void
2440231200Smmset_num_722(unsigned char *p, uint16_t value)
2441231200Smm{
2442231200Smm	archive_be16enc(p, value);
2443231200Smm}
2444231200Smm
2445231200Smm/*
2446231200Smm * Both-byte orders.
2447231200Smm * ISO9660 Standard 7.2.3
2448231200Smm */
2449231200Smmstatic void
2450231200Smmset_num_723(unsigned char *p, uint16_t value)
2451231200Smm{
2452231200Smm	archive_le16enc(p, value);
2453231200Smm	archive_be16enc(p+2, value);
2454231200Smm}
2455231200Smm
2456231200Smm/*
2457231200Smm * Least significant byte first.
2458231200Smm * ISO9660 Standard 7.3.1
2459231200Smm */
2460231200Smmstatic inline void
2461231200Smmset_num_731(unsigned char *p, uint32_t value)
2462231200Smm{
2463231200Smm	archive_le32enc(p, value);
2464231200Smm}
2465231200Smm
2466231200Smm/*
2467231200Smm * Most significant byte first.
2468231200Smm * ISO9660 Standard 7.3.2
2469231200Smm */
2470231200Smmstatic inline void
2471231200Smmset_num_732(unsigned char *p, uint32_t value)
2472231200Smm{
2473231200Smm	archive_be32enc(p, value);
2474231200Smm}
2475231200Smm
2476231200Smm/*
2477231200Smm * Both-byte orders.
2478231200Smm * ISO9660 Standard 7.3.3
2479231200Smm */
2480231200Smmstatic inline void
2481231200Smmset_num_733(unsigned char *p, uint32_t value)
2482231200Smm{
2483231200Smm	archive_le32enc(p, value);
2484231200Smm	archive_be32enc(p+4, value);
2485231200Smm}
2486231200Smm
2487231200Smmstatic void
2488231200Smmset_digit(unsigned char *p, size_t s, int value)
2489231200Smm{
2490231200Smm
2491231200Smm	while (s--) {
2492231200Smm		p[s] = '0' + (value % 10);
2493231200Smm		value /= 10;
2494231200Smm	}
2495231200Smm}
2496231200Smm
2497231200Smm#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
2498231200Smm#define get_gmoffset(tm)	((tm)->tm_gmtoff)
2499231200Smm#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
2500231200Smm#define get_gmoffset(tm)	((tm)->__tm_gmtoff)
2501231200Smm#else
2502231200Smmstatic long
2503231200Smmget_gmoffset(struct tm *tm)
2504231200Smm{
2505231200Smm	long offset;
2506231200Smm
2507231200Smm#if defined(HAVE__GET_TIMEZONE)
2508231200Smm	_get_timezone(&offset);
2509231200Smm#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
2510231200Smm	offset = _timezone;
2511231200Smm#else
2512231200Smm	offset = timezone;
2513231200Smm#endif
2514231200Smm	offset *= -1;
2515231200Smm	if (tm->tm_isdst)
2516231200Smm		offset += 3600;
2517231200Smm	return (offset);
2518231200Smm}
2519231200Smm#endif
2520231200Smm
2521231200Smmstatic void
2522231200Smmget_tmfromtime(struct tm *tm, time_t *t)
2523231200Smm{
2524231200Smm#if HAVE_LOCALTIME_R
2525231200Smm	tzset();
2526231200Smm	localtime_r(t, tm);
2527231200Smm#elif HAVE__LOCALTIME64_S
2528313571Smm	__time64_t tmp_t = (__time64_t) *t; //time_t may be shorter than 64 bits
2529313571Smm	_localtime64_s(tm, &tmp_t);
2530231200Smm#else
2531231200Smm	memcpy(tm, localtime(t), sizeof(*tm));
2532231200Smm#endif
2533231200Smm}
2534231200Smm
2535231200Smm/*
2536231200Smm * Date and Time Format.
2537231200Smm * ISO9660 Standard 8.4.26.1
2538231200Smm */
2539231200Smmstatic void
2540231200Smmset_date_time(unsigned char *p, time_t t)
2541231200Smm{
2542231200Smm	struct tm tm;
2543231200Smm
2544231200Smm	get_tmfromtime(&tm, &t);
2545231200Smm	set_digit(p, 4, tm.tm_year + 1900);
2546231200Smm	set_digit(p+4, 2, tm.tm_mon + 1);
2547231200Smm	set_digit(p+6, 2, tm.tm_mday);
2548231200Smm	set_digit(p+8, 2, tm.tm_hour);
2549231200Smm	set_digit(p+10, 2, tm.tm_min);
2550231200Smm	set_digit(p+12, 2, tm.tm_sec);
2551231200Smm	set_digit(p+14, 2, 0);
2552238856Smm	set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
2553231200Smm}
2554231200Smm
2555231200Smmstatic void
2556231200Smmset_date_time_null(unsigned char *p)
2557231200Smm{
2558313571Smm	memset(p, (int)'0', 16);
2559231200Smm	p[16] = 0;
2560231200Smm}
2561231200Smm
2562231200Smmstatic void
2563231200Smmset_time_915(unsigned char *p, time_t t)
2564231200Smm{
2565231200Smm	struct tm tm;
2566231200Smm
2567231200Smm	get_tmfromtime(&tm, &t);
2568231200Smm	set_num_711(p+0, tm.tm_year);
2569231200Smm	set_num_711(p+1, tm.tm_mon+1);
2570231200Smm	set_num_711(p+2, tm.tm_mday);
2571231200Smm	set_num_711(p+3, tm.tm_hour);
2572231200Smm	set_num_711(p+4, tm.tm_min);
2573231200Smm	set_num_711(p+5, tm.tm_sec);
2574238856Smm	set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
2575231200Smm}
2576231200Smm
2577231200Smm
2578231200Smm/*
2579231200Smm * Write SUSP "CE" System Use Entry.
2580231200Smm */
2581231200Smmstatic int
2582231200Smmset_SUSP_CE(unsigned char *p, int location, int offset, int size)
2583231200Smm{
2584231200Smm	unsigned char *bp = p -1;
2585231200Smm	/*  Extend the System Use Area
2586231200Smm	 *   "CE" Format:
2587231200Smm	 *               len  ver
2588231200Smm	 *    +----+----+----+----+-----------+-----------+
2589231200Smm	 *    | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |
2590231200Smm	 *    +----+----+----+----+-----------+-----------+
2591231200Smm	 *    0    1    2    3    4          12          20
2592231200Smm	 *    +-----------+
2593231200Smm	 *    | LOCATION3 |
2594231200Smm	 *    +-----------+
2595231200Smm	 *   20          28
2596231200Smm	 *   LOCATION1 : Location of Continuation of System Use Area.
2597231200Smm	 *   LOCATION2 : Offset to Start of Continuation.
2598231200Smm	 *   LOCATION3 : Length of the Continuation.
2599231200Smm	 */
2600231200Smm
2601231200Smm	bp[1] = 'C';
2602231200Smm	bp[2] = 'E';
2603231200Smm	bp[3] = RR_CE_SIZE;	/* length	*/
2604231200Smm	bp[4] = 1;		/* version	*/
2605231200Smm	set_num_733(bp+5, location);
2606231200Smm	set_num_733(bp+13, offset);
2607231200Smm	set_num_733(bp+21, size);
2608231200Smm	return (RR_CE_SIZE);
2609231200Smm}
2610231200Smm
2611231200Smm/*
2612231200Smm * The functions, which names are beginning with extra_, are used to
2613231200Smm * control extra records.
2614231200Smm * The maximum size of a Directory Record is 254. When a filename is
2615231200Smm * very long, all of RRIP data of a file won't stored to the Directory
2616231200Smm * Record and so remaining RRIP data store to an extra record instead.
2617231200Smm */
2618231200Smmstatic unsigned char *
2619231200Smmextra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,
2620231200Smm    struct ctl_extr_rec *ctl)
2621231200Smm{
2622231200Smm	ctl->bp = bp;
2623231200Smm	if (bp != NULL)
2624231200Smm		bp += dr_len;
2625231200Smm	ctl->use_extr = 0;
2626231200Smm	ctl->isoent = isoent;
2627231200Smm	ctl->ce_ptr = NULL;
2628231200Smm	ctl->cur_len = ctl->dr_len = dr_len;
2629231200Smm	ctl->limit = DR_LIMIT;
2630231200Smm
2631231200Smm	return (bp);
2632231200Smm}
2633231200Smm
2634231200Smmstatic void
2635231200Smmextra_close_record(struct ctl_extr_rec *ctl, int ce_size)
2636231200Smm{
2637231200Smm	int padding = 0;
2638231200Smm
2639231200Smm	if (ce_size > 0)
2640231200Smm		extra_tell_used_size(ctl, ce_size);
2641231200Smm	/* Padding. */
2642231200Smm	if (ctl->cur_len & 0x01) {
2643231200Smm		ctl->cur_len++;
2644231200Smm		if (ctl->bp != NULL)
2645231200Smm			ctl->bp[ctl->cur_len] = 0;
2646231200Smm		padding = 1;
2647231200Smm	}
2648231200Smm	if (ctl->use_extr) {
2649231200Smm		if (ctl->ce_ptr != NULL)
2650231200Smm			set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,
2651231200Smm			    ctl->extr_off, ctl->cur_len - padding);
2652231200Smm	} else
2653231200Smm		ctl->dr_len = ctl->cur_len;
2654231200Smm}
2655231200Smm
2656231200Smm#define extra_space(ctl)	((ctl)->limit - (ctl)->cur_len)
2657231200Smm
2658231200Smmstatic unsigned char *
2659231200Smmextra_next_record(struct ctl_extr_rec *ctl, int length)
2660231200Smm{
2661231200Smm	int cur_len = ctl->cur_len;/* save cur_len */
2662231200Smm
2663231200Smm	/* Close the current extra record or Directory Record. */
2664231200Smm	extra_close_record(ctl, RR_CE_SIZE);
2665231200Smm
2666231200Smm	/* Get a next extra record. */
2667231200Smm	ctl->use_extr = 1;
2668231200Smm	if (ctl->bp != NULL) {
2669231200Smm		/* Storing data into an extra record. */
2670231200Smm		unsigned char *p;
2671231200Smm
2672231200Smm		/* Save the pointer where a CE extension will be
2673231200Smm		 * stored to. */
2674231200Smm		ctl->ce_ptr = &ctl->bp[cur_len+1];
2675231200Smm		p = extra_get_record(ctl->isoent,
2676231200Smm		    &ctl->limit, &ctl->extr_off, &ctl->extr_loc);
2677231200Smm		ctl->bp = p - 1;/* the base of bp offset is 1. */
2678231200Smm	} else
2679231200Smm		/* Calculating the size of an extra record. */
2680231200Smm		(void)extra_get_record(ctl->isoent,
2681231200Smm		    &ctl->limit, NULL, NULL);
2682231200Smm	ctl->cur_len = 0;
2683231200Smm	/* Check if an extra record is almost full.
2684231200Smm	 * If so, get a next one. */
2685231200Smm	if (extra_space(ctl) < length)
2686231200Smm		(void)extra_next_record(ctl, length);
2687231200Smm
2688231200Smm	return (ctl->bp);
2689231200Smm}
2690231200Smm
2691231200Smmstatic inline struct extr_rec *
2692231200Smmextra_last_record(struct isoent *isoent)
2693231200Smm{
2694231200Smm	if (isoent->extr_rec_list.first == NULL)
2695231200Smm		return (NULL);
2696231200Smm	return ((struct extr_rec *)(void *)
2697231200Smm		((char *)(isoent->extr_rec_list.last)
2698231200Smm		    - offsetof(struct extr_rec, next)));
2699231200Smm}
2700231200Smm
2701231200Smmstatic unsigned char *
2702231200Smmextra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
2703231200Smm{
2704231200Smm	struct extr_rec *rec;
2705231200Smm
2706231200Smm	isoent = isoent->parent;
2707231200Smm	if (off != NULL) {
2708231200Smm		/* Storing data into an extra record. */
2709231200Smm		rec = isoent->extr_rec_list.current;
2710231200Smm		if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)
2711231200Smm			rec = rec->next;
2712231200Smm	} else {
2713231200Smm		/* Calculating the size of an extra record. */
2714231200Smm		rec = extra_last_record(isoent);
2715231200Smm		if (rec == NULL ||
2716231200Smm		    DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {
2717231200Smm			rec = malloc(sizeof(*rec));
2718231200Smm			if (rec == NULL)
2719231200Smm				return (NULL);
2720231200Smm			rec->location = 0;
2721231200Smm			rec->offset = 0;
2722231200Smm			/* Insert `rec` into the tail of isoent->extr_rec_list */
2723231200Smm			rec->next = NULL;
2724302001Smm			/*
2725302001Smm			 * Note: testing isoent->extr_rec_list.last == NULL
2726302001Smm			 * here is really unneeded since it has been already
2727302001Smm			 * initialized at isoent_new function but Clang Static
2728302001Smm			 * Analyzer claims that it is dereference of null
2729302001Smm			 * pointer.
2730302001Smm			 */
2731302001Smm			if (isoent->extr_rec_list.last == NULL)
2732302001Smm				isoent->extr_rec_list.last =
2733302001Smm					&(isoent->extr_rec_list.first);
2734231200Smm			*isoent->extr_rec_list.last = rec;
2735231200Smm			isoent->extr_rec_list.last = &(rec->next);
2736231200Smm		}
2737231200Smm	}
2738231200Smm	*space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;
2739231200Smm	if (*space & 0x01)
2740231200Smm		*space -= 1;/* Keep padding space. */
2741231200Smm	if (off != NULL)
2742231200Smm		*off = rec->offset;
2743231200Smm	if (loc != NULL)
2744231200Smm		*loc = rec->location;
2745231200Smm	isoent->extr_rec_list.current = rec;
2746231200Smm
2747231200Smm	return (&rec->buf[rec->offset]);
2748231200Smm}
2749231200Smm
2750231200Smmstatic void
2751231200Smmextra_tell_used_size(struct ctl_extr_rec *ctl, int size)
2752231200Smm{
2753231200Smm	struct isoent *isoent;
2754231200Smm	struct extr_rec *rec;
2755231200Smm
2756231200Smm	if (ctl->use_extr) {
2757231200Smm		isoent = ctl->isoent->parent;
2758231200Smm		rec = isoent->extr_rec_list.current;
2759231200Smm		if (rec != NULL)
2760231200Smm			rec->offset += size;
2761231200Smm	}
2762231200Smm	ctl->cur_len += size;
2763231200Smm}
2764231200Smm
2765231200Smmstatic int
2766231200Smmextra_setup_location(struct isoent *isoent, int location)
2767231200Smm{
2768231200Smm	struct extr_rec *rec;
2769231200Smm	int cnt;
2770231200Smm
2771231200Smm	cnt = 0;
2772231200Smm	rec = isoent->extr_rec_list.first;
2773231200Smm	isoent->extr_rec_list.current = rec;
2774231200Smm	while (rec) {
2775231200Smm		cnt++;
2776231200Smm		rec->location = location++;
2777231200Smm		rec->offset = 0;
2778231200Smm		rec = rec->next;
2779231200Smm	}
2780231200Smm	return (cnt);
2781231200Smm}
2782231200Smm
2783231200Smm/*
2784231200Smm * Create the RRIP entries.
2785231200Smm */
2786231200Smmstatic int
2787231200Smmset_directory_record_rr(unsigned char *bp, int dr_len,
2788231200Smm    struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)
2789231200Smm{
2790231200Smm	/* Flags(BP 5) of the Rockridge "RR" System Use Field */
2791231200Smm	unsigned char rr_flag;
2792231200Smm#define RR_USE_PX	0x01
2793231200Smm#define RR_USE_PN	0x02
2794231200Smm#define RR_USE_SL	0x04
2795231200Smm#define RR_USE_NM	0x08
2796231200Smm#define RR_USE_CL	0x10
2797231200Smm#define RR_USE_PL	0x20
2798231200Smm#define RR_USE_RE	0x40
2799231200Smm#define RR_USE_TF	0x80
2800231200Smm	int length;
2801231200Smm	struct ctl_extr_rec ctl;
2802231200Smm	struct isoent *rr_parent, *pxent;
2803231200Smm	struct isofile *file;
2804231200Smm
2805231200Smm	bp = extra_open_record(bp, dr_len, isoent, &ctl);
2806231200Smm
2807231200Smm	if (t == DIR_REC_PARENT) {
2808231200Smm		rr_parent = isoent->rr_parent;
2809231200Smm		pxent = isoent->parent;
2810231200Smm		if (rr_parent != NULL)
2811231200Smm			isoent = rr_parent;
2812231200Smm		else
2813231200Smm			isoent = isoent->parent;
2814231200Smm	} else {
2815231200Smm		rr_parent = NULL;
2816231200Smm		pxent = isoent;
2817231200Smm	}
2818231200Smm	file = isoent->file;
2819231200Smm
2820231200Smm	if (t != DIR_REC_NORMAL) {
2821231200Smm		rr_flag = RR_USE_PX | RR_USE_TF;
2822231200Smm		if (rr_parent != NULL)
2823231200Smm			rr_flag |= RR_USE_PL;
2824231200Smm	} else {
2825231200Smm		rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;
2826231200Smm		if (archive_entry_filetype(file->entry) == AE_IFLNK)
2827231200Smm			rr_flag |= RR_USE_SL;
2828231200Smm		if (isoent->rr_parent != NULL)
2829231200Smm			rr_flag |= RR_USE_RE;
2830231200Smm		if (isoent->rr_child != NULL)
2831231200Smm			rr_flag |= RR_USE_CL;
2832231200Smm		if (archive_entry_filetype(file->entry) == AE_IFCHR ||
2833231200Smm		    archive_entry_filetype(file->entry) == AE_IFBLK)
2834231200Smm			rr_flag |= RR_USE_PN;
2835231200Smm#ifdef COMPAT_MKISOFS
2836231200Smm		/*
2837231200Smm		 * mkisofs 2.01.01a63 records "RE" extension to
2838231200Smm		 * the entry of "rr_moved" directory.
2839231200Smm		 * I don't understand this behavior.
2840231200Smm		 */
2841231200Smm		if (isoent->virtual &&
2842231200Smm		    isoent->parent == iso9660->primary.rootent &&
2843231200Smm		    strcmp(isoent->file->basename.s, "rr_moved") == 0)
2844231200Smm			rr_flag |= RR_USE_RE;
2845231200Smm#endif
2846231200Smm	}
2847231200Smm
2848231200Smm	/* Write "SP" System Use Entry. */
2849231200Smm	if (t == DIR_REC_SELF && isoent == isoent->parent) {
2850231200Smm		length = 7;
2851231200Smm		if (bp != NULL) {
2852231200Smm			bp[1] = 'S';
2853231200Smm			bp[2] = 'P';
2854231200Smm			bp[3] = length;
2855231200Smm			bp[4] = 1;	/* version	*/
2856231200Smm			bp[5] = 0xBE;  /* Check Byte	*/
2857231200Smm			bp[6] = 0xEF;  /* Check Byte	*/
2858231200Smm			bp[7] = 0;
2859231200Smm			bp += length;
2860231200Smm		}
2861231200Smm		extra_tell_used_size(&ctl, length);
2862231200Smm	}
2863231200Smm
2864231200Smm	/* Write "RR" System Use Entry. */
2865231200Smm	length = 5;
2866231200Smm	if (extra_space(&ctl) < length)
2867231200Smm		bp = extra_next_record(&ctl, length);
2868231200Smm	if (bp != NULL) {
2869231200Smm		bp[1] = 'R';
2870231200Smm		bp[2] = 'R';
2871231200Smm		bp[3] = length;
2872231200Smm		bp[4] = 1;	/* version */
2873231200Smm		bp[5] = rr_flag;
2874231200Smm		bp += length;
2875231200Smm	}
2876231200Smm	extra_tell_used_size(&ctl, length);
2877231200Smm
2878231200Smm	/* Write "NM" System Use Entry. */
2879231200Smm	if (rr_flag & RR_USE_NM) {
2880231200Smm		/*
2881231200Smm		 *   "NM" Format:
2882231200Smm		 *     e.g. a basename is 'foo'
2883231200Smm		 *               len  ver  flg
2884231200Smm		 *    +----+----+----+----+----+----+----+----+
2885231200Smm		 *    | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|
2886231200Smm		 *    +----+----+----+----+----+----+----+----+
2887231200Smm		 *    <----------------- len ----------------->
2888231200Smm		 */
2889231200Smm		size_t nmlen = file->basename.length;
2890231200Smm		const char *nm = file->basename.s;
2891231200Smm		size_t nmmax;
2892231200Smm
2893231200Smm		if (extra_space(&ctl) < 6)
2894231200Smm			bp = extra_next_record(&ctl, 6);
2895231200Smm		if (bp != NULL) {
2896231200Smm			bp[1] = 'N';
2897231200Smm			bp[2] = 'M';
2898231200Smm			bp[4] = 1;	    /* version	*/
2899231200Smm		}
2900231200Smm		nmmax = extra_space(&ctl);
2901231200Smm		if (nmmax > 0xff)
2902231200Smm			nmmax = 0xff;
2903231200Smm		while (nmlen + 5 > nmmax) {
2904248616Smm			length = (int)nmmax;
2905231200Smm			if (bp != NULL) {
2906231200Smm				bp[3] = length;
2907231200Smm				bp[5] = 0x01;/* Alternate Name continues
2908231200Smm					       * in next "NM" field */
2909231200Smm				memcpy(bp+6, nm, length - 5);
2910231200Smm				bp += length;
2911231200Smm			}
2912231200Smm			nmlen -= length - 5;
2913231200Smm			nm += length - 5;
2914231200Smm			extra_tell_used_size(&ctl, length);
2915231200Smm			if (extra_space(&ctl) < 6) {
2916231200Smm				bp = extra_next_record(&ctl, 6);
2917231200Smm				nmmax = extra_space(&ctl);
2918231200Smm				if (nmmax > 0xff)
2919231200Smm					nmmax = 0xff;
2920231200Smm			}
2921231200Smm			if (bp != NULL) {
2922231200Smm				bp[1] = 'N';
2923231200Smm				bp[2] = 'M';
2924231200Smm				bp[4] = 1;    /* version */
2925231200Smm			}
2926231200Smm		}
2927248616Smm		length = 5 + (int)nmlen;
2928231200Smm		if (bp != NULL) {
2929231200Smm			bp[3] = length;
2930231200Smm			bp[5] = 0;
2931231200Smm			memcpy(bp+6, nm, nmlen);
2932231200Smm			bp += length;
2933231200Smm		}
2934231200Smm		extra_tell_used_size(&ctl, length);
2935231200Smm	}
2936231200Smm
2937231200Smm	/* Write "PX" System Use Entry. */
2938231200Smm	if (rr_flag & RR_USE_PX) {
2939231200Smm		/*
2940231200Smm		 *   "PX" Format:
2941231200Smm		 *               len  ver
2942231200Smm		 *    +----+----+----+----+-----------+-----------+
2943231200Smm		 *    | 'P'| 'X'| 2C | 01 | FILE MODE |   LINKS   |
2944231200Smm		 *    +----+----+----+----+-----------+-----------+
2945231200Smm		 *    0    1    2    3    4          12          20
2946231200Smm		 *    +-----------+-----------+------------------+
2947231200Smm		 *    |  USER ID  | GROUP ID  |FILE SERIAL NUMBER|
2948231200Smm		 *    +-----------+-----------+------------------+
2949231200Smm		 *   20          28          36                 44
2950231200Smm		 */
2951231200Smm		length = 44;
2952231200Smm		if (extra_space(&ctl) < length)
2953231200Smm			bp = extra_next_record(&ctl, length);
2954231200Smm		if (bp != NULL) {
2955231200Smm			mode_t mode;
2956238856Smm			int64_t uid;
2957238856Smm			int64_t gid;
2958231200Smm
2959231200Smm			mode = archive_entry_mode(file->entry);
2960231200Smm			uid = archive_entry_uid(file->entry);
2961231200Smm			gid = archive_entry_gid(file->entry);
2962231200Smm			if (iso9660->opt.rr == OPT_RR_USEFUL) {
2963231200Smm				/*
2964313571Smm				 * This action is similar to mkisofs -r option
2965231200Smm				 * but our rockridge=useful option does not
2966231200Smm				 * set a zero to uid and gid.
2967231200Smm				 */
2968231200Smm				/* set all read bit ON */
2969231200Smm				mode |= 0444;
2970231200Smm#if !defined(_WIN32) && !defined(__CYGWIN__)
2971231200Smm				if (mode & 0111)
2972231200Smm#endif
2973231200Smm					/* set all exec bit ON */
2974231200Smm					mode |= 0111;
2975231200Smm				/* clear all write bits. */
2976231200Smm				mode &= ~0222;
2977231200Smm				/* clear setuid,setgid,sticky bits. */
2978231200Smm				mode &= ~07000;
2979231200Smm			}
2980231200Smm
2981231200Smm			bp[1] = 'P';
2982231200Smm			bp[2] = 'X';
2983231200Smm			bp[3] = length;
2984231200Smm			bp[4] = 1;	/* version	*/
2985231200Smm			/* file mode */
2986231200Smm			set_num_733(bp+5, mode);
2987231200Smm			/* file links (stat.st_nlink) */
2988231200Smm			set_num_733(bp+13,
2989231200Smm			    archive_entry_nlink(file->entry));
2990238856Smm			set_num_733(bp+21, (uint32_t)uid);
2991238856Smm			set_num_733(bp+29, (uint32_t)gid);
2992231200Smm			/* File Serial Number */
2993231200Smm			if (pxent->dir)
2994231200Smm				set_num_733(bp+37, pxent->dir_location);
2995231200Smm			else if (file->hardlink_target != NULL)
2996231200Smm				set_num_733(bp+37,
2997231200Smm				    file->hardlink_target->cur_content->location);
2998231200Smm			else
2999231200Smm				set_num_733(bp+37,
3000231200Smm				    file->cur_content->location);
3001231200Smm			bp += length;
3002231200Smm		}
3003231200Smm		extra_tell_used_size(&ctl, length);
3004231200Smm	}
3005231200Smm
3006231200Smm	/* Write "SL" System Use Entry. */
3007231200Smm	if (rr_flag & RR_USE_SL) {
3008231200Smm		/*
3009231200Smm		 *   "SL" Format:
3010231200Smm		 *     e.g. a symbolic name is 'foo/bar'
3011231200Smm		 *               len  ver  flg
3012231200Smm		 *    +----+----+----+----+----+------------+
3013231200Smm		 *    | 'S'| 'L'| 0F | 01 | 00 | components |
3014231200Smm		 *    +----+----+----+----+----+-----+------+
3015231200Smm		 *    0    1    2    3    4    5  ...|...  15
3016231200Smm		 *    <----------------- len --------+------>
3017231200Smm		 *    components :                   |
3018231200Smm		 *     cflg clen                     |
3019231200Smm		 *    +----+----+----+----+----+     |
3020231200Smm		 *    | 00 | 03 | 'f'| 'o'| 'o'| <---+
3021231200Smm		 *    +----+----+----+----+----+     |
3022231200Smm		 *    5    6    7    8    9   10     |
3023231200Smm		 *     cflg clen                     |
3024231200Smm		 *    +----+----+----+----+----+     |
3025231200Smm		 *    | 00 | 03 | 'b'| 'a'| 'r'| <---+
3026231200Smm		 *    +----+----+----+----+----+
3027231200Smm		 *   10   11   12   13   14   15
3028231200Smm		 *
3029311042Smm		 *    - cflg : flag of component
3030311042Smm		 *    - clen : length of component
3031231200Smm		 */
3032231200Smm		const char *sl;
3033231200Smm		char sl_last;
3034231200Smm
3035231200Smm		if (extra_space(&ctl) < 7)
3036231200Smm			bp = extra_next_record(&ctl, 7);
3037231200Smm		sl = file->symlink.s;
3038231200Smm		sl_last = '\0';
3039231200Smm		if (bp != NULL) {
3040231200Smm			bp[1] = 'S';
3041231200Smm			bp[2] = 'L';
3042231200Smm			bp[4] = 1;	/* version	*/
3043231200Smm		}
3044231200Smm		for (;;) {
3045231200Smm			unsigned char *nc, *cf,  *cl, cldmy = 0;
3046231200Smm			int sllen, slmax;
3047231200Smm
3048231200Smm			slmax = extra_space(&ctl);
3049231200Smm			if (slmax > 0xff)
3050231200Smm				slmax = 0xff;
3051231200Smm			if (bp != NULL)
3052231200Smm				nc = &bp[6];
3053231200Smm			else
3054231200Smm				nc = NULL;
3055231200Smm			cf = cl = NULL;
3056231200Smm			sllen = 0;
3057231200Smm			while (*sl && sllen + 11 < slmax) {
3058231200Smm				if (sl_last == '\0' && sl[0] == '/') {
3059231200Smm					/*
3060231200Smm					 *     flg  len
3061231200Smm					 *    +----+----+
3062231200Smm					 *    | 08 | 00 | ROOT component.
3063231200Smm					 *    +----+----+ ("/")
3064231200Smm					 *
3065231200Smm				 	 * Root component has to appear
3066231200Smm				 	 * at the first component only.
3067231200Smm					 */
3068231200Smm					if (nc != NULL) {
3069231200Smm						cf = nc++;
3070231200Smm						*cf = 0x08; /* ROOT */
3071231200Smm						*nc++ = 0;
3072231200Smm					}
3073231200Smm					sllen += 2;
3074231200Smm					sl++;
3075231200Smm					sl_last = '/';
3076231200Smm					cl = NULL;
3077231200Smm					continue;
3078231200Smm				}
3079231200Smm				if (((sl_last == '\0' || sl_last == '/') &&
3080231200Smm				      sl[0] == '.' && sl[1] == '.' &&
3081231200Smm				     (sl[2] == '/' || sl[2] == '\0')) ||
3082231200Smm				    (sl[0] == '/' &&
3083231200Smm				      sl[1] == '.' && sl[2] == '.' &&
3084231200Smm				     (sl[3] == '/' || sl[3] == '\0'))) {
3085231200Smm					/*
3086231200Smm					 *     flg  len
3087231200Smm					 *    +----+----+
3088231200Smm					 *    | 04 | 00 | PARENT component.
3089231200Smm					 *    +----+----+ ("..")
3090231200Smm					 */
3091231200Smm					if (nc != NULL) {
3092231200Smm						cf = nc++;
3093231200Smm						*cf = 0x04; /* PARENT */
3094231200Smm						*nc++ = 0;
3095231200Smm					}
3096231200Smm					sllen += 2;
3097231200Smm					if (sl[0] == '/')
3098231200Smm						sl += 3;/* skip "/.." */
3099231200Smm					else
3100231200Smm						sl += 2;/* skip ".." */
3101231200Smm					sl_last = '.';
3102231200Smm					cl = NULL;
3103231200Smm					continue;
3104231200Smm				}
3105231200Smm				if (((sl_last == '\0' || sl_last == '/') &&
3106231200Smm				      sl[0] == '.' &&
3107231200Smm				     (sl[1] == '/' || sl[1] == '\0')) ||
3108231200Smm				    (sl[0] == '/' && sl[1] == '.' &&
3109231200Smm				     (sl[2] == '/' || sl[2] == '\0'))) {
3110231200Smm					/*
3111231200Smm					 *     flg  len
3112231200Smm					 *    +----+----+
3113313571Smm					 *    | 02 | 00 | CURRENT component.
3114231200Smm					 *    +----+----+ (".")
3115231200Smm					 */
3116231200Smm					if (nc != NULL) {
3117231200Smm						cf = nc++;
3118231200Smm						*cf = 0x02; /* CURRENT */
3119231200Smm						*nc++ = 0;
3120231200Smm					}
3121231200Smm					sllen += 2;
3122231200Smm					if (sl[0] == '/')
3123231200Smm						sl += 2;/* skip "/." */
3124231200Smm					else
3125231200Smm						sl ++;  /* skip "." */
3126231200Smm					sl_last = '.';
3127231200Smm					cl = NULL;
3128231200Smm					continue;
3129231200Smm				}
3130231200Smm				if (sl[0] == '/' || cl == NULL) {
3131231200Smm					if (nc != NULL) {
3132231200Smm						cf = nc++;
3133231200Smm						*cf = 0;
3134231200Smm						cl = nc++;
3135231200Smm						*cl = 0;
3136231200Smm					} else
3137231200Smm						cl = &cldmy;
3138231200Smm					sllen += 2;
3139231200Smm					if (sl[0] == '/') {
3140231200Smm						sl_last = *sl++;
3141231200Smm						continue;
3142231200Smm					}
3143231200Smm				}
3144231200Smm				sl_last = *sl++;
3145231200Smm				if (nc != NULL) {
3146231200Smm					*nc++ = sl_last;
3147231200Smm					(*cl) ++;
3148231200Smm				}
3149231200Smm				sllen++;
3150231200Smm			}
3151231200Smm			if (*sl) {
3152231200Smm				length = 5 + sllen;
3153231200Smm				if (bp != NULL) {
3154231200Smm					/*
3155231200Smm					 * Mark flg as CONTINUE component.
3156231200Smm					 */
3157231200Smm					*cf |= 0x01;
3158231200Smm					/*
3159231200Smm					 *               len  ver  flg
3160231200Smm					 *    +----+----+----+----+----+-
3161231200Smm					 *    | 'S'| 'L'| XX | 01 | 01 |
3162231200Smm					 *    +----+----+----+----+----+-
3163231200Smm					 *                           ^
3164231200Smm					 *           continues in next "SL"
3165231200Smm					 */
3166231200Smm					bp[3] = length;
3167231200Smm					bp[5] = 0x01;/* This Symbolic Link
3168231200Smm						      * continues in next
3169231200Smm						      * "SL" field */
3170231200Smm					bp += length;
3171231200Smm				}
3172231200Smm				extra_tell_used_size(&ctl, length);
3173231200Smm				if (extra_space(&ctl) < 11)
3174231200Smm					bp = extra_next_record(&ctl, 11);
3175231200Smm				if (bp != NULL) {
3176231200Smm					/* Next 'SL' */
3177231200Smm					bp[1] = 'S';
3178231200Smm					bp[2] = 'L';
3179231200Smm					bp[4] = 1;    /* version */
3180231200Smm				}
3181231200Smm			} else {
3182231200Smm				length = 5 + sllen;
3183231200Smm				if (bp != NULL) {
3184231200Smm					bp[3] = length;
3185231200Smm					bp[5] = 0;
3186231200Smm					bp += length;
3187231200Smm				}
3188231200Smm				extra_tell_used_size(&ctl, length);
3189231200Smm				break;
3190231200Smm			}
3191231200Smm		}
3192231200Smm	}
3193231200Smm
3194231200Smm	/* Write "TF" System Use Entry. */
3195231200Smm	if (rr_flag & RR_USE_TF) {
3196231200Smm		/*
3197231200Smm		 *   "TF" Format:
3198231200Smm		 *               len  ver
3199231200Smm		 *    +----+----+----+----+-----+-------------+
3200231200Smm		 *    | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |
3201231200Smm		 *    +----+----+----+----+-----+-------------+
3202231200Smm		 *    0    1    2    3    4     5            XX
3203231200Smm		 *    TIME STAMPS : ISO 9660 Standard 9.1.5.
3204231200Smm		 *                  If TF_LONG_FORM FLAGS is set,
3205231200Smm		 *                  use ISO9660 Standard 8.4.26.1.
3206231200Smm		 */
3207231200Smm#define TF_CREATION	0x01	/* Creation time recorded		*/
3208231200Smm#define TF_MODIFY	0x02	/* Modification time recorded		*/
3209231200Smm#define TF_ACCESS	0x04	/* Last Access time recorded		*/
3210231200Smm#define TF_ATTRIBUTES	0x08	/* Last Attribute Change time recorded  */
3211231200Smm#define TF_BACKUP	0x10	/* Last Backup time recorded		*/
3212231200Smm#define TF_EXPIRATION	0x20	/* Expiration time recorded		*/
3213231200Smm#define TF_EFFECTIVE	0x40	/* Effective time recorded		*/
3214231200Smm#define TF_LONG_FORM	0x80	/* ISO 9660 17-byte time format used	*/
3215231200Smm		unsigned char tf_flags;
3216231200Smm
3217231200Smm		length = 5;
3218231200Smm		tf_flags = 0;
3219231200Smm#ifndef COMPAT_MKISOFS
3220231200Smm		if (archive_entry_birthtime_is_set(file->entry) &&
3221231200Smm		    archive_entry_birthtime(file->entry) <=
3222231200Smm		    archive_entry_mtime(file->entry)) {
3223231200Smm			length += 7;
3224231200Smm			tf_flags |= TF_CREATION;
3225231200Smm		}
3226231200Smm#endif
3227231200Smm		if (archive_entry_mtime_is_set(file->entry)) {
3228231200Smm			length += 7;
3229231200Smm			tf_flags |= TF_MODIFY;
3230231200Smm		}
3231231200Smm		if (archive_entry_atime_is_set(file->entry)) {
3232231200Smm			length += 7;
3233231200Smm			tf_flags |= TF_ACCESS;
3234231200Smm		}
3235231200Smm		if (archive_entry_ctime_is_set(file->entry)) {
3236231200Smm			length += 7;
3237231200Smm			tf_flags |= TF_ATTRIBUTES;
3238231200Smm		}
3239231200Smm		if (extra_space(&ctl) < length)
3240231200Smm			bp = extra_next_record(&ctl, length);
3241231200Smm		if (bp != NULL) {
3242231200Smm			bp[1] = 'T';
3243231200Smm			bp[2] = 'F';
3244231200Smm			bp[3] = length;
3245231200Smm			bp[4] = 1;	/* version	*/
3246231200Smm			bp[5] = tf_flags;
3247231200Smm			bp += 5;
3248231200Smm			/* Creation time */
3249231200Smm			if (tf_flags & TF_CREATION) {
3250231200Smm				set_time_915(bp+1,
3251231200Smm				    archive_entry_birthtime(file->entry));
3252231200Smm				bp += 7;
3253231200Smm			}
3254231200Smm			/* Modification time */
3255231200Smm			if (tf_flags & TF_MODIFY) {
3256231200Smm				set_time_915(bp+1,
3257231200Smm				    archive_entry_mtime(file->entry));
3258231200Smm				bp += 7;
3259231200Smm			}
3260231200Smm			/* Last Access time */
3261231200Smm			if (tf_flags & TF_ACCESS) {
3262231200Smm				set_time_915(bp+1,
3263231200Smm				    archive_entry_atime(file->entry));
3264231200Smm				bp += 7;
3265231200Smm			}
3266231200Smm			/* Last Attribute Change time */
3267231200Smm			if (tf_flags & TF_ATTRIBUTES) {
3268231200Smm				set_time_915(bp+1,
3269231200Smm				    archive_entry_ctime(file->entry));
3270231200Smm				bp += 7;
3271231200Smm			}
3272231200Smm		}
3273231200Smm		extra_tell_used_size(&ctl, length);
3274231200Smm	}
3275231200Smm
3276231200Smm	/* Write "RE" System Use Entry. */
3277231200Smm	if (rr_flag & RR_USE_RE) {
3278231200Smm		/*
3279231200Smm		 *   "RE" Format:
3280231200Smm		 *               len  ver
3281231200Smm		 *    +----+----+----+----+
3282231200Smm		 *    | 'R'| 'E'| 04 | 01 |
3283231200Smm		 *    +----+----+----+----+
3284231200Smm		 *    0    1    2    3    4
3285231200Smm		 */
3286231200Smm		length = 4;
3287231200Smm		if (extra_space(&ctl) < length)
3288231200Smm			bp = extra_next_record(&ctl, length);
3289231200Smm		if (bp != NULL) {
3290231200Smm			bp[1] = 'R';
3291231200Smm			bp[2] = 'E';
3292231200Smm			bp[3] = length;
3293231200Smm			bp[4] = 1;	/* version	*/
3294231200Smm			bp += length;
3295231200Smm		}
3296231200Smm		extra_tell_used_size(&ctl, length);
3297231200Smm	}
3298231200Smm
3299231200Smm	/* Write "PL" System Use Entry. */
3300231200Smm	if (rr_flag & RR_USE_PL) {
3301231200Smm		/*
3302231200Smm		 *   "PL" Format:
3303231200Smm		 *               len  ver
3304231200Smm		 *    +----+----+----+----+------------+
3305231200Smm		 *    | 'P'| 'L'| 0C | 01 | *LOCATION  |
3306231200Smm		 *    +----+----+----+----+------------+
3307231200Smm		 *    0    1    2    3    4           12
3308231200Smm		 *    *LOCATION: location of parent directory
3309231200Smm		 */
3310231200Smm		length = 12;
3311231200Smm		if (extra_space(&ctl) < length)
3312231200Smm			bp = extra_next_record(&ctl, length);
3313231200Smm		if (bp != NULL) {
3314231200Smm			bp[1] = 'P';
3315231200Smm			bp[2] = 'L';
3316231200Smm			bp[3] = length;
3317231200Smm			bp[4] = 1;	/* version	*/
3318231200Smm			set_num_733(bp + 5,
3319231200Smm			    rr_parent->dir_location);
3320231200Smm			bp += length;
3321231200Smm		}
3322231200Smm		extra_tell_used_size(&ctl, length);
3323231200Smm	}
3324231200Smm
3325231200Smm	/* Write "CL" System Use Entry. */
3326231200Smm	if (rr_flag & RR_USE_CL) {
3327231200Smm		/*
3328231200Smm		 *   "CL" Format:
3329231200Smm		 *               len  ver
3330231200Smm		 *    +----+----+----+----+------------+
3331231200Smm		 *    | 'C'| 'L'| 0C | 01 | *LOCATION  |
3332231200Smm		 *    +----+----+----+----+------------+
3333231200Smm		 *    0    1    2    3    4           12
3334231200Smm		 *    *LOCATION: location of child directory
3335231200Smm		 */
3336231200Smm		length = 12;
3337231200Smm		if (extra_space(&ctl) < length)
3338231200Smm			bp = extra_next_record(&ctl, length);
3339231200Smm		if (bp != NULL) {
3340231200Smm			bp[1] = 'C';
3341231200Smm			bp[2] = 'L';
3342231200Smm			bp[3] = length;
3343231200Smm			bp[4] = 1;	/* version	*/
3344231200Smm			set_num_733(bp + 5,
3345231200Smm			    isoent->rr_child->dir_location);
3346231200Smm			bp += length;
3347231200Smm		}
3348231200Smm		extra_tell_used_size(&ctl, length);
3349231200Smm	}
3350231200Smm
3351231200Smm	/* Write "PN" System Use Entry. */
3352231200Smm	if (rr_flag & RR_USE_PN) {
3353231200Smm		/*
3354231200Smm		 *   "PN" Format:
3355231200Smm		 *               len  ver
3356231200Smm		 *    +----+----+----+----+------------+------------+
3357231200Smm		 *    | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low  |
3358231200Smm		 *    +----+----+----+----+------------+------------+
3359231200Smm		 *    0    1    2    3    4           12           20
3360231200Smm		 */
3361231200Smm		length = 20;
3362231200Smm		if (extra_space(&ctl) < length)
3363231200Smm			bp = extra_next_record(&ctl, length);
3364231200Smm		if (bp != NULL) {
3365231200Smm			uint64_t dev;
3366231200Smm
3367231200Smm			bp[1] = 'P';
3368231200Smm			bp[2] = 'N';
3369231200Smm			bp[3] = length;
3370231200Smm			bp[4] = 1;	/* version	*/
3371231200Smm			dev = (uint64_t)archive_entry_rdev(file->entry);
3372238856Smm			set_num_733(bp + 5, (uint32_t)(dev >> 32));
3373238856Smm			set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
3374231200Smm			bp += length;
3375231200Smm		}
3376231200Smm		extra_tell_used_size(&ctl, length);
3377231200Smm	}
3378231200Smm
3379231200Smm	/* Write "ZF" System Use Entry. */
3380231200Smm	if (file->zisofs.header_size) {
3381231200Smm		/*
3382231200Smm		 *   "ZF" Format:
3383231200Smm		 *               len  ver
3384231200Smm		 *    +----+----+----+----+----+----+-------------+
3385231200Smm		 *    | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |
3386231200Smm		 *    +----+----+----+----+----+----+-------------+
3387231200Smm		 *    0    1    2    3    4    5    6             7
3388231200Smm		 *    +--------------------+-------------------+
3389231200Smm		 *    | Log2 of block Size | Uncompressed Size |
3390231200Smm		 *    +--------------------+-------------------+
3391231200Smm		 *    7                    8                   16
3392231200Smm		 */
3393231200Smm		length = 16;
3394231200Smm		if (extra_space(&ctl) < length)
3395231200Smm			bp = extra_next_record(&ctl, length);
3396231200Smm		if (bp != NULL) {
3397231200Smm			bp[1] = 'Z';
3398231200Smm			bp[2] = 'F';
3399231200Smm			bp[3] = length;
3400231200Smm			bp[4] = 1;	/* version	*/
3401231200Smm			bp[5] = 'p';
3402231200Smm			bp[6] = 'z';
3403231200Smm			bp[7] = file->zisofs.header_size;
3404231200Smm			bp[8] = file->zisofs.log2_bs;
3405231200Smm			set_num_733(bp + 9, file->zisofs.uncompressed_size);
3406231200Smm			bp += length;
3407231200Smm		}
3408231200Smm		extra_tell_used_size(&ctl, length);
3409231200Smm	}
3410231200Smm
3411231200Smm	/* Write "CE" System Use Entry. */
3412231200Smm	if (t == DIR_REC_SELF && isoent == isoent->parent) {
3413231200Smm		length = RR_CE_SIZE;
3414231200Smm		if (bp != NULL)
3415231200Smm			set_SUSP_CE(bp+1, iso9660->location_rrip_er,
3416231200Smm			    0, RRIP_ER_SIZE);
3417231200Smm		extra_tell_used_size(&ctl, length);
3418231200Smm	}
3419231200Smm
3420231200Smm	extra_close_record(&ctl, 0);
3421231200Smm
3422231200Smm	return (ctl.dr_len);
3423231200Smm}
3424231200Smm
3425231200Smm/*
3426231200Smm * Write data of a Directory Record or calculate writing bytes itself.
3427231200Smm * If parameter `p' is NULL, calculates the size of writing data, which
3428231200Smm * a Directory Record needs to write, then it saved and return
3429231200Smm * the calculated size.
3430231200Smm * Parameter `n' is a remaining size of buffer. when parameter `p' is
3431231200Smm * not NULL, check whether that `n' is not less than the saved size.
3432231200Smm * if that `n' is small, return zero.
3433231200Smm *
3434231200Smm * This format of the Directory Record is according to
3435231200Smm * ISO9660 Standard 9.1
3436231200Smm */
3437231200Smmstatic int
3438231200Smmset_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
3439231200Smm    struct iso9660 *iso9660, enum dir_rec_type t,
3440231200Smm    enum vdd_type vdd_type)
3441231200Smm{
3442231200Smm	unsigned char *bp;
3443231200Smm	size_t dr_len;
3444231200Smm	size_t fi_len;
3445231200Smm
3446231200Smm	if (p != NULL) {
3447231200Smm		/*
3448231200Smm		 * Check whether a write buffer size is less than the
3449231200Smm		 * saved size which is needed to write this Directory
3450231200Smm		 * Record.
3451231200Smm		 */
3452231200Smm		switch (t) {
3453231200Smm		case DIR_REC_VD:
3454231200Smm			dr_len = isoent->dr_len.vd; break;
3455231200Smm		case DIR_REC_SELF:
3456231200Smm			dr_len = isoent->dr_len.self; break;
3457231200Smm		case DIR_REC_PARENT:
3458231200Smm			dr_len = isoent->dr_len.parent; break;
3459231200Smm		case DIR_REC_NORMAL:
3460231200Smm		default:
3461231200Smm			dr_len = isoent->dr_len.normal; break;
3462231200Smm		}
3463231200Smm		if (dr_len > n)
3464231200Smm			return (0);/* Needs more buffer size. */
3465231200Smm	}
3466231200Smm
3467231200Smm	if (t == DIR_REC_NORMAL && isoent->identifier != NULL)
3468231200Smm		fi_len = isoent->id_len;
3469231200Smm	else
3470231200Smm		fi_len = 1;
3471231200Smm
3472231200Smm	if (p != NULL) {
3473231200Smm		struct isoent *xisoent;
3474231200Smm		struct isofile *file;
3475231200Smm		unsigned char flag;
3476231200Smm
3477231200Smm		if (t == DIR_REC_PARENT)
3478231200Smm			xisoent = isoent->parent;
3479231200Smm		else
3480231200Smm			xisoent = isoent;
3481231200Smm		file = isoent->file;
3482231200Smm		if (file->hardlink_target != NULL)
3483231200Smm			file = file->hardlink_target;
3484231200Smm		/* Make a file flag. */
3485231200Smm		if (xisoent->dir)
3486231200Smm			flag = FILE_FLAG_DIRECTORY;
3487231200Smm		else {
3488231200Smm			if (file->cur_content->next != NULL)
3489231200Smm				flag = FILE_FLAG_MULTI_EXTENT;
3490231200Smm			else
3491231200Smm				flag = 0;
3492231200Smm		}
3493231200Smm
3494231200Smm		bp = p -1;
3495231200Smm		/* Extended Attribute Record Length */
3496231200Smm		set_num_711(bp+2, 0);
3497231200Smm		/* Location of Extent */
3498231200Smm		if (xisoent->dir)
3499231200Smm			set_num_733(bp+3, xisoent->dir_location);
3500231200Smm		else
3501231200Smm			set_num_733(bp+3, file->cur_content->location);
3502231200Smm		/* Data Length */
3503231200Smm		if (xisoent->dir)
3504231200Smm			set_num_733(bp+11,
3505231200Smm			    xisoent->dir_block * LOGICAL_BLOCK_SIZE);
3506231200Smm		else
3507238856Smm			set_num_733(bp+11, (uint32_t)file->cur_content->size);
3508231200Smm		/* Recording Date and Time */
3509231200Smm		/* NOTE:
3510231200Smm		 *  If a file type is symbolic link, you are seeing this
3511231200Smm		 *  field value is different from a value mkisofs makes.
3512231200Smm		 *  libarchive uses lstat to get this one, but it
3513231200Smm		 *  seems mkisofs uses stat to get.
3514231200Smm		 */
3515231200Smm		set_time_915(bp+19,
3516231200Smm		    archive_entry_mtime(xisoent->file->entry));
3517231200Smm		/* File Flags */
3518231200Smm		bp[26] = flag;
3519231200Smm		/* File Unit Size */
3520231200Smm		set_num_711(bp+27, 0);
3521231200Smm		/* Interleave Gap Size */
3522231200Smm		set_num_711(bp+28, 0);
3523231200Smm		/* Volume Sequence Number */
3524231200Smm		set_num_723(bp+29, iso9660->volume_sequence_number);
3525231200Smm		/* Length of File Identifier */
3526248616Smm		set_num_711(bp+33, (unsigned char)fi_len);
3527231200Smm		/* File Identifier */
3528231200Smm		switch (t) {
3529231200Smm		case DIR_REC_VD:
3530231200Smm		case DIR_REC_SELF:
3531231200Smm			set_num_711(bp+34, 0);
3532231200Smm			break;
3533231200Smm		case DIR_REC_PARENT:
3534231200Smm			set_num_711(bp+34, 1);
3535231200Smm			break;
3536231200Smm		case DIR_REC_NORMAL:
3537231200Smm			if (isoent->identifier != NULL)
3538231200Smm				memcpy(bp+34, isoent->identifier, fi_len);
3539231200Smm			else
3540231200Smm				set_num_711(bp+34, 0);
3541231200Smm			break;
3542231200Smm		}
3543231200Smm	} else
3544231200Smm		bp = NULL;
3545231200Smm	dr_len = 33 + fi_len;
3546231200Smm	/* Padding Field */
3547231200Smm	if (dr_len & 0x01) {
3548231200Smm		dr_len ++;
3549231200Smm		if (p != NULL)
3550231200Smm			bp[dr_len] = 0;
3551231200Smm	}
3552231200Smm
3553231200Smm	/* Volume Descriptor does not record extension. */
3554231200Smm	if (t == DIR_REC_VD) {
3555231200Smm		if (p != NULL)
3556231200Smm			/* Length of Directory Record */
3557248616Smm			set_num_711(p, (unsigned char)dr_len);
3558231200Smm		else
3559248616Smm			isoent->dr_len.vd = (int)dr_len;
3560248616Smm		return ((int)dr_len);
3561231200Smm	}
3562231200Smm
3563231200Smm	/* Rockridge */
3564231200Smm	if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
3565248616Smm		dr_len = set_directory_record_rr(bp, (int)dr_len,
3566231200Smm		    isoent, iso9660, t);
3567231200Smm
3568231200Smm	if (p != NULL)
3569231200Smm		/* Length of Directory Record */
3570248616Smm		set_num_711(p, (unsigned char)dr_len);
3571231200Smm	else {
3572231200Smm		/*
3573231200Smm		 * Save the size which is needed to write this
3574231200Smm		 * Directory Record.
3575231200Smm		 */
3576231200Smm		switch (t) {
3577231200Smm		case DIR_REC_VD:
3578231200Smm			/* This case does not come, but compiler
3579231200Smm			 * complains that DIR_REC_VD not handled
3580231200Smm			 *  in switch ....  */
3581231200Smm			break;
3582231200Smm		case DIR_REC_SELF:
3583248616Smm			isoent->dr_len.self = (int)dr_len; break;
3584231200Smm		case DIR_REC_PARENT:
3585248616Smm			isoent->dr_len.parent = (int)dr_len; break;
3586231200Smm		case DIR_REC_NORMAL:
3587248616Smm			isoent->dr_len.normal = (int)dr_len; break;
3588231200Smm		}
3589231200Smm	}
3590231200Smm
3591248616Smm	return ((int)dr_len);
3592231200Smm}
3593231200Smm
3594231200Smm/*
3595231200Smm * Calculate the size of a directory record.
3596231200Smm */
3597231200Smmstatic inline int
3598231200Smmget_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
3599231200Smm    enum dir_rec_type t, enum vdd_type vdd_type)
3600231200Smm{
3601231200Smm
3602231200Smm	return (set_directory_record(NULL, SIZE_MAX,
3603231200Smm	    isoent, iso9660, t, vdd_type));
3604231200Smm}
3605231200Smm
3606231200Smm/*
3607231200Smm * Manage to write ISO-image data with wbuff to reduce calling
3608231200Smm * __archive_write_output() for performance.
3609231200Smm */
3610231200Smm
3611231200Smm
3612231200Smmstatic inline unsigned char *
3613231200Smmwb_buffptr(struct archive_write *a)
3614231200Smm{
3615231200Smm	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3616231200Smm
3617231200Smm	return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
3618231200Smm		- iso9660->wbuff_remaining]));
3619231200Smm}
3620231200Smm
3621231200Smmstatic int
3622231200Smmwb_write_out(struct archive_write *a)
3623231200Smm{
3624231200Smm	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3625231200Smm	size_t wsize, nw;
3626231200Smm	int r;
3627231200Smm
3628231200Smm	wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
3629231200Smm	nw = wsize % LOGICAL_BLOCK_SIZE;
3630231200Smm	if (iso9660->wbuff_type == WB_TO_STREAM)
3631231200Smm		r = __archive_write_output(a, iso9660->wbuff, wsize - nw);
3632231200Smm	else
3633231200Smm		r = write_to_temp(a, iso9660->wbuff, wsize - nw);
3634231200Smm	/* Increase the offset. */
3635231200Smm	iso9660->wbuff_offset += wsize - nw;
3636231200Smm	if (iso9660->wbuff_offset > iso9660->wbuff_written)
3637231200Smm		iso9660->wbuff_written = iso9660->wbuff_offset;
3638231200Smm	iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3639231200Smm	if (nw) {
3640231200Smm		iso9660->wbuff_remaining -= nw;
3641231200Smm		memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);
3642231200Smm	}
3643231200Smm	return (r);
3644231200Smm}
3645231200Smm
3646231200Smmstatic int
3647231200Smmwb_consume(struct archive_write *a, size_t size)
3648231200Smm{
3649231200Smm	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3650231200Smm
3651231200Smm	if (size > iso9660->wbuff_remaining ||
3652231200Smm	    iso9660->wbuff_remaining == 0) {
3653231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3654353377Smm		    "Internal Programming error: iso9660:wb_consume()"
3655231200Smm		    " size=%jd, wbuff_remaining=%jd",
3656231200Smm		    (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);
3657231200Smm		return (ARCHIVE_FATAL);
3658231200Smm	}
3659231200Smm	iso9660->wbuff_remaining -= size;
3660231200Smm	if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)
3661231200Smm		return (wb_write_out(a));
3662231200Smm	return (ARCHIVE_OK);
3663231200Smm}
3664231200Smm
3665231200Smm#ifdef HAVE_ZLIB_H
3666231200Smm
3667231200Smmstatic int
3668231200Smmwb_set_offset(struct archive_write *a, int64_t off)
3669231200Smm{
3670231200Smm	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3671231200Smm	int64_t used, ext_bytes;
3672231200Smm
3673231200Smm	if (iso9660->wbuff_type != WB_TO_TEMP) {
3674231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3675353377Smm		    "Internal Programming error: iso9660:wb_set_offset()");
3676231200Smm		return (ARCHIVE_FATAL);
3677231200Smm	}
3678231200Smm
3679231200Smm	used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
3680231200Smm	if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)
3681231200Smm		iso9660->wbuff_tail = iso9660->wbuff_offset + used;
3682231200Smm	if (iso9660->wbuff_offset < iso9660->wbuff_written) {
3683231200Smm		if (used > 0 &&
3684238856Smm		    write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
3685231200Smm			return (ARCHIVE_FATAL);
3686231200Smm		iso9660->wbuff_offset = iso9660->wbuff_written;
3687231200Smm		lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
3688231200Smm		iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3689231200Smm		used = 0;
3690231200Smm	}
3691231200Smm	if (off < iso9660->wbuff_offset) {
3692231200Smm		/*
3693231200Smm		 * Write out waiting data.
3694231200Smm		 */
3695231200Smm		if (used > 0) {
3696231200Smm			if (wb_write_out(a) != ARCHIVE_OK)
3697231200Smm				return (ARCHIVE_FATAL);
3698231200Smm		}
3699231200Smm		lseek(iso9660->temp_fd, off, SEEK_SET);
3700231200Smm		iso9660->wbuff_offset = off;
3701231200Smm		iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3702231200Smm	} else if (off <= iso9660->wbuff_tail) {
3703238856Smm		iso9660->wbuff_remaining = (size_t)
3704238856Smm		    (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
3705231200Smm	} else {
3706231200Smm		ext_bytes = off - iso9660->wbuff_tail;
3707238856Smm		iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
3708238856Smm		   - (iso9660->wbuff_tail - iso9660->wbuff_offset));
3709232153Smm		while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
3710231200Smm			if (write_null(a, (size_t)iso9660->wbuff_remaining)
3711231200Smm			    != ARCHIVE_OK)
3712231200Smm				return (ARCHIVE_FATAL);
3713231200Smm			ext_bytes -= iso9660->wbuff_remaining;
3714231200Smm		}
3715231200Smm		if (ext_bytes > 0) {
3716231200Smm			if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)
3717231200Smm				return (ARCHIVE_FATAL);
3718231200Smm		}
3719231200Smm	}
3720231200Smm	return (ARCHIVE_OK);
3721231200Smm}
3722231200Smm
3723231200Smm#endif /* HAVE_ZLIB_H */
3724231200Smm
3725231200Smmstatic int
3726231200Smmwrite_null(struct archive_write *a, size_t size)
3727231200Smm{
3728231200Smm	size_t remaining;
3729231200Smm	unsigned char *p, *old;
3730231200Smm	int r;
3731231200Smm
3732231200Smm	remaining = wb_remaining(a);
3733231200Smm	p = wb_buffptr(a);
3734231200Smm	if (size <= remaining) {
3735231200Smm		memset(p, 0, size);
3736231200Smm		return (wb_consume(a, size));
3737231200Smm	}
3738231200Smm	memset(p, 0, remaining);
3739231200Smm	r = wb_consume(a, remaining);
3740231200Smm	if (r != ARCHIVE_OK)
3741231200Smm		return (r);
3742231200Smm	size -= remaining;
3743231200Smm	old = p;
3744231200Smm	p = wb_buffptr(a);
3745231200Smm	memset(p, 0, old - p);
3746231200Smm	remaining = wb_remaining(a);
3747231200Smm	while (size) {
3748231200Smm		size_t wsize = size;
3749231200Smm
3750231200Smm		if (wsize > remaining)
3751231200Smm			wsize = remaining;
3752231200Smm		r = wb_consume(a, wsize);
3753231200Smm		if (r != ARCHIVE_OK)
3754231200Smm			return (r);
3755231200Smm		size -= wsize;
3756231200Smm	}
3757231200Smm	return (ARCHIVE_OK);
3758231200Smm}
3759231200Smm
3760231200Smm/*
3761231200Smm * Write Volume Descriptor Set Terminator
3762231200Smm */
3763231200Smmstatic int
3764231200Smmwrite_VD_terminator(struct archive_write *a)
3765231200Smm{
3766231200Smm	unsigned char *bp;
3767231200Smm
3768231200Smm	bp = wb_buffptr(a) -1;
3769231200Smm	set_VD_bp(bp, VDT_TERMINATOR, 1);
3770231200Smm	set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);
3771231200Smm
3772231200Smm	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
3773231200Smm}
3774231200Smm
3775231200Smmstatic int
3776231200Smmset_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
3777231200Smm    struct archive_write *a, struct vdd *vdd, struct archive_string *id,
3778231200Smm    const char *label, int leading_under, enum char_type char_type)
3779231200Smm{
3780231200Smm	char identifier[256];
3781231200Smm	struct isoent *isoent;
3782231200Smm	const char *ids;
3783231200Smm	size_t len;
3784231200Smm	int r;
3785231200Smm
3786231200Smm	if (id->length > 0 && leading_under && id->s[0] != '_') {
3787231200Smm		if (char_type == A_CHAR)
3788231200Smm			r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);
3789231200Smm		else
3790231200Smm			r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);
3791231200Smm	} else if (id->length > 0) {
3792231200Smm		ids = id->s;
3793231200Smm		if (leading_under)
3794231200Smm			ids++;
3795231200Smm		isoent = isoent_find_entry(vdd->rootent, ids);
3796231200Smm		if (isoent == NULL) {
3797231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3798231200Smm			    "Not Found %s `%s'.",
3799231200Smm			    label, ids);
3800231200Smm			return (ARCHIVE_FATAL);
3801231200Smm		}
3802231200Smm		len = isoent->ext_off + isoent->ext_len;
3803231200Smm		if (vdd->vdd_type == VDD_JOLIET) {
3804231200Smm			if (len > sizeof(identifier)-2)
3805231200Smm				len = sizeof(identifier)-2;
3806231200Smm		} else {
3807231200Smm			if (len > sizeof(identifier)-1)
3808231200Smm				len = sizeof(identifier)-1;
3809231200Smm		}
3810231200Smm		memcpy(identifier, isoent->identifier, len);
3811231200Smm		identifier[len] = '\0';
3812231200Smm		if (vdd->vdd_type == VDD_JOLIET) {
3813231200Smm			identifier[len+1] = 0;
3814231200Smm			vdc = VDC_UCS2_DIRECT;
3815231200Smm		}
3816231200Smm		if (char_type == A_CHAR)
3817231200Smm			r = set_str_a_characters_bp(a, bp, from, to,
3818231200Smm			    identifier, vdc);
3819231200Smm		else
3820231200Smm			r = set_str_d_characters_bp(a, bp, from, to,
3821231200Smm			    identifier, vdc);
3822231200Smm	} else {
3823231200Smm		if (char_type == A_CHAR)
3824231200Smm			r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);
3825231200Smm		else
3826231200Smm			r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);
3827231200Smm	}
3828231200Smm	return (r);
3829231200Smm}
3830231200Smm
3831231200Smm/*
3832231200Smm * Write Primary/Supplementary Volume Descriptor
3833231200Smm */
3834231200Smmstatic int
3835231200Smmwrite_VD(struct archive_write *a, struct vdd *vdd)
3836231200Smm{
3837231200Smm	struct iso9660 *iso9660;
3838231200Smm	unsigned char *bp;
3839231200Smm	uint16_t volume_set_size = 1;
3840231200Smm	char identifier[256];
3841231200Smm	enum VD_type vdt;
3842231200Smm	enum vdc vdc;
3843231200Smm	unsigned char vd_ver, fst_ver;
3844231200Smm	int r;
3845231200Smm
3846231200Smm	iso9660 = a->format_data;
3847231200Smm	switch (vdd->vdd_type) {
3848231200Smm	case VDD_JOLIET:
3849231200Smm		vdt = VDT_SUPPLEMENTARY;
3850231200Smm		vd_ver = fst_ver = 1;
3851231200Smm		vdc = VDC_UCS2;
3852231200Smm		break;
3853231200Smm	case VDD_ENHANCED:
3854231200Smm		vdt = VDT_SUPPLEMENTARY;
3855231200Smm		vd_ver = fst_ver = 2;
3856231200Smm		vdc = VDC_LOWERCASE;
3857231200Smm		break;
3858231200Smm	case VDD_PRIMARY:
3859231200Smm	default:
3860231200Smm		vdt = VDT_PRIMARY;
3861231200Smm		vd_ver = fst_ver = 1;
3862231200Smm#ifdef COMPAT_MKISOFS
3863231200Smm		vdc = VDC_LOWERCASE;
3864231200Smm#else
3865231200Smm		vdc = VDC_STD;
3866231200Smm#endif
3867231200Smm		break;
3868231200Smm	}
3869231200Smm
3870231200Smm	bp = wb_buffptr(a) -1;
3871231200Smm	/* Volume Descriptor Type */
3872231200Smm	set_VD_bp(bp, vdt, vd_ver);
3873231200Smm	/* Unused Field */
3874231200Smm	set_unused_field_bp(bp, 8, 8);
3875231200Smm	/* System Identifier */
3876231200Smm	get_system_identitier(identifier, sizeof(identifier));
3877231200Smm	r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);
3878231200Smm	if (r != ARCHIVE_OK)
3879231200Smm		return (r);
3880231200Smm	/* Volume Identifier */
3881231200Smm	r = set_str_d_characters_bp(a, bp, 41, 72,
3882231200Smm	    iso9660->volume_identifier.s, vdc);
3883231200Smm	if (r != ARCHIVE_OK)
3884231200Smm		return (r);
3885231200Smm	/* Unused Field */
3886231200Smm	set_unused_field_bp(bp, 73, 80);
3887231200Smm	/* Volume Space Size */
3888231200Smm	set_num_733(bp+81, iso9660->volume_space_size);
3889231200Smm	if (vdd->vdd_type == VDD_JOLIET) {
3890231200Smm		/* Escape Sequences */
3891231200Smm		bp[89] = 0x25;/* UCS-2 Level 3 */
3892231200Smm		bp[90] = 0x2F;
3893231200Smm		bp[91] = 0x45;
3894231200Smm		memset(bp + 92, 0, 120 - 92 + 1);
3895231200Smm	} else {
3896231200Smm		/* Unused Field */
3897231200Smm		set_unused_field_bp(bp, 89, 120);
3898231200Smm	}
3899231200Smm	/* Volume Set Size */
3900231200Smm	set_num_723(bp+121, volume_set_size);
3901231200Smm	/* Volume Sequence Number */
3902231200Smm	set_num_723(bp+125, iso9660->volume_sequence_number);
3903231200Smm	/* Logical Block Size */
3904231200Smm	set_num_723(bp+129, LOGICAL_BLOCK_SIZE);
3905231200Smm	/* Path Table Size */
3906231200Smm	set_num_733(bp+133, vdd->path_table_size);
3907231200Smm	/* Location of Occurrence of Type L Path Table */
3908231200Smm	set_num_731(bp+141, vdd->location_type_L_path_table);
3909231200Smm	/* Location of Optional Occurrence of Type L Path Table */
3910231200Smm	set_num_731(bp+145, 0);
3911231200Smm	/* Location of Occurrence of Type M Path Table */
3912231200Smm	set_num_732(bp+149, vdd->location_type_M_path_table);
3913231200Smm	/* Location of Optional Occurrence of Type M Path Table */
3914231200Smm	set_num_732(bp+153, 0);
3915231200Smm	/* Directory Record for Root Directory(BP 157 to 190) */
3916231200Smm	set_directory_record(bp+157, 190-157+1, vdd->rootent,
3917231200Smm	    iso9660, DIR_REC_VD, vdd->vdd_type);
3918231200Smm	/* Volume Set Identifier */
3919231200Smm	r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);
3920231200Smm	if (r != ARCHIVE_OK)
3921231200Smm		return (r);
3922231200Smm	/* Publisher Identifier */
3923231200Smm	r = set_file_identifier(bp, 319, 446, vdc, a, vdd,
3924231200Smm	    &(iso9660->publisher_identifier),
3925231200Smm	    "Publisher File", 1, A_CHAR);
3926231200Smm	if (r != ARCHIVE_OK)
3927231200Smm		return (r);
3928231200Smm	/* Data Preparer Identifier */
3929231200Smm	r = set_file_identifier(bp, 447, 574, vdc, a, vdd,
3930231200Smm	    &(iso9660->data_preparer_identifier),
3931231200Smm	    "Data Preparer File", 1, A_CHAR);
3932231200Smm	if (r != ARCHIVE_OK)
3933231200Smm		return (r);
3934231200Smm	/* Application Identifier */
3935231200Smm	r = set_file_identifier(bp, 575, 702, vdc, a, vdd,
3936231200Smm	    &(iso9660->application_identifier),
3937231200Smm	    "Application File", 1, A_CHAR);
3938231200Smm	if (r != ARCHIVE_OK)
3939231200Smm		return (r);
3940231200Smm	/* Copyright File Identifier */
3941231200Smm	r = set_file_identifier(bp, 703, 739, vdc, a, vdd,
3942231200Smm	    &(iso9660->copyright_file_identifier),
3943231200Smm	    "Copyright File", 0, D_CHAR);
3944231200Smm	if (r != ARCHIVE_OK)
3945231200Smm		return (r);
3946231200Smm	/* Abstract File Identifier */
3947231200Smm	r = set_file_identifier(bp, 740, 776, vdc, a, vdd,
3948231200Smm	    &(iso9660->abstract_file_identifier),
3949231200Smm	    "Abstract File", 0, D_CHAR);
3950231200Smm	if (r != ARCHIVE_OK)
3951231200Smm		return (r);
3952313571Smm	/* Bibliographic File Identifier */
3953231200Smm	r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
3954231200Smm	    &(iso9660->bibliographic_file_identifier),
3955231200Smm	    "Bibliongraphic File", 0, D_CHAR);
3956231200Smm	if (r != ARCHIVE_OK)
3957231200Smm		return (r);
3958231200Smm	/* Volume Creation Date and Time */
3959231200Smm	set_date_time(bp+814, iso9660->birth_time);
3960231200Smm	/* Volume Modification Date and Time */
3961231200Smm	set_date_time(bp+831, iso9660->birth_time);
3962231200Smm	/* Volume Expiration Date and Time(obsolete) */
3963231200Smm	set_date_time_null(bp+848);
3964231200Smm	/* Volume Effective Date and Time */
3965231200Smm	set_date_time(bp+865, iso9660->birth_time);
3966231200Smm	/* File Structure Version */
3967231200Smm	bp[882] = fst_ver;
3968231200Smm	/* Reserved */
3969231200Smm	bp[883] = 0;
3970231200Smm	/* Application Use */
3971231200Smm	memset(bp + 884, 0x20, 1395 - 884 + 1);
3972231200Smm	/* Reserved */
3973231200Smm	set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);
3974231200Smm
3975231200Smm	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
3976231200Smm}
3977231200Smm
3978231200Smm/*
3979231200Smm * Write Boot Record Volume Descriptor
3980231200Smm */
3981231200Smmstatic int
3982231200Smmwrite_VD_boot_record(struct archive_write *a)
3983231200Smm{
3984231200Smm	struct iso9660 *iso9660;
3985231200Smm	unsigned char *bp;
3986231200Smm
3987231200Smm	iso9660 = a->format_data;
3988231200Smm	bp = wb_buffptr(a) -1;
3989231200Smm	/* Volume Descriptor Type */
3990231200Smm	set_VD_bp(bp, VDT_BOOT_RECORD, 1);
3991231200Smm	/* Boot System Identifier */
3992231200Smm	memcpy(bp+8, "EL TORITO SPECIFICATION", 23);
3993231200Smm	set_unused_field_bp(bp, 8+23, 39);
3994231200Smm	/* Unused */
3995231200Smm	set_unused_field_bp(bp, 40, 71);
3996231200Smm	/* Absolute pointer to first sector of Boot Catalog */
3997231200Smm	set_num_731(bp+72,
3998231200Smm	    iso9660->el_torito.catalog->file->content.location);
3999231200Smm	/* Unused */
4000231200Smm	set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);
4001231200Smm
4002231200Smm	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4003231200Smm}
4004231200Smm
4005231200Smmenum keytype {
4006231200Smm	KEY_FLG,
4007231200Smm	KEY_STR,
4008231200Smm	KEY_INT,
4009302001Smm	KEY_HEX
4010231200Smm};
4011231200Smmstatic void
4012231200Smmset_option_info(struct archive_string *info, int *opt, const char *key,
4013231200Smm    enum keytype type,  ...)
4014231200Smm{
4015231200Smm	va_list ap;
4016231200Smm	char prefix;
4017231200Smm	const char *s;
4018231200Smm	int d;
4019231200Smm
4020231200Smm	prefix = (*opt==0)? ' ':',';
4021231200Smm	va_start(ap, type);
4022231200Smm	switch (type) {
4023231200Smm	case KEY_FLG:
4024231200Smm		d = va_arg(ap, int);
4025231200Smm		archive_string_sprintf(info, "%c%s%s",
4026231200Smm		    prefix, (d == 0)?"!":"", key);
4027231200Smm		break;
4028231200Smm	case KEY_STR:
4029231200Smm		s = va_arg(ap, const char *);
4030231200Smm		archive_string_sprintf(info, "%c%s=%s",
4031231200Smm		    prefix, key, s);
4032231200Smm		break;
4033231200Smm	case KEY_INT:
4034231200Smm		d = va_arg(ap, int);
4035231200Smm		archive_string_sprintf(info, "%c%s=%d",
4036231200Smm		    prefix, key, d);
4037231200Smm		break;
4038231200Smm	case KEY_HEX:
4039231200Smm		d = va_arg(ap, int);
4040231200Smm		archive_string_sprintf(info, "%c%s=%x",
4041231200Smm		    prefix, key, d);
4042231200Smm		break;
4043231200Smm	}
4044231200Smm	va_end(ap);
4045231200Smm
4046231200Smm	*opt = 1;
4047231200Smm}
4048231200Smm
4049231200Smm/*
4050231200Smm * Make Non-ISO File System Information
4051231200Smm */
4052231200Smmstatic int
4053231200Smmwrite_information_block(struct archive_write *a)
4054231200Smm{
4055231200Smm	struct iso9660 *iso9660;
4056231200Smm	char buf[128];
4057231200Smm	const char *v;
4058231200Smm	int opt, r;
4059231200Smm	struct archive_string info;
4060231200Smm	size_t info_size = LOGICAL_BLOCK_SIZE *
4061231200Smm			       NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
4062231200Smm
4063231200Smm	iso9660 = (struct iso9660 *)a->format_data;
4064231200Smm	if (info_size > wb_remaining(a)) {
4065231200Smm		r = wb_write_out(a);
4066231200Smm		if (r != ARCHIVE_OK)
4067231200Smm			return (r);
4068231200Smm	}
4069231200Smm	archive_string_init(&info);
4070231200Smm	if (archive_string_ensure(&info, info_size) == NULL) {
4071231200Smm		archive_set_error(&a->archive, ENOMEM,
4072231200Smm		    "Can't allocate memory");
4073231200Smm		return (ARCHIVE_FATAL);
4074231200Smm	}
4075231200Smm	memset(info.s, 0, info_size);
4076231200Smm	opt = 0;
4077231200Smm#if defined(HAVE__CTIME64_S)
4078315433Smm	{
4079315433Smm		__time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
4080315433Smm		_ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
4081315433Smm	}
4082231200Smm#elif defined(HAVE_CTIME_R)
4083231200Smm	ctime_r(&(iso9660->birth_time), buf);
4084231200Smm#else
4085231200Smm	strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);
4086231200Smm	buf[sizeof(buf)-1] = '\0';
4087231200Smm#endif
4088231200Smm	archive_string_sprintf(&info,
4089231200Smm	    "INFO %s%s", buf, archive_version_string());
4090231200Smm	if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)
4091231200Smm		set_option_info(&info, &opt, "abstract-file",
4092231200Smm		    KEY_STR, iso9660->abstract_file_identifier.s);
4093231200Smm	if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)
4094231200Smm		set_option_info(&info, &opt, "application-id",
4095231200Smm		    KEY_STR, iso9660->application_identifier.s);
4096231200Smm	if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)
4097231200Smm		set_option_info(&info, &opt, "allow-vernum",
4098231200Smm		    KEY_FLG, iso9660->opt.allow_vernum);
4099231200Smm	if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)
4100231200Smm		set_option_info(&info, &opt, "biblio-file",
4101231200Smm		    KEY_STR, iso9660->bibliographic_file_identifier.s);
4102231200Smm	if (iso9660->opt.boot != OPT_BOOT_DEFAULT)
4103231200Smm		set_option_info(&info, &opt, "boot",
4104231200Smm		    KEY_STR, iso9660->el_torito.boot_filename.s);
4105231200Smm	if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)
4106231200Smm		set_option_info(&info, &opt, "boot-catalog",
4107231200Smm		    KEY_STR, iso9660->el_torito.catalog_filename.s);
4108231200Smm	if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)
4109231200Smm		set_option_info(&info, &opt, "boot-info-table",
4110231200Smm		    KEY_FLG, iso9660->opt.boot_info_table);
4111231200Smm	if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)
4112231200Smm		set_option_info(&info, &opt, "boot-load-seg",
4113231200Smm		    KEY_HEX, iso9660->el_torito.boot_load_seg);
4114231200Smm	if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)
4115231200Smm		set_option_info(&info, &opt, "boot-load-size",
4116231200Smm		    KEY_INT, iso9660->el_torito.boot_load_size);
4117231200Smm	if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {
4118231200Smm		v = "no-emulation";
4119231200Smm		if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)
4120231200Smm			v = "fd";
4121231200Smm		if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)
4122231200Smm			v = "hard-disk";
4123231200Smm		set_option_info(&info, &opt, "boot-type",
4124231200Smm		    KEY_STR, v);
4125231200Smm	}
4126231200Smm#ifdef HAVE_ZLIB_H
4127231200Smm	if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)
4128231200Smm		set_option_info(&info, &opt, "compression-level",
4129231200Smm		    KEY_INT, iso9660->zisofs.compression_level);
4130231200Smm#endif
4131231200Smm	if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)
4132231200Smm		set_option_info(&info, &opt, "copyright-file",
4133231200Smm		    KEY_STR, iso9660->copyright_file_identifier.s);
4134231200Smm	if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)
4135231200Smm		set_option_info(&info, &opt, "iso-level",
4136231200Smm		    KEY_INT, iso9660->opt.iso_level);
4137231200Smm	if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {
4138231200Smm		if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
4139231200Smm			set_option_info(&info, &opt, "joliet",
4140231200Smm			    KEY_STR, "long");
4141231200Smm		else
4142231200Smm			set_option_info(&info, &opt, "joliet",
4143231200Smm			    KEY_FLG, iso9660->opt.joliet);
4144231200Smm	}
4145231200Smm	if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)
4146231200Smm		set_option_info(&info, &opt, "limit-depth",
4147231200Smm		    KEY_FLG, iso9660->opt.limit_depth);
4148231200Smm	if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)
4149231200Smm		set_option_info(&info, &opt, "limit-dirs",
4150231200Smm		    KEY_FLG, iso9660->opt.limit_dirs);
4151231200Smm	if (iso9660->opt.pad != OPT_PAD_DEFAULT)
4152231200Smm		set_option_info(&info, &opt, "pad",
4153231200Smm		    KEY_FLG, iso9660->opt.pad);
4154231200Smm	if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)
4155231200Smm		set_option_info(&info, &opt, "publisher",
4156231200Smm		    KEY_STR, iso9660->publisher_identifier.s);
4157231200Smm	if (iso9660->opt.rr != OPT_RR_DEFAULT) {
4158231200Smm		if (iso9660->opt.rr == OPT_RR_DISABLED)
4159231200Smm			set_option_info(&info, &opt, "rockridge",
4160231200Smm			    KEY_FLG, iso9660->opt.rr);
4161231200Smm		else if (iso9660->opt.rr == OPT_RR_STRICT)
4162231200Smm			set_option_info(&info, &opt, "rockridge",
4163231200Smm			    KEY_STR, "strict");
4164231200Smm		else if (iso9660->opt.rr == OPT_RR_USEFUL)
4165231200Smm			set_option_info(&info, &opt, "rockridge",
4166231200Smm			    KEY_STR, "useful");
4167231200Smm	}
4168231200Smm	if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)
4169231200Smm		set_option_info(&info, &opt, "volume-id",
4170231200Smm		    KEY_STR, iso9660->volume_identifier.s);
4171231200Smm	if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)
4172231200Smm		set_option_info(&info, &opt, "zisofs",
4173231200Smm		    KEY_FLG, iso9660->opt.zisofs);
4174231200Smm
4175231200Smm	memcpy(wb_buffptr(a), info.s, info_size);
4176231200Smm	archive_string_free(&info);
4177231200Smm	return (wb_consume(a, info_size));
4178231200Smm}
4179231200Smm
4180231200Smmstatic int
4181231200Smmwrite_rr_ER(struct archive_write *a)
4182231200Smm{
4183231200Smm	unsigned char *p;
4184231200Smm
4185231200Smm	p = wb_buffptr(a);
4186231200Smm
4187231200Smm	memset(p, 0, LOGICAL_BLOCK_SIZE);
4188231200Smm	p[0] = 'E';
4189231200Smm	p[1] = 'R';
4190231200Smm	p[3] = 0x01;
4191231200Smm	p[2] = RRIP_ER_SIZE;
4192231200Smm	p[4] = RRIP_ER_ID_SIZE;
4193231200Smm	p[5] = RRIP_ER_DSC_SIZE;
4194231200Smm	p[6] = RRIP_ER_SRC_SIZE;
4195231200Smm	p[7] = 0x01;
4196231200Smm	memcpy(&p[8], rrip_identifier, p[4]);
4197231200Smm	memcpy(&p[8+p[4]], rrip_descriptor, p[5]);
4198231200Smm	memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);
4199231200Smm
4200231200Smm	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4201231200Smm}
4202231200Smm
4203231200Smmstatic void
4204231200Smmcalculate_path_table_size(struct vdd *vdd)
4205231200Smm{
4206231200Smm	int depth, size;
4207231200Smm	struct path_table *pt;
4208231200Smm
4209231200Smm	pt = vdd->pathtbl;
4210231200Smm	size = 0;
4211231200Smm	for (depth = 0; depth < vdd->max_depth; depth++) {
4212231200Smm		struct isoent **ptbl;
4213231200Smm		int i, cnt;
4214231200Smm
4215231200Smm		if ((cnt = pt[depth].cnt) == 0)
4216231200Smm			break;
4217231200Smm
4218231200Smm		ptbl = pt[depth].sorted;
4219231200Smm		for (i = 0; i < cnt; i++) {
4220231200Smm			int len;
4221231200Smm
4222231200Smm			if (ptbl[i]->identifier == NULL)
4223231200Smm				len = 1; /* root directory */
4224231200Smm			else
4225231200Smm				len = ptbl[i]->id_len;
4226231200Smm			if (len & 0x01)
4227231200Smm				len++; /* Padding Field */
4228231200Smm			size += 8 + len;
4229231200Smm		}
4230231200Smm	}
4231231200Smm	vdd->path_table_size = size;
4232231200Smm	vdd->path_table_block =
4233231200Smm	    ((size + PATH_TABLE_BLOCK_SIZE -1) /
4234231200Smm	    PATH_TABLE_BLOCK_SIZE) *
4235231200Smm	    (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);
4236231200Smm}
4237231200Smm
4238231200Smmstatic int
4239231200Smm_write_path_table(struct archive_write *a, int type_m, int depth,
4240231200Smm    struct vdd *vdd)
4241231200Smm{
4242231200Smm	unsigned char *bp, *wb;
4243231200Smm	struct isoent **ptbl;
4244231200Smm	size_t wbremaining;
4245231200Smm	int i, r, wsize;
4246231200Smm
4247231200Smm	if (vdd->pathtbl[depth].cnt == 0)
4248231200Smm		return (0);
4249231200Smm
4250231200Smm	wsize = 0;
4251231200Smm	wb = wb_buffptr(a);
4252231200Smm	wbremaining = wb_remaining(a);
4253231200Smm	bp = wb - 1;
4254231200Smm	ptbl = vdd->pathtbl[depth].sorted;
4255231200Smm	for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {
4256231200Smm		struct isoent *np;
4257231200Smm		size_t len;
4258231200Smm
4259231200Smm		np = ptbl[i];
4260231200Smm		if (np->identifier == NULL)
4261231200Smm			len = 1; /* root directory */
4262231200Smm		else
4263231200Smm			len = np->id_len;
4264231200Smm		if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {
4265231200Smm			r = wb_consume(a, (bp+1) - wb);
4266231200Smm			if (r < 0)
4267231200Smm				return (r);
4268231200Smm			wb = wb_buffptr(a);
4269231200Smm			wbremaining = wb_remaining(a);
4270231200Smm			bp = wb -1;
4271231200Smm		}
4272231200Smm		/* Length of Directory Identifier */
4273248616Smm		set_num_711(bp+1, (unsigned char)len);
4274231200Smm		/* Extended Attribute Record Length */
4275231200Smm		set_num_711(bp+2, 0);
4276231200Smm		/* Location of Extent */
4277231200Smm		if (type_m)
4278231200Smm			set_num_732(bp+3, np->dir_location);
4279231200Smm		else
4280231200Smm			set_num_731(bp+3, np->dir_location);
4281231200Smm		/* Parent Directory Number */
4282231200Smm		if (type_m)
4283231200Smm			set_num_722(bp+7, np->parent->dir_number);
4284231200Smm		else
4285231200Smm			set_num_721(bp+7, np->parent->dir_number);
4286231200Smm		/* Directory Identifier */
4287231200Smm		if (np->identifier == NULL)
4288231200Smm			bp[9] = 0;
4289231200Smm		else
4290231200Smm			memcpy(&bp[9], np->identifier, len);
4291231200Smm		if (len & 0x01) {
4292231200Smm			/* Padding Field */
4293231200Smm			bp[9+len] = 0;
4294231200Smm			len++;
4295231200Smm		}
4296248616Smm		wsize += 8 + (int)len;
4297231200Smm		bp += 8 + len;
4298231200Smm	}
4299231200Smm	if ((bp + 1) > wb) {
4300231200Smm		r = wb_consume(a, (bp+1)-wb);
4301231200Smm		if (r < 0)
4302231200Smm			return (r);
4303231200Smm	}
4304231200Smm	return (wsize);
4305231200Smm}
4306231200Smm
4307231200Smmstatic int
4308231200Smmwrite_path_table(struct archive_write *a, int type_m, struct vdd *vdd)
4309231200Smm{
4310231200Smm	int depth, r;
4311231200Smm	size_t path_table_size;
4312231200Smm
4313231200Smm	r = ARCHIVE_OK;
4314231200Smm	path_table_size = 0;
4315231200Smm	for (depth = 0; depth < vdd->max_depth; depth++) {
4316231200Smm		r = _write_path_table(a, type_m, depth, vdd);
4317231200Smm		if (r < 0)
4318231200Smm			return (r);
4319231200Smm		path_table_size += r;
4320231200Smm	}
4321231200Smm
4322231200Smm	/* Write padding data. */
4323231200Smm	path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;
4324231200Smm	if (path_table_size > 0)
4325231200Smm		r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);
4326231200Smm	return (r);
4327231200Smm}
4328231200Smm
4329231200Smmstatic int
4330231200Smmcalculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,
4331231200Smm    struct isoent *isoent, int depth)
4332231200Smm{
4333231200Smm	struct isoent **enttbl;
4334231200Smm	int bs, block, i;
4335231200Smm
4336231200Smm	block = 1;
4337231200Smm	bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);
4338231200Smm	bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);
4339231200Smm
4340231200Smm	if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
4341231200Smm	    !iso9660->opt.rr && depth + 1 >= vdd->max_depth))
4342231200Smm		return (block);
4343231200Smm
4344231200Smm	enttbl = isoent->children_sorted;
4345231200Smm	for (i = 0; i < isoent->children.cnt; i++) {
4346231200Smm		struct isoent *np = enttbl[i];
4347231200Smm		struct isofile *file;
4348231200Smm
4349231200Smm		file = np->file;
4350231200Smm		if (file->hardlink_target != NULL)
4351231200Smm			file = file->hardlink_target;
4352231200Smm		file->cur_content = &(file->content);
4353231200Smm		do {
4354231200Smm			int dr_l;
4355231200Smm
4356231200Smm			dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,
4357231200Smm			    vdd->vdd_type);
4358231200Smm			if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {
4359231200Smm				block ++;
4360231200Smm				bs = dr_l;
4361231200Smm			} else
4362231200Smm				bs += dr_l;
4363231200Smm			file->cur_content = file->cur_content->next;
4364231200Smm		} while (file->cur_content != NULL);
4365231200Smm	}
4366231200Smm	return (block);
4367231200Smm}
4368231200Smm
4369231200Smmstatic int
4370231200Smm_write_directory_descriptors(struct archive_write *a, struct vdd *vdd,
4371231200Smm    struct isoent *isoent, int depth)
4372231200Smm{
4373231200Smm	struct iso9660 *iso9660 = a->format_data;
4374231200Smm	struct isoent **enttbl;
4375231200Smm	unsigned char *p, *wb;
4376231200Smm	int i, r;
4377231200Smm	int dr_l;
4378231200Smm
4379231200Smm	p = wb = wb_buffptr(a);
4380231200Smm#define WD_REMAINING	(LOGICAL_BLOCK_SIZE - (p - wb))
4381231200Smm	p += set_directory_record(p, WD_REMAINING, isoent,
4382231200Smm	    iso9660, DIR_REC_SELF, vdd->vdd_type);
4383231200Smm	p += set_directory_record(p, WD_REMAINING, isoent,
4384231200Smm	    iso9660, DIR_REC_PARENT, vdd->vdd_type);
4385231200Smm
4386231200Smm	if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
4387231200Smm	    !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {
4388231200Smm		memset(p, 0, WD_REMAINING);
4389231200Smm		return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4390231200Smm	}
4391231200Smm
4392231200Smm	enttbl = isoent->children_sorted;
4393231200Smm	for (i = 0; i < isoent->children.cnt; i++) {
4394231200Smm		struct isoent *np = enttbl[i];
4395231200Smm		struct isofile *file = np->file;
4396231200Smm
4397231200Smm		if (file->hardlink_target != NULL)
4398231200Smm			file = file->hardlink_target;
4399231200Smm		file->cur_content = &(file->content);
4400231200Smm		do {
4401231200Smm			dr_l = set_directory_record(p, WD_REMAINING,
4402231200Smm			    np, iso9660, DIR_REC_NORMAL,
4403231200Smm			    vdd->vdd_type);
4404231200Smm			if (dr_l == 0) {
4405231200Smm				memset(p, 0, WD_REMAINING);
4406231200Smm				r = wb_consume(a, LOGICAL_BLOCK_SIZE);
4407231200Smm				if (r < 0)
4408231200Smm					return (r);
4409231200Smm				p = wb = wb_buffptr(a);
4410231200Smm				dr_l = set_directory_record(p,
4411231200Smm				    WD_REMAINING, np, iso9660,
4412231200Smm				    DIR_REC_NORMAL, vdd->vdd_type);
4413231200Smm			}
4414231200Smm			p += dr_l;
4415231200Smm			file->cur_content = file->cur_content->next;
4416231200Smm		} while (file->cur_content != NULL);
4417231200Smm	}
4418231200Smm	memset(p, 0, WD_REMAINING);
4419231200Smm	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4420231200Smm}
4421231200Smm
4422231200Smmstatic int
4423231200Smmwrite_directory_descriptors(struct archive_write *a, struct vdd *vdd)
4424231200Smm{
4425231200Smm	struct isoent *np;
4426231200Smm	int depth, r;
4427231200Smm
4428231200Smm	depth = 0;
4429231200Smm	np = vdd->rootent;
4430231200Smm	do {
4431231200Smm		struct extr_rec *extr;
4432231200Smm
4433231200Smm		r = _write_directory_descriptors(a, vdd, np, depth);
4434231200Smm		if (r < 0)
4435231200Smm			return (r);
4436231200Smm		if (vdd->vdd_type != VDD_JOLIET) {
4437231200Smm			/*
4438231200Smm			 * This extract record is used by SUSP,RRIP.
4439231200Smm			 * Not for joliet.
4440231200Smm			 */
4441231200Smm			for (extr = np->extr_rec_list.first;
4442231200Smm			    extr != NULL;
4443231200Smm			    extr = extr->next) {
4444231200Smm				unsigned char *wb;
4445231200Smm
4446231200Smm				wb = wb_buffptr(a);
4447231200Smm				memcpy(wb, extr->buf, extr->offset);
4448231200Smm				memset(wb + extr->offset, 0,
4449231200Smm				    LOGICAL_BLOCK_SIZE - extr->offset);
4450231200Smm				r = wb_consume(a, LOGICAL_BLOCK_SIZE);
4451231200Smm				if (r < 0)
4452231200Smm					return (r);
4453231200Smm			}
4454231200Smm		}
4455231200Smm
4456231200Smm		if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
4457231200Smm			/* Enter to sub directories. */
4458231200Smm			np = np->subdirs.first;
4459231200Smm			depth++;
4460231200Smm			continue;
4461231200Smm		}
4462231200Smm		while (np != np->parent) {
4463231200Smm			if (np->drnext == NULL) {
4464231200Smm				/* Return to the parent directory. */
4465231200Smm				np = np->parent;
4466231200Smm				depth--;
4467231200Smm			} else {
4468231200Smm				np = np->drnext;
4469231200Smm				break;
4470231200Smm			}
4471231200Smm		}
4472231200Smm	} while (np != np->parent);
4473231200Smm
4474231200Smm	return (ARCHIVE_OK);
4475231200Smm}
4476231200Smm
4477231200Smm/*
4478231200Smm * Read file contents from the temporary file, and write it.
4479231200Smm */
4480231200Smmstatic int
4481231200Smmwrite_file_contents(struct archive_write *a, int64_t offset, int64_t size)
4482231200Smm{
4483231200Smm	struct iso9660 *iso9660 = a->format_data;
4484231200Smm	int r;
4485231200Smm
4486231200Smm	lseek(iso9660->temp_fd, offset, SEEK_SET);
4487231200Smm
4488231200Smm	while (size) {
4489231200Smm		size_t rsize;
4490231200Smm		ssize_t rs;
4491231200Smm		unsigned char *wb;
4492231200Smm
4493231200Smm		wb = wb_buffptr(a);
4494231200Smm		rsize = wb_remaining(a);
4495231200Smm		if (rsize > (size_t)size)
4496231200Smm			rsize = (size_t)size;
4497231200Smm		rs = read(iso9660->temp_fd, wb, rsize);
4498231200Smm		if (rs <= 0) {
4499231200Smm			archive_set_error(&a->archive, errno,
4500231200Smm			    "Can't read temporary file(%jd)", (intmax_t)rs);
4501231200Smm			return (ARCHIVE_FATAL);
4502231200Smm		}
4503231200Smm		size -= rs;
4504231200Smm		r = wb_consume(a, rs);
4505231200Smm		if (r < 0)
4506231200Smm			return (r);
4507231200Smm	}
4508231200Smm	return (ARCHIVE_OK);
4509231200Smm}
4510231200Smm
4511231200Smmstatic int
4512231200Smmwrite_file_descriptors(struct archive_write *a)
4513231200Smm{
4514231200Smm	struct iso9660 *iso9660 = a->format_data;
4515231200Smm	struct isofile *file;
4516231200Smm	int64_t blocks, offset;
4517231200Smm	int r;
4518231200Smm
4519231200Smm	blocks = 0;
4520231200Smm	offset = 0;
4521231200Smm
4522231200Smm	/* Make the boot catalog contents, and write it. */
4523231200Smm	if (iso9660->el_torito.catalog != NULL) {
4524231200Smm		r = make_boot_catalog(a);
4525231200Smm		if (r < 0)
4526231200Smm			return (r);
4527231200Smm	}
4528231200Smm
4529231200Smm	/* Write the boot file contents. */
4530231200Smm	if (iso9660->el_torito.boot != NULL) {
4531232153Smm		file = iso9660->el_torito.boot->file;
4532231200Smm		blocks = file->content.blocks;
4533231200Smm		offset = file->content.offset_of_temp;
4534231200Smm		if (offset != 0) {
4535231200Smm			r = write_file_contents(a, offset,
4536231200Smm			    blocks << LOGICAL_BLOCK_BITS);
4537231200Smm			if (r < 0)
4538231200Smm				return (r);
4539231200Smm			blocks = 0;
4540231200Smm			offset = 0;
4541231200Smm		}
4542231200Smm	}
4543231200Smm
4544231200Smm	/* Write out all file contents. */
4545231200Smm	for (file = iso9660->data_file_list.first;
4546231200Smm	    file != NULL; file = file->datanext) {
4547231200Smm
4548231200Smm		if (!file->write_content)
4549231200Smm			continue;
4550231200Smm
4551231200Smm		if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <
4552231200Smm		     file->content.offset_of_temp) {
4553231200Smm			if (blocks > 0) {
4554231200Smm				r = write_file_contents(a, offset,
4555231200Smm				    blocks << LOGICAL_BLOCK_BITS);
4556231200Smm				if (r < 0)
4557231200Smm					return (r);
4558231200Smm			}
4559231200Smm			blocks = 0;
4560231200Smm			offset = file->content.offset_of_temp;
4561231200Smm		}
4562231200Smm
4563231200Smm		file->cur_content = &(file->content);
4564231200Smm		do {
4565231200Smm			blocks += file->cur_content->blocks;
4566311042Smm			/* Next fragment */
4567231200Smm			file->cur_content = file->cur_content->next;
4568231200Smm		} while (file->cur_content != NULL);
4569231200Smm	}
4570231200Smm
4571231200Smm	/* Flush out remaining blocks. */
4572231200Smm	if (blocks > 0) {
4573231200Smm		r = write_file_contents(a, offset,
4574231200Smm		    blocks << LOGICAL_BLOCK_BITS);
4575231200Smm		if (r < 0)
4576231200Smm			return (r);
4577231200Smm	}
4578231200Smm
4579231200Smm	return (ARCHIVE_OK);
4580231200Smm}
4581231200Smm
4582231200Smmstatic void
4583231200Smmisofile_init_entry_list(struct iso9660 *iso9660)
4584231200Smm{
4585231200Smm	iso9660->all_file_list.first = NULL;
4586231200Smm	iso9660->all_file_list.last = &(iso9660->all_file_list.first);
4587231200Smm}
4588231200Smm
4589231200Smmstatic void
4590231200Smmisofile_add_entry(struct iso9660 *iso9660, struct isofile *file)
4591231200Smm{
4592231200Smm	file->allnext = NULL;
4593231200Smm	*iso9660->all_file_list.last = file;
4594231200Smm	iso9660->all_file_list.last = &(file->allnext);
4595231200Smm}
4596231200Smm
4597231200Smmstatic void
4598231200Smmisofile_free_all_entries(struct iso9660 *iso9660)
4599231200Smm{
4600231200Smm	struct isofile *file, *file_next;
4601231200Smm
4602231200Smm	file = iso9660->all_file_list.first;
4603231200Smm	while (file != NULL) {
4604231200Smm		file_next = file->allnext;
4605231200Smm		isofile_free(file);
4606231200Smm		file = file_next;
4607231200Smm	}
4608231200Smm}
4609231200Smm
4610231200Smmstatic void
4611231200Smmisofile_init_entry_data_file_list(struct iso9660 *iso9660)
4612231200Smm{
4613231200Smm	iso9660->data_file_list.first = NULL;
4614231200Smm	iso9660->data_file_list.last = &(iso9660->data_file_list.first);
4615231200Smm}
4616231200Smm
4617231200Smmstatic void
4618231200Smmisofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)
4619231200Smm{
4620231200Smm	file->datanext = NULL;
4621231200Smm	*iso9660->data_file_list.last = file;
4622231200Smm	iso9660->data_file_list.last = &(file->datanext);
4623231200Smm}
4624231200Smm
4625231200Smm
4626231200Smmstatic struct isofile *
4627231200Smmisofile_new(struct archive_write *a, struct archive_entry *entry)
4628231200Smm{
4629231200Smm	struct isofile *file;
4630231200Smm
4631231200Smm	file = calloc(1, sizeof(*file));
4632231200Smm	if (file == NULL)
4633231200Smm		return (NULL);
4634231200Smm
4635231200Smm	if (entry != NULL)
4636231200Smm		file->entry = archive_entry_clone(entry);
4637231200Smm	else
4638231200Smm		file->entry = archive_entry_new2(&a->archive);
4639231200Smm	if (file->entry == NULL) {
4640231200Smm		free(file);
4641231200Smm		return (NULL);
4642231200Smm	}
4643231200Smm	archive_string_init(&(file->parentdir));
4644231200Smm	archive_string_init(&(file->basename));
4645231200Smm	archive_string_init(&(file->basename_utf16));
4646231200Smm	archive_string_init(&(file->symlink));
4647231200Smm	file->cur_content = &(file->content);
4648231200Smm
4649231200Smm	return (file);
4650231200Smm}
4651231200Smm
4652231200Smmstatic void
4653231200Smmisofile_free(struct isofile *file)
4654231200Smm{
4655231200Smm	struct content *con, *tmp;
4656231200Smm
4657231200Smm	con = file->content.next;
4658231200Smm	while (con != NULL) {
4659231200Smm		tmp = con;
4660231200Smm		con = con->next;
4661231200Smm		free(tmp);
4662231200Smm	}
4663231200Smm	archive_entry_free(file->entry);
4664231200Smm	archive_string_free(&(file->parentdir));
4665231200Smm	archive_string_free(&(file->basename));
4666231200Smm	archive_string_free(&(file->basename_utf16));
4667231200Smm	archive_string_free(&(file->symlink));
4668231200Smm	free(file);
4669231200Smm}
4670231200Smm
4671231200Smm#if defined(_WIN32) || defined(__CYGWIN__)
4672231200Smmstatic int
4673231200Smmcleanup_backslash_1(char *p)
4674231200Smm{
4675231200Smm	int mb, dos;
4676231200Smm
4677231200Smm	mb = dos = 0;
4678231200Smm	while (*p) {
4679231200Smm		if (*(unsigned char *)p > 127)
4680231200Smm			mb = 1;
4681231200Smm		if (*p == '\\') {
4682231200Smm			/* If we have not met any multi-byte characters,
4683231200Smm			 * we can replace '\' with '/'. */
4684231200Smm			if (!mb)
4685231200Smm				*p = '/';
4686231200Smm			dos = 1;
4687231200Smm		}
4688231200Smm		p++;
4689231200Smm	}
4690231200Smm	if (!mb || !dos)
4691231200Smm		return (0);
4692231200Smm	return (-1);
4693231200Smm}
4694231200Smm
4695231200Smmstatic void
4696231200Smmcleanup_backslash_2(wchar_t *p)
4697231200Smm{
4698231200Smm
4699231200Smm	/* Convert a path-separator from '\' to  '/' */
4700231200Smm	while (*p != L'\0') {
4701231200Smm		if (*p == L'\\')
4702231200Smm			*p = L'/';
4703231200Smm		p++;
4704231200Smm	}
4705231200Smm}
4706231200Smm#endif
4707231200Smm
4708231200Smm/*
4709231200Smm * Generate a parent directory name and a base name from a pathname.
4710231200Smm */
4711231200Smmstatic int
4712231200Smmisofile_gen_utility_names(struct archive_write *a, struct isofile *file)
4713231200Smm{
4714231200Smm	struct iso9660 *iso9660;
4715231200Smm	const char *pathname;
4716231200Smm	char *p, *dirname, *slash;
4717231200Smm	size_t len;
4718231200Smm	int ret = ARCHIVE_OK;
4719231200Smm
4720231200Smm	iso9660 = a->format_data;
4721231200Smm
4722231200Smm	archive_string_empty(&(file->parentdir));
4723231200Smm	archive_string_empty(&(file->basename));
4724231200Smm	archive_string_empty(&(file->basename_utf16));
4725231200Smm	archive_string_empty(&(file->symlink));
4726231200Smm
4727231200Smm	pathname =  archive_entry_pathname(file->entry);
4728231200Smm	if (pathname == NULL || pathname[0] == '\0') {/* virtual root */
4729231200Smm		file->dircnt = 0;
4730231200Smm		return (ret);
4731231200Smm	}
4732231200Smm
4733231200Smm	/*
4734231200Smm	 * Make a UTF-16BE basename if Joliet extension enabled.
4735231200Smm	 */
4736231200Smm	if (iso9660->opt.joliet) {
4737231200Smm		const char *u16, *ulast;
4738231200Smm		size_t u16len, ulen_last;
4739231200Smm
4740231200Smm		if (iso9660->sconv_to_utf16be == NULL) {
4741231200Smm			iso9660->sconv_to_utf16be =
4742231200Smm			    archive_string_conversion_to_charset(
4743231200Smm				&(a->archive), "UTF-16BE", 1);
4744231200Smm			if (iso9660->sconv_to_utf16be == NULL)
4745231200Smm				/* Couldn't allocate memory */
4746231200Smm				return (ARCHIVE_FATAL);
4747231200Smm			iso9660->sconv_from_utf16be =
4748231200Smm			    archive_string_conversion_from_charset(
4749231200Smm				&(a->archive), "UTF-16BE", 1);
4750231200Smm			if (iso9660->sconv_from_utf16be == NULL)
4751231200Smm				/* Couldn't allocate memory */
4752231200Smm				return (ARCHIVE_FATAL);
4753231200Smm		}
4754231200Smm
4755231200Smm		/*
4756311042Smm		 * Convert a filename to UTF-16BE.
4757231200Smm		 */
4758231200Smm		if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
4759231200Smm		    iso9660->sconv_to_utf16be)) {
4760231200Smm			if (errno == ENOMEM) {
4761231200Smm				archive_set_error(&a->archive, ENOMEM,
4762231200Smm				    "Can't allocate memory for UTF-16BE");
4763231200Smm				return (ARCHIVE_FATAL);
4764231200Smm			}
4765231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4766231200Smm			    "A filename cannot be converted to UTF-16BE;"
4767231200Smm			    "You should disable making Joliet extension");
4768231200Smm			ret = ARCHIVE_WARN;
4769231200Smm		}
4770231200Smm
4771231200Smm		/*
4772231200Smm		 * Make sure a path separator is not in the last;
4773231200Smm		 * Remove trailing '/'.
4774231200Smm		 */
4775231200Smm		while (u16len >= 2) {
4776231200Smm#if defined(_WIN32) || defined(__CYGWIN__)
4777231200Smm			if (u16[u16len-2] == 0 &&
4778231200Smm			    (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))
4779231200Smm#else
4780231200Smm			if (u16[u16len-2] == 0 && u16[u16len-1] == '/')
4781231200Smm#endif
4782231200Smm			{
4783231200Smm				u16len -= 2;
4784231200Smm			} else
4785231200Smm				break;
4786231200Smm		}
4787231200Smm
4788231200Smm		/*
4789231200Smm		 * Find a basename in UTF-16BE.
4790231200Smm		 */
4791231200Smm		ulast = u16;
4792231200Smm		u16len >>= 1;
4793231200Smm		ulen_last = u16len;
4794231200Smm		while (u16len > 0) {
4795231200Smm#if defined(_WIN32) || defined(__CYGWIN__)
4796231200Smm			if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))
4797231200Smm#else
4798231200Smm			if (u16[0] == 0 && u16[1] == '/')
4799231200Smm#endif
4800231200Smm			{
4801231200Smm				ulast = u16 + 2;
4802231200Smm				ulen_last = u16len -1;
4803231200Smm			}
4804231200Smm			u16 += 2;
4805231200Smm			u16len --;
4806231200Smm		}
4807231200Smm		ulen_last <<= 1;
4808231200Smm		if (archive_string_ensure(&(file->basename_utf16),
4809231200Smm		    ulen_last) == NULL) {
4810231200Smm			archive_set_error(&a->archive, ENOMEM,
4811231200Smm			    "Can't allocate memory for UTF-16BE");
4812231200Smm			return (ARCHIVE_FATAL);
4813231200Smm		}
4814231200Smm
4815231200Smm		/*
4816231200Smm		 * Set UTF-16BE basename.
4817231200Smm		 */
4818231200Smm		memcpy(file->basename_utf16.s, ulast, ulen_last);
4819231200Smm		file->basename_utf16.length = ulen_last;
4820231200Smm	}
4821231200Smm
4822231200Smm	archive_strcpy(&(file->parentdir), pathname);
4823231200Smm#if defined(_WIN32) || defined(__CYGWIN__)
4824231200Smm	/*
4825231200Smm	 * Convert a path-separator from '\' to  '/'
4826231200Smm	 */
4827231200Smm	if (cleanup_backslash_1(file->parentdir.s) != 0) {
4828231200Smm		const wchar_t *wp = archive_entry_pathname_w(file->entry);
4829231200Smm		struct archive_wstring ws;
4830231200Smm
4831231200Smm		if (wp != NULL) {
4832238856Smm			int r;
4833231200Smm			archive_string_init(&ws);
4834231200Smm			archive_wstrcpy(&ws, wp);
4835231200Smm			cleanup_backslash_2(ws.s);
4836231200Smm			archive_string_empty(&(file->parentdir));
4837238856Smm			r = archive_string_append_from_wcs(&(file->parentdir),
4838231200Smm			    ws.s, ws.length);
4839231200Smm			archive_wstring_free(&ws);
4840238856Smm			if (r < 0 && errno == ENOMEM) {
4841238856Smm				archive_set_error(&a->archive, ENOMEM,
4842238856Smm				    "Can't allocate memory");
4843238856Smm				return (ARCHIVE_FATAL);
4844238856Smm			}
4845231200Smm		}
4846231200Smm	}
4847231200Smm#endif
4848231200Smm
4849231200Smm	len = file->parentdir.length;
4850231200Smm	p = dirname = file->parentdir.s;
4851231200Smm
4852231200Smm	/*
4853231200Smm	 * Remove leading '/', '../' and './' elements
4854231200Smm	 */
4855231200Smm	while (*p) {
4856231200Smm		if (p[0] == '/') {
4857231200Smm			p++;
4858231200Smm			len--;
4859231200Smm		} else if (p[0] != '.')
4860231200Smm			break;
4861231200Smm		else if (p[1] == '.' && p[2] == '/') {
4862231200Smm			p += 3;
4863231200Smm			len -= 3;
4864231200Smm		} else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
4865231200Smm			p += 2;
4866231200Smm			len -= 2;
4867231200Smm		} else if (p[1] == '\0') {
4868231200Smm			p++;
4869231200Smm			len--;
4870231200Smm		} else
4871231200Smm			break;
4872231200Smm	}
4873231200Smm	if (p != dirname) {
4874231200Smm		memmove(dirname, p, len+1);
4875231200Smm		p = dirname;
4876231200Smm	}
4877231200Smm	/*
4878231200Smm	 * Remove "/","/." and "/.." elements from tail.
4879231200Smm	 */
4880231200Smm	while (len > 0) {
4881231200Smm		size_t ll = len;
4882231200Smm
4883231200Smm		if (len > 0 && p[len-1] == '/') {
4884231200Smm			p[len-1] = '\0';
4885231200Smm			len--;
4886231200Smm		}
4887231200Smm		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
4888231200Smm			p[len-2] = '\0';
4889231200Smm			len -= 2;
4890231200Smm		}
4891231200Smm		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
4892231200Smm		    p[len-1] == '.') {
4893231200Smm			p[len-3] = '\0';
4894231200Smm			len -= 3;
4895231200Smm		}
4896231200Smm		if (ll == len)
4897231200Smm			break;
4898231200Smm	}
4899231200Smm	while (*p) {
4900231200Smm		if (p[0] == '/') {
4901231200Smm			if (p[1] == '/')
4902231200Smm				/* Convert '//' --> '/' */
4903231200Smm				strcpy(p, p+1);
4904231200Smm			else if (p[1] == '.' && p[2] == '/')
4905231200Smm				/* Convert '/./' --> '/' */
4906231200Smm				strcpy(p, p+2);
4907231200Smm			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
4908231200Smm				/* Convert 'dir/dir1/../dir2/'
4909231200Smm				 *     --> 'dir/dir2/'
4910231200Smm				 */
4911231200Smm				char *rp = p -1;
4912231200Smm				while (rp >= dirname) {
4913231200Smm					if (*rp == '/')
4914231200Smm						break;
4915231200Smm					--rp;
4916231200Smm				}
4917231200Smm				if (rp > dirname) {
4918231200Smm					strcpy(rp, p+3);
4919231200Smm					p = rp;
4920231200Smm				} else {
4921231200Smm					strcpy(dirname, p+4);
4922231200Smm					p = dirname;
4923231200Smm				}
4924231200Smm			} else
4925231200Smm				p++;
4926231200Smm		} else
4927231200Smm			p++;
4928231200Smm	}
4929231200Smm	p = dirname;
4930231200Smm	len = strlen(p);
4931231200Smm
4932231200Smm	if (archive_entry_filetype(file->entry) == AE_IFLNK) {
4933231200Smm		/* Convert symlink name too. */
4934231200Smm		pathname = archive_entry_symlink(file->entry);
4935231200Smm		archive_strcpy(&(file->symlink),  pathname);
4936231200Smm#if defined(_WIN32) || defined(__CYGWIN__)
4937231200Smm		/*
4938231200Smm		 * Convert a path-separator from '\' to  '/'
4939231200Smm		 */
4940231200Smm		if (archive_strlen(&(file->symlink)) > 0 &&
4941231200Smm		    cleanup_backslash_1(file->symlink.s) != 0) {
4942231200Smm			const wchar_t *wp =
4943231200Smm			    archive_entry_symlink_w(file->entry);
4944231200Smm			struct archive_wstring ws;
4945231200Smm
4946231200Smm			if (wp != NULL) {
4947238856Smm				int r;
4948231200Smm				archive_string_init(&ws);
4949231200Smm				archive_wstrcpy(&ws, wp);
4950231200Smm				cleanup_backslash_2(ws.s);
4951231200Smm				archive_string_empty(&(file->symlink));
4952238856Smm				r = archive_string_append_from_wcs(
4953231200Smm				    &(file->symlink),
4954231200Smm				    ws.s, ws.length);
4955231200Smm				archive_wstring_free(&ws);
4956238856Smm				if (r < 0 && errno == ENOMEM) {
4957238856Smm					archive_set_error(&a->archive, ENOMEM,
4958238856Smm					    "Can't allocate memory");
4959238856Smm					return (ARCHIVE_FATAL);
4960238856Smm				}
4961231200Smm			}
4962231200Smm		}
4963231200Smm#endif
4964231200Smm	}
4965231200Smm	/*
4966231200Smm	 * - Count up directory elements.
4967231200Smm	 * - Find out the position which points the last position of
4968231200Smm	 *   path separator('/').
4969231200Smm	 */
4970231200Smm	slash = NULL;
4971231200Smm	file->dircnt = 0;
4972231200Smm	for (; *p != '\0'; p++)
4973231200Smm		if (*p == '/') {
4974231200Smm			slash = p;
4975231200Smm			file->dircnt++;
4976231200Smm		}
4977231200Smm	if (slash == NULL) {
4978231200Smm		/* The pathname doesn't have a parent directory. */
4979231200Smm		file->parentdir.length = len;
4980231200Smm		archive_string_copy(&(file->basename), &(file->parentdir));
4981231200Smm		archive_string_empty(&(file->parentdir));
4982231200Smm		*file->parentdir.s = '\0';
4983231200Smm		return (ret);
4984231200Smm	}
4985231200Smm
4986231200Smm	/* Make a basename from dirname and slash */
4987231200Smm	*slash  = '\0';
4988231200Smm	file->parentdir.length = slash - dirname;
4989231200Smm	archive_strcpy(&(file->basename),  slash + 1);
4990231200Smm	if (archive_entry_filetype(file->entry) == AE_IFDIR)
4991231200Smm		file->dircnt ++;
4992231200Smm	return (ret);
4993231200Smm}
4994231200Smm
4995231200Smm/*
4996231200Smm * Register a entry to get a hardlink target.
4997231200Smm */
4998231200Smmstatic int
4999231200Smmisofile_register_hardlink(struct archive_write *a, struct isofile *file)
5000231200Smm{
5001231200Smm	struct iso9660 *iso9660 = a->format_data;
5002231200Smm	struct hardlink *hl;
5003231200Smm	const char *pathname;
5004231200Smm
5005231200Smm	archive_entry_set_nlink(file->entry, 1);
5006231200Smm	pathname = archive_entry_hardlink(file->entry);
5007231200Smm	if (pathname == NULL) {
5008231200Smm		/* This `file` is a hardlink target. */
5009231200Smm		hl = malloc(sizeof(*hl));
5010231200Smm		if (hl == NULL) {
5011231200Smm			archive_set_error(&a->archive, ENOMEM,
5012231200Smm			    "Can't allocate memory");
5013231200Smm			return (ARCHIVE_FATAL);
5014231200Smm		}
5015231200Smm		hl->nlink = 1;
5016231200Smm		/* A hardlink target must be the first position. */
5017231200Smm		file->hlnext = NULL;
5018231200Smm		hl->file_list.first = file;
5019231200Smm		hl->file_list.last = &(file->hlnext);
5020231200Smm		__archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),
5021231200Smm		    (struct archive_rb_node *)hl);
5022231200Smm	} else {
5023231200Smm		hl = (struct hardlink *)__archive_rb_tree_find_node(
5024231200Smm		    &(iso9660->hardlink_rbtree), pathname);
5025231200Smm		if (hl != NULL) {
5026231200Smm			/* Insert `file` entry into the tail. */
5027231200Smm			file->hlnext = NULL;
5028231200Smm			*hl->file_list.last = file;
5029231200Smm			hl->file_list.last = &(file->hlnext);
5030231200Smm			hl->nlink++;
5031231200Smm		}
5032231200Smm		archive_entry_unset_size(file->entry);
5033231200Smm	}
5034231200Smm
5035231200Smm	return (ARCHIVE_OK);
5036231200Smm}
5037231200Smm
5038231200Smm/*
5039231200Smm * Hardlinked files have to have the same location of extent.
5040231200Smm * We have to find out hardlink target entries for the entries
5041231200Smm * which have a hardlink target name.
5042231200Smm */
5043231200Smmstatic void
5044231200Smmisofile_connect_hardlink_files(struct iso9660 *iso9660)
5045231200Smm{
5046231200Smm	struct archive_rb_node *n;
5047231200Smm	struct hardlink *hl;
5048231200Smm	struct isofile *target, *nf;
5049231200Smm
5050231200Smm	ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {
5051231200Smm		hl = (struct hardlink *)n;
5052231200Smm
5053231200Smm		/* The first entry must be a hardlink target. */
5054231200Smm		target = hl->file_list.first;
5055231200Smm		archive_entry_set_nlink(target->entry, hl->nlink);
5056231200Smm		/* Set a hardlink target to reference entries. */
5057231200Smm		for (nf = target->hlnext;
5058231200Smm		    nf != NULL; nf = nf->hlnext) {
5059231200Smm			nf->hardlink_target = target;
5060231200Smm			archive_entry_set_nlink(nf->entry, hl->nlink);
5061231200Smm		}
5062231200Smm	}
5063231200Smm}
5064231200Smm
5065231200Smmstatic int
5066231200Smmisofile_hd_cmp_node(const struct archive_rb_node *n1,
5067231200Smm    const struct archive_rb_node *n2)
5068231200Smm{
5069231200Smm	const struct hardlink *h1 = (const struct hardlink *)n1;
5070231200Smm	const struct hardlink *h2 = (const struct hardlink *)n2;
5071231200Smm
5072231200Smm	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
5073231200Smm		       archive_entry_pathname(h2->file_list.first->entry)));
5074231200Smm}
5075231200Smm
5076231200Smmstatic int
5077231200Smmisofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
5078231200Smm{
5079231200Smm	const struct hardlink *h = (const struct hardlink *)n;
5080231200Smm
5081231200Smm	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
5082231200Smm		       (const char *)key));
5083231200Smm}
5084231200Smm
5085231200Smmstatic void
5086231200Smmisofile_init_hardlinks(struct iso9660 *iso9660)
5087231200Smm{
5088231200Smm	static const struct archive_rb_tree_ops rb_ops = {
5089231200Smm		isofile_hd_cmp_node, isofile_hd_cmp_key,
5090231200Smm	};
5091231200Smm
5092231200Smm	__archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);
5093231200Smm}
5094231200Smm
5095231200Smmstatic void
5096231200Smmisofile_free_hardlinks(struct iso9660 *iso9660)
5097231200Smm{
5098358090Smm	struct archive_rb_node *n, *tmp;
5099231200Smm
5100358090Smm	ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(iso9660->hardlink_rbtree), tmp) {
5101358090Smm		__archive_rb_tree_remove_node(&(iso9660->hardlink_rbtree), n);
5102231200Smm		free(n);
5103231200Smm	}
5104231200Smm}
5105231200Smm
5106231200Smmstatic struct isoent *
5107231200Smmisoent_new(struct isofile *file)
5108231200Smm{
5109231200Smm	struct isoent *isoent;
5110231200Smm	static const struct archive_rb_tree_ops rb_ops = {
5111231200Smm		isoent_cmp_node, isoent_cmp_key,
5112231200Smm	};
5113231200Smm
5114231200Smm	isoent = calloc(1, sizeof(*isoent));
5115231200Smm	if (isoent == NULL)
5116231200Smm		return (NULL);
5117231200Smm	isoent->file = file;
5118231200Smm	isoent->children.first = NULL;
5119231200Smm	isoent->children.last = &(isoent->children.first);
5120231200Smm	__archive_rb_tree_init(&(isoent->rbtree), &rb_ops);
5121231200Smm	isoent->subdirs.first = NULL;
5122231200Smm	isoent->subdirs.last = &(isoent->subdirs.first);
5123231200Smm	isoent->extr_rec_list.first = NULL;
5124231200Smm	isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);
5125231200Smm	isoent->extr_rec_list.current = NULL;
5126231200Smm	if (archive_entry_filetype(file->entry) == AE_IFDIR)
5127231200Smm		isoent->dir = 1;
5128231200Smm
5129231200Smm	return (isoent);
5130231200Smm}
5131231200Smm
5132231200Smmstatic inline struct isoent *
5133231200Smmisoent_clone(struct isoent *src)
5134231200Smm{
5135231200Smm	return (isoent_new(src->file));
5136231200Smm}
5137231200Smm
5138231200Smmstatic void
5139231200Smm_isoent_free(struct isoent *isoent)
5140231200Smm{
5141231200Smm	struct extr_rec *er, *er_next;
5142231200Smm
5143231200Smm	free(isoent->children_sorted);
5144231200Smm	free(isoent->identifier);
5145231200Smm	er = isoent->extr_rec_list.first;
5146231200Smm	while (er != NULL) {
5147231200Smm		er_next = er->next;
5148231200Smm		free(er);
5149231200Smm		er = er_next;
5150231200Smm	}
5151231200Smm	free(isoent);
5152231200Smm}
5153231200Smm
5154231200Smmstatic void
5155231200Smmisoent_free_all(struct isoent *isoent)
5156231200Smm{
5157231200Smm	struct isoent *np, *np_temp;
5158231200Smm
5159231200Smm	if (isoent == NULL)
5160231200Smm		return;
5161231200Smm	np = isoent;
5162231200Smm	for (;;) {
5163231200Smm		if (np->dir) {
5164231200Smm			if (np->children.first != NULL) {
5165231200Smm				/* Enter to sub directories. */
5166231200Smm				np = np->children.first;
5167231200Smm				continue;
5168231200Smm			}
5169231200Smm		}
5170231200Smm		for (;;) {
5171231200Smm			np_temp = np;
5172231200Smm			if (np->chnext == NULL) {
5173231200Smm				/* Return to the parent directory. */
5174231200Smm				np = np->parent;
5175231200Smm				_isoent_free(np_temp);
5176231200Smm				if (np == np_temp)
5177231200Smm					return;
5178231200Smm			} else {
5179231200Smm				np = np->chnext;
5180231200Smm				_isoent_free(np_temp);
5181231200Smm				break;
5182231200Smm			}
5183231200Smm		}
5184231200Smm	}
5185231200Smm}
5186231200Smm
5187231200Smmstatic struct isoent *
5188231200Smmisoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)
5189231200Smm{
5190231200Smm	struct isofile *file;
5191231200Smm	struct isoent *isoent;
5192231200Smm
5193231200Smm	file = isofile_new(a, NULL);
5194231200Smm	if (file == NULL)
5195231200Smm		return (NULL);
5196231200Smm	archive_entry_set_pathname(file->entry, pathname);
5197231200Smm	archive_entry_unset_mtime(file->entry);
5198231200Smm	archive_entry_unset_atime(file->entry);
5199231200Smm	archive_entry_unset_ctime(file->entry);
5200231200Smm	archive_entry_set_uid(file->entry, getuid());
5201231200Smm	archive_entry_set_gid(file->entry, getgid());
5202231200Smm	archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
5203231200Smm	archive_entry_set_nlink(file->entry, 2);
5204231200Smm	if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
5205231200Smm		isofile_free(file);
5206231200Smm		return (NULL);
5207231200Smm	}
5208231200Smm	isofile_add_entry(iso9660, file);
5209231200Smm
5210231200Smm	isoent = isoent_new(file);
5211231200Smm	if (isoent == NULL)
5212231200Smm		return (NULL);
5213231200Smm	isoent->dir = 1;
5214231200Smm	isoent->virtual = 1;
5215231200Smm
5216231200Smm	return (isoent);
5217231200Smm}
5218231200Smm
5219231200Smmstatic int
5220231200Smmisoent_cmp_node(const struct archive_rb_node *n1,
5221231200Smm    const struct archive_rb_node *n2)
5222231200Smm{
5223231200Smm	const struct isoent *e1 = (const struct isoent *)n1;
5224231200Smm	const struct isoent *e2 = (const struct isoent *)n2;
5225231200Smm
5226231200Smm	return (strcmp(e1->file->basename.s, e2->file->basename.s));
5227231200Smm}
5228231200Smm
5229231200Smmstatic int
5230231200Smmisoent_cmp_key(const struct archive_rb_node *n, const void *key)
5231231200Smm{
5232231200Smm	const struct isoent *e = (const struct isoent *)n;
5233231200Smm
5234231200Smm	return (strcmp(e->file->basename.s, (const char *)key));
5235231200Smm}
5236231200Smm
5237231200Smmstatic int
5238231200Smmisoent_add_child_head(struct isoent *parent, struct isoent *child)
5239231200Smm{
5240231200Smm
5241231200Smm	if (!__archive_rb_tree_insert_node(
5242231200Smm	    &(parent->rbtree), (struct archive_rb_node *)child))
5243231200Smm		return (0);
5244231200Smm	if ((child->chnext = parent->children.first) == NULL)
5245231200Smm		parent->children.last = &(child->chnext);
5246231200Smm	parent->children.first = child;
5247231200Smm	parent->children.cnt++;
5248231200Smm	child->parent = parent;
5249231200Smm
5250231200Smm	/* Add a child to a sub-directory chain */
5251231200Smm	if (child->dir) {
5252231200Smm		if ((child->drnext = parent->subdirs.first) == NULL)
5253231200Smm			parent->subdirs.last = &(child->drnext);
5254231200Smm		parent->subdirs.first = child;
5255231200Smm		parent->subdirs.cnt++;
5256231200Smm		child->parent = parent;
5257231200Smm	} else
5258231200Smm		child->drnext = NULL;
5259231200Smm	return (1);
5260231200Smm}
5261231200Smm
5262231200Smmstatic int
5263231200Smmisoent_add_child_tail(struct isoent *parent, struct isoent *child)
5264231200Smm{
5265231200Smm
5266231200Smm	if (!__archive_rb_tree_insert_node(
5267231200Smm	    &(parent->rbtree), (struct archive_rb_node *)child))
5268231200Smm		return (0);
5269231200Smm	child->chnext = NULL;
5270231200Smm	*parent->children.last = child;
5271231200Smm	parent->children.last = &(child->chnext);
5272231200Smm	parent->children.cnt++;
5273231200Smm	child->parent = parent;
5274231200Smm
5275231200Smm	/* Add a child to a sub-directory chain */
5276231200Smm	child->drnext = NULL;
5277231200Smm	if (child->dir) {
5278231200Smm		*parent->subdirs.last = child;
5279231200Smm		parent->subdirs.last = &(child->drnext);
5280231200Smm		parent->subdirs.cnt++;
5281231200Smm		child->parent = parent;
5282231200Smm	}
5283231200Smm	return (1);
5284231200Smm}
5285231200Smm
5286231200Smmstatic void
5287231200Smmisoent_remove_child(struct isoent *parent, struct isoent *child)
5288231200Smm{
5289231200Smm	struct isoent *ent;
5290231200Smm
5291231200Smm	/* Remove a child entry from children chain. */
5292231200Smm	ent = parent->children.first;
5293231200Smm	while (ent->chnext != child)
5294231200Smm		ent = ent->chnext;
5295231200Smm	if ((ent->chnext = ent->chnext->chnext) == NULL)
5296231200Smm		parent->children.last = &(ent->chnext);
5297231200Smm	parent->children.cnt--;
5298231200Smm
5299231200Smm	if (child->dir) {
5300231200Smm		/* Remove a child entry from sub-directory chain. */
5301231200Smm		ent = parent->subdirs.first;
5302231200Smm		while (ent->drnext != child)
5303231200Smm			ent = ent->drnext;
5304231200Smm		if ((ent->drnext = ent->drnext->drnext) == NULL)
5305231200Smm			parent->subdirs.last = &(ent->drnext);
5306231200Smm		parent->subdirs.cnt--;
5307231200Smm	}
5308231200Smm
5309231200Smm	__archive_rb_tree_remove_node(&(parent->rbtree),
5310231200Smm	    (struct archive_rb_node *)child);
5311231200Smm}
5312231200Smm
5313231200Smmstatic int
5314231200Smmisoent_clone_tree(struct archive_write *a, struct isoent **nroot,
5315231200Smm    struct isoent *root)
5316231200Smm{
5317231200Smm	struct isoent *np, *xroot, *newent;
5318231200Smm
5319231200Smm	np = root;
5320231200Smm	xroot = NULL;
5321231200Smm	do {
5322231200Smm		newent = isoent_clone(np);
5323231200Smm		if (newent == NULL) {
5324231200Smm			archive_set_error(&a->archive, ENOMEM,
5325231200Smm			    "Can't allocate memory");
5326231200Smm			return (ARCHIVE_FATAL);
5327231200Smm		}
5328231200Smm		if (xroot == NULL) {
5329231200Smm			*nroot = xroot = newent;
5330231200Smm			newent->parent = xroot;
5331231200Smm		} else
5332231200Smm			isoent_add_child_tail(xroot, newent);
5333231200Smm		if (np->dir && np->children.first != NULL) {
5334231200Smm			/* Enter to sub directories. */
5335231200Smm			np = np->children.first;
5336231200Smm			xroot = newent;
5337231200Smm			continue;
5338231200Smm		}
5339231200Smm		while (np != np->parent) {
5340231200Smm			if (np->chnext == NULL) {
5341231200Smm				/* Return to the parent directory. */
5342231200Smm				np = np->parent;
5343231200Smm				xroot = xroot->parent;
5344231200Smm			} else {
5345231200Smm				np = np->chnext;
5346231200Smm				break;
5347231200Smm			}
5348231200Smm		}
5349231200Smm	} while (np != np->parent);
5350231200Smm
5351231200Smm	return (ARCHIVE_OK);
5352231200Smm}
5353231200Smm
5354231200Smm/*
5355231200Smm * Setup directory locations.
5356231200Smm */
5357231200Smmstatic void
5358231200Smmisoent_setup_directory_location(struct iso9660 *iso9660, int location,
5359231200Smm    struct vdd *vdd)
5360231200Smm{
5361231200Smm	struct isoent *np;
5362231200Smm	int depth;
5363231200Smm
5364231200Smm	vdd->total_dir_block = 0;
5365231200Smm	depth = 0;
5366231200Smm	np = vdd->rootent;
5367231200Smm	do {
5368231200Smm		int block;
5369231200Smm
5370231200Smm		np->dir_block = calculate_directory_descriptors(
5371231200Smm		    iso9660, vdd, np, depth);
5372231200Smm		vdd->total_dir_block += np->dir_block;
5373231200Smm		np->dir_location = location;
5374231200Smm		location += np->dir_block;
5375231200Smm		block = extra_setup_location(np, location);
5376231200Smm		vdd->total_dir_block += block;
5377231200Smm		location += block;
5378231200Smm
5379231200Smm		if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
5380231200Smm			/* Enter to sub directories. */
5381231200Smm			np = np->subdirs.first;
5382231200Smm			depth++;
5383231200Smm			continue;
5384231200Smm		}
5385231200Smm		while (np != np->parent) {
5386231200Smm			if (np->drnext == NULL) {
5387231200Smm				/* Return to the parent directory. */
5388231200Smm				np = np->parent;
5389231200Smm				depth--;
5390231200Smm			} else {
5391231200Smm				np = np->drnext;
5392231200Smm				break;
5393231200Smm			}
5394231200Smm		}
5395231200Smm	} while (np != np->parent);
5396231200Smm}
5397231200Smm
5398231200Smmstatic void
5399231200Smm_isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,
5400231200Smm    int *symlocation)
5401231200Smm{
5402231200Smm	struct isoent **children;
5403231200Smm	int n;
5404231200Smm
5405231200Smm	if (isoent->children.cnt == 0)
5406231200Smm		return;
5407231200Smm
5408231200Smm	children = isoent->children_sorted;
5409231200Smm	for (n = 0; n < isoent->children.cnt; n++) {
5410231200Smm		struct isoent *np;
5411231200Smm		struct isofile *file;
5412231200Smm
5413231200Smm		np = children[n];
5414231200Smm		if (np->dir)
5415231200Smm			continue;
5416231200Smm		if (np == iso9660->el_torito.boot)
5417231200Smm			continue;
5418231200Smm		file = np->file;
5419231200Smm		if (file->boot || file->hardlink_target != NULL)
5420231200Smm			continue;
5421231200Smm		if (archive_entry_filetype(file->entry) == AE_IFLNK ||
5422231200Smm		    file->content.size == 0) {
5423231200Smm			/*
5424231200Smm			 * Do not point a valid location.
5425231200Smm			 * Make sure entry is not hardlink file.
5426231200Smm			 */
5427231200Smm			file->content.location = (*symlocation)--;
5428231200Smm			continue;
5429231200Smm		}
5430231200Smm
5431231200Smm		file->write_content = 1;
5432231200Smm	}
5433231200Smm}
5434231200Smm
5435231200Smm/*
5436231200Smm * Setup file locations.
5437231200Smm */
5438231200Smmstatic void
5439231200Smmisoent_setup_file_location(struct iso9660 *iso9660, int location)
5440231200Smm{
5441231200Smm	struct isoent *isoent;
5442231200Smm	struct isoent *np;
5443231200Smm	struct isofile *file;
5444231200Smm	size_t size;
5445231200Smm	int block;
5446231200Smm	int depth;
5447231200Smm	int joliet;
5448231200Smm	int symlocation;
5449231200Smm	int total_block;
5450231200Smm
5451231200Smm	iso9660->total_file_block = 0;
5452231200Smm	if ((isoent = iso9660->el_torito.catalog) != NULL) {
5453231200Smm		isoent->file->content.location = location;
5454238856Smm		block = (int)((archive_entry_size(isoent->file->entry) +
5455238856Smm		    LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
5456231200Smm		location += block;
5457231200Smm		iso9660->total_file_block += block;
5458231200Smm	}
5459231200Smm	if ((isoent = iso9660->el_torito.boot) != NULL) {
5460231200Smm		isoent->file->content.location = location;
5461231200Smm		size = fd_boot_image_size(iso9660->el_torito.media_type);
5462231200Smm		if (size == 0)
5463238856Smm			size = (size_t)archive_entry_size(isoent->file->entry);
5464248616Smm		block = ((int)size + LOGICAL_BLOCK_SIZE -1)
5465248616Smm		    >> LOGICAL_BLOCK_BITS;
5466231200Smm		location += block;
5467231200Smm		iso9660->total_file_block += block;
5468231200Smm		isoent->file->content.blocks = block;
5469231200Smm	}
5470231200Smm
5471231200Smm	depth = 0;
5472231200Smm	symlocation = -16;
5473231200Smm	if (!iso9660->opt.rr && iso9660->opt.joliet) {
5474231200Smm		joliet = 1;
5475231200Smm		np = iso9660->joliet.rootent;
5476231200Smm	} else {
5477231200Smm		joliet = 0;
5478231200Smm		np = iso9660->primary.rootent;
5479231200Smm	}
5480231200Smm	do {
5481231200Smm		_isoent_file_location(iso9660, np, &symlocation);
5482231200Smm
5483231200Smm		if (np->subdirs.first != NULL &&
5484231200Smm		    (joliet ||
5485231200Smm		    ((iso9660->opt.rr == OPT_RR_DISABLED &&
5486231200Smm		      depth + 2 < iso9660->primary.max_depth) ||
5487231200Smm		     (iso9660->opt.rr &&
5488231200Smm		      depth + 1 < iso9660->primary.max_depth)))) {
5489231200Smm			/* Enter to sub directories. */
5490231200Smm			np = np->subdirs.first;
5491231200Smm			depth++;
5492231200Smm			continue;
5493231200Smm		}
5494231200Smm		while (np != np->parent) {
5495231200Smm			if (np->drnext == NULL) {
5496231200Smm				/* Return to the parent directory. */
5497231200Smm				np = np->parent;
5498231200Smm				depth--;
5499231200Smm			} else {
5500231200Smm				np = np->drnext;
5501231200Smm				break;
5502231200Smm			}
5503231200Smm		}
5504231200Smm	} while (np != np->parent);
5505231200Smm
5506231200Smm	total_block = 0;
5507231200Smm	for (file = iso9660->data_file_list.first;
5508231200Smm	    file != NULL; file = file->datanext) {
5509231200Smm
5510231200Smm		if (!file->write_content)
5511231200Smm			continue;
5512231200Smm
5513231200Smm		file->cur_content = &(file->content);
5514231200Smm		do {
5515231200Smm			file->cur_content->location = location;
5516231200Smm			location += file->cur_content->blocks;
5517231200Smm			total_block += file->cur_content->blocks;
5518311042Smm			/* Next fragment */
5519231200Smm			file->cur_content = file->cur_content->next;
5520231200Smm		} while (file->cur_content != NULL);
5521231200Smm	}
5522231200Smm	iso9660->total_file_block += total_block;
5523231200Smm}
5524231200Smm
5525231200Smmstatic int
5526248616Smmget_path_component(char *name, size_t n, const char *fn)
5527231200Smm{
5528231200Smm	char *p;
5529248616Smm	size_t l;
5530231200Smm
5531231200Smm	p = strchr(fn, '/');
5532231200Smm	if (p == NULL) {
5533231200Smm		if ((l = strlen(fn)) == 0)
5534231200Smm			return (0);
5535231200Smm	} else
5536231200Smm		l = p - fn;
5537231200Smm	if (l > n -1)
5538231200Smm		return (-1);
5539231200Smm	memcpy(name, fn, l);
5540231200Smm	name[l] = '\0';
5541231200Smm
5542248616Smm	return ((int)l);
5543231200Smm}
5544231200Smm
5545231200Smm/*
5546231200Smm * Add a new entry into the tree.
5547231200Smm */
5548231200Smmstatic int
5549231200Smmisoent_tree(struct archive_write *a, struct isoent **isoentpp)
5550231200Smm{
5551231200Smm#if defined(_WIN32) && !defined(__CYGWIN__)
5552231200Smm	char name[_MAX_FNAME];/* Included null terminator size. */
5553231200Smm#elif defined(NAME_MAX) && NAME_MAX >= 255
5554231200Smm	char name[NAME_MAX+1];
5555231200Smm#else
5556231200Smm	char name[256];
5557231200Smm#endif
5558231200Smm	struct iso9660 *iso9660 = a->format_data;
5559231200Smm	struct isoent *dent, *isoent, *np;
5560231200Smm	struct isofile *f1, *f2;
5561231200Smm	const char *fn, *p;
5562231200Smm	int l;
5563231200Smm
5564231200Smm	isoent = *isoentpp;
5565231200Smm	dent = iso9660->primary.rootent;
5566231200Smm	if (isoent->file->parentdir.length > 0)
5567231200Smm		fn = p = isoent->file->parentdir.s;
5568231200Smm	else
5569231200Smm		fn = p = "";
5570231200Smm
5571231200Smm	/*
5572231200Smm	 * If the path of the parent directory of `isoent' entry is
5573231200Smm	 * the same as the path of `cur_dirent', add isoent to
5574231200Smm	 * `cur_dirent'.
5575231200Smm	 */
5576231200Smm	if (archive_strlen(&(iso9660->cur_dirstr))
5577231200Smm	      == archive_strlen(&(isoent->file->parentdir)) &&
5578231200Smm	    strcmp(iso9660->cur_dirstr.s, fn) == 0) {
5579231200Smm		if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {
5580231200Smm			np = (struct isoent *)__archive_rb_tree_find_node(
5581231200Smm			    &(iso9660->cur_dirent->rbtree),
5582231200Smm			    isoent->file->basename.s);
5583231200Smm			goto same_entry;
5584231200Smm		}
5585231200Smm		return (ARCHIVE_OK);
5586231200Smm	}
5587231200Smm
5588231200Smm	for (;;) {
5589231200Smm		l = get_path_component(name, sizeof(name), fn);
5590231200Smm		if (l == 0) {
5591231200Smm			np = NULL;
5592231200Smm			break;
5593231200Smm		}
5594231200Smm		if (l < 0) {
5595231200Smm			archive_set_error(&a->archive,
5596231200Smm			    ARCHIVE_ERRNO_MISC,
5597231200Smm			    "A name buffer is too small");
5598231200Smm			_isoent_free(isoent);
5599231200Smm			return (ARCHIVE_FATAL);
5600231200Smm		}
5601231200Smm
5602231200Smm		np = isoent_find_child(dent, name);
5603231200Smm		if (np == NULL || fn[0] == '\0')
5604231200Smm			break;
5605231200Smm
5606231200Smm		/* Find next subdirectory. */
5607231200Smm		if (!np->dir) {
5608231200Smm			/* NOT Directory! */
5609231200Smm			archive_set_error(&a->archive,
5610231200Smm			    ARCHIVE_ERRNO_MISC,
5611231200Smm			    "`%s' is not directory, we cannot insert `%s' ",
5612231200Smm			    archive_entry_pathname(np->file->entry),
5613231200Smm			    archive_entry_pathname(isoent->file->entry));
5614231200Smm			_isoent_free(isoent);
5615231200Smm			*isoentpp = NULL;
5616231200Smm			return (ARCHIVE_FAILED);
5617231200Smm		}
5618231200Smm		fn += l;
5619231200Smm		if (fn[0] == '/')
5620231200Smm			fn++;
5621231200Smm		dent = np;
5622231200Smm	}
5623231200Smm	if (np == NULL) {
5624231200Smm		/*
5625231200Smm		 * Create virtual parent directories.
5626231200Smm		 */
5627231200Smm		while (fn[0] != '\0') {
5628231200Smm			struct isoent *vp;
5629231200Smm			struct archive_string as;
5630231200Smm
5631231200Smm			archive_string_init(&as);
5632231200Smm			archive_strncat(&as, p, fn - p + l);
5633231200Smm			if (as.s[as.length-1] == '/') {
5634231200Smm				as.s[as.length-1] = '\0';
5635231200Smm				as.length--;
5636231200Smm			}
5637231200Smm			vp = isoent_create_virtual_dir(a, iso9660, as.s);
5638231200Smm			if (vp == NULL) {
5639231200Smm				archive_string_free(&as);
5640231200Smm				archive_set_error(&a->archive, ENOMEM,
5641231200Smm				    "Can't allocate memory");
5642231200Smm				_isoent_free(isoent);
5643231200Smm				*isoentpp = NULL;
5644231200Smm				return (ARCHIVE_FATAL);
5645231200Smm			}
5646231200Smm			archive_string_free(&as);
5647231200Smm
5648231200Smm			if (vp->file->dircnt > iso9660->dircnt_max)
5649231200Smm				iso9660->dircnt_max = vp->file->dircnt;
5650231200Smm			isoent_add_child_tail(dent, vp);
5651231200Smm			np = vp;
5652231200Smm
5653231200Smm			fn += l;
5654231200Smm			if (fn[0] == '/')
5655231200Smm				fn++;
5656231200Smm			l = get_path_component(name, sizeof(name), fn);
5657231200Smm			if (l < 0) {
5658231200Smm				archive_string_free(&as);
5659231200Smm				archive_set_error(&a->archive,
5660231200Smm				    ARCHIVE_ERRNO_MISC,
5661231200Smm				    "A name buffer is too small");
5662231200Smm				_isoent_free(isoent);
5663231200Smm				*isoentpp = NULL;
5664231200Smm				return (ARCHIVE_FATAL);
5665231200Smm			}
5666231200Smm			dent = np;
5667231200Smm		}
5668231200Smm
5669231200Smm		/* Found out the parent directory where isoent can be
5670231200Smm		 * inserted. */
5671231200Smm		iso9660->cur_dirent = dent;
5672231200Smm		archive_string_empty(&(iso9660->cur_dirstr));
5673231200Smm		archive_string_ensure(&(iso9660->cur_dirstr),
5674231200Smm		    archive_strlen(&(dent->file->parentdir)) +
5675231200Smm		    archive_strlen(&(dent->file->basename)) + 2);
5676231200Smm		if (archive_strlen(&(dent->file->parentdir)) +
5677231200Smm		    archive_strlen(&(dent->file->basename)) == 0)
5678231200Smm			iso9660->cur_dirstr.s[0] = 0;
5679231200Smm		else {
5680231200Smm			if (archive_strlen(&(dent->file->parentdir)) > 0) {
5681231200Smm				archive_string_copy(&(iso9660->cur_dirstr),
5682231200Smm				    &(dent->file->parentdir));
5683231200Smm				archive_strappend_char(&(iso9660->cur_dirstr), '/');
5684231200Smm			}
5685231200Smm			archive_string_concat(&(iso9660->cur_dirstr),
5686231200Smm			    &(dent->file->basename));
5687231200Smm		}
5688231200Smm
5689231200Smm		if (!isoent_add_child_tail(dent, isoent)) {
5690231200Smm			np = (struct isoent *)__archive_rb_tree_find_node(
5691231200Smm			    &(dent->rbtree), isoent->file->basename.s);
5692231200Smm			goto same_entry;
5693231200Smm		}
5694231200Smm		return (ARCHIVE_OK);
5695231200Smm	}
5696231200Smm
5697231200Smmsame_entry:
5698231200Smm	/*
5699231200Smm	 * We have already has the entry the filename of which is
5700231200Smm	 * the same.
5701231200Smm	 */
5702231200Smm	f1 = np->file;
5703231200Smm	f2 = isoent->file;
5704231200Smm
5705231200Smm	/* If the file type of entries is different,
5706231200Smm	 * we cannot handle it. */
5707231200Smm	if (archive_entry_filetype(f1->entry) !=
5708231200Smm	    archive_entry_filetype(f2->entry)) {
5709231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
5710231200Smm		    "Found duplicate entries `%s' and its file type is "
5711231200Smm		    "different",
5712231200Smm		    archive_entry_pathname(f1->entry));
5713231200Smm		_isoent_free(isoent);
5714231200Smm		*isoentpp = NULL;
5715231200Smm		return (ARCHIVE_FAILED);
5716231200Smm	}
5717231200Smm
5718231200Smm	/* Swap file entries. */
5719231200Smm	np->file = f2;
5720231200Smm	isoent->file = f1;
5721231200Smm	np->virtual = 0;
5722231200Smm
5723231200Smm	_isoent_free(isoent);
5724231200Smm	*isoentpp = np;
5725231200Smm	return (ARCHIVE_OK);
5726231200Smm}
5727231200Smm
5728231200Smm/*
5729231200Smm * Find a entry from `isoent'
5730231200Smm */
5731231200Smmstatic struct isoent *
5732231200Smmisoent_find_child(struct isoent *isoent, const char *child_name)
5733231200Smm{
5734231200Smm	struct isoent *np;
5735231200Smm
5736231200Smm	np = (struct isoent *)__archive_rb_tree_find_node(
5737231200Smm	    &(isoent->rbtree), child_name);
5738231200Smm	return (np);
5739231200Smm}
5740231200Smm
5741231200Smm/*
5742231200Smm * Find a entry full-path of which is specified by `fn' parameter,
5743231200Smm * in the tree.
5744231200Smm */
5745231200Smmstatic struct isoent *
5746231200Smmisoent_find_entry(struct isoent *rootent, const char *fn)
5747231200Smm{
5748231200Smm#if defined(_WIN32) && !defined(__CYGWIN__)
5749231200Smm	char name[_MAX_FNAME];/* Included null terminator size. */
5750231200Smm#elif defined(NAME_MAX) && NAME_MAX >= 255
5751231200Smm	char name[NAME_MAX+1];
5752231200Smm#else
5753231200Smm	char name[256];
5754231200Smm#endif
5755231200Smm	struct isoent *isoent, *np;
5756231200Smm	int l;
5757231200Smm
5758231200Smm	isoent = rootent;
5759231200Smm	np = NULL;
5760231200Smm	for (;;) {
5761231200Smm		l = get_path_component(name, sizeof(name), fn);
5762231200Smm		if (l == 0)
5763231200Smm			break;
5764231200Smm		fn += l;
5765231200Smm		if (fn[0] == '/')
5766231200Smm			fn++;
5767231200Smm
5768231200Smm		np = isoent_find_child(isoent, name);
5769231200Smm		if (np == NULL)
5770231200Smm			break;
5771231200Smm		if (fn[0] == '\0')
5772231200Smm			break;/* We found out the entry */
5773231200Smm
5774231200Smm		/* Try sub directory. */
5775231200Smm		isoent = np;
5776231200Smm		np = NULL;
5777231200Smm		if (!isoent->dir)
5778231200Smm			break;/* Not directory */
5779231200Smm	}
5780231200Smm
5781231200Smm	return (np);
5782231200Smm}
5783231200Smm
5784231200Smm/*
5785231200Smm * Following idr_* functions are used for resolving duplicated filenames
5786231200Smm * and unreceivable filenames to generate ISO9660/Joliet Identifiers.
5787231200Smm */
5788231200Smm
5789231200Smmstatic void
5790231200Smmidr_relaxed_filenames(char *map)
5791231200Smm{
5792231200Smm	int i;
5793231200Smm
5794231200Smm	for (i = 0x21; i <= 0x2F; i++)
5795231200Smm		map[i] = 1;
5796231200Smm	for (i = 0x3A; i <= 0x41; i++)
5797231200Smm		map[i] = 1;
5798231200Smm	for (i = 0x5B; i <= 0x5E; i++)
5799231200Smm		map[i] = 1;
5800231200Smm	map[0x60] = 1;
5801231200Smm	for (i = 0x7B; i <= 0x7E; i++)
5802231200Smm		map[i] = 1;
5803231200Smm}
5804231200Smm
5805231200Smmstatic void
5806231200Smmidr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)
5807231200Smm{
5808231200Smm
5809231200Smm	idr->idrent_pool = NULL;
5810231200Smm	idr->pool_size = 0;
5811231200Smm	if (vdd->vdd_type != VDD_JOLIET) {
5812231200Smm		if (iso9660->opt.iso_level <= 3) {
5813231200Smm			memcpy(idr->char_map, d_characters_map,
5814231200Smm			    sizeof(idr->char_map));
5815231200Smm		} else {
5816231200Smm			memcpy(idr->char_map, d1_characters_map,
5817231200Smm			    sizeof(idr->char_map));
5818231200Smm			idr_relaxed_filenames(idr->char_map);
5819231200Smm		}
5820231200Smm	}
5821231200Smm}
5822231200Smm
5823231200Smmstatic void
5824231200Smmidr_cleanup(struct idr *idr)
5825231200Smm{
5826231200Smm	free(idr->idrent_pool);
5827231200Smm}
5828231200Smm
5829231200Smmstatic int
5830231200Smmidr_ensure_poolsize(struct archive_write *a, struct idr *idr,
5831231200Smm    int cnt)
5832231200Smm{
5833231200Smm
5834231200Smm	if (idr->pool_size < cnt) {
5835248616Smm		void *p;
5836231200Smm		const int bk = (1 << 7) - 1;
5837231200Smm		int psize;
5838231200Smm
5839231200Smm		psize = (cnt + bk) & ~bk;
5840248616Smm		p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
5841248616Smm		if (p == NULL) {
5842231200Smm			archive_set_error(&a->archive, ENOMEM,
5843231200Smm			    "Can't allocate memory");
5844231200Smm			return (ARCHIVE_FATAL);
5845231200Smm		}
5846248616Smm		idr->idrent_pool = (struct idrent *)p;
5847231200Smm		idr->pool_size = psize;
5848231200Smm	}
5849231200Smm	return (ARCHIVE_OK);
5850231200Smm}
5851231200Smm
5852231200Smmstatic int
5853231200Smmidr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,
5854231200Smm    int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)
5855231200Smm{
5856231200Smm	int r;
5857231200Smm
5858231200Smm	(void)ffmax; /* UNUSED */
5859231200Smm
5860231200Smm	r = idr_ensure_poolsize(a, idr, cnt);
5861231200Smm	if (r != ARCHIVE_OK)
5862231200Smm		return (r);
5863231200Smm	__archive_rb_tree_init(&(idr->rbtree), rbt_ops);
5864231200Smm	idr->wait_list.first = NULL;
5865231200Smm	idr->wait_list.last = &(idr->wait_list.first);
5866231200Smm	idr->pool_idx = 0;
5867231200Smm	idr->num_size = num_size;
5868231200Smm	idr->null_size = null_size;
5869231200Smm	return (ARCHIVE_OK);
5870231200Smm}
5871231200Smm
5872231200Smmstatic void
5873231200Smmidr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
5874231200Smm{
5875231200Smm	struct idrent *idrent, *n;
5876231200Smm
5877231200Smm	idrent = &(idr->idrent_pool[idr->pool_idx++]);
5878231200Smm	idrent->wnext = idrent->avail = NULL;
5879231200Smm	idrent->isoent = isoent;
5880231200Smm	idrent->weight = weight;
5881231200Smm	idrent->noff = noff;
5882231200Smm	idrent->rename_num = 0;
5883231200Smm
5884231200Smm	if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {
5885231200Smm		n = (struct idrent *)__archive_rb_tree_find_node(
5886231200Smm		    &(idr->rbtree), idrent->isoent);
5887231200Smm		if (n != NULL) {
5888231200Smm			/* this `idrent' needs to rename. */
5889231200Smm			idrent->avail = n;
5890231200Smm			*idr->wait_list.last = idrent;
5891231200Smm			idr->wait_list.last = &(idrent->wnext);
5892231200Smm		}
5893231200Smm	}
5894231200Smm}
5895231200Smm
5896231200Smmstatic void
5897231200Smmidr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
5898231200Smm{
5899231200Smm	unsigned char *p;
5900231200Smm	int wnp_ext_off;
5901231200Smm
5902231200Smm	wnp_ext_off = wnp->isoent->ext_off;
5903231200Smm	if (wnp->noff + numsize != wnp_ext_off) {
5904231200Smm		p = (unsigned char *)wnp->isoent->identifier;
5905231200Smm		/* Extend the filename; foo.c --> foo___.c */
5906231200Smm		memmove(p + wnp->noff + numsize, p + wnp_ext_off,
5907231200Smm		    wnp->isoent->ext_len + nullsize);
5908231200Smm		wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
5909231200Smm		wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
5910231200Smm	}
5911231200Smm}
5912231200Smm
5913231200Smmstatic void
5914231200Smmidr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
5915231200Smm{
5916231200Smm	struct idrent *n;
5917231200Smm	unsigned char *p;
5918231200Smm
5919231200Smm	for (n = idr->wait_list.first; n != NULL; n = n->wnext) {
5920231200Smm		idr_extend_identifier(n, idr->num_size, idr->null_size);
5921231200Smm		p = (unsigned char *)n->isoent->identifier + n->noff;
5922231200Smm		do {
5923231200Smm			fsetnum(p, n->avail->rename_num++);
5924231200Smm		} while (!__archive_rb_tree_insert_node(
5925231200Smm		    &(idr->rbtree), &(n->rbnode)));
5926231200Smm	}
5927231200Smm}
5928231200Smm
5929231200Smmstatic void
5930231200Smmidr_set_num(unsigned char *p, int num)
5931231200Smm{
5932231200Smm	static const char xdig[] = {
5933231200Smm		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5934231200Smm		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
5935231200Smm		'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
5936231200Smm		'U', 'V', 'W', 'X', 'Y', 'Z'
5937231200Smm	};
5938231200Smm
5939231200Smm	num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);
5940231200Smm	p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];
5941231200Smm	num %= sizeof(xdig) * sizeof(xdig);
5942231200Smm	p[1] = xdig[ (num / sizeof(xdig))];
5943231200Smm	num %= sizeof(xdig);
5944231200Smm	p[2] = xdig[num];
5945231200Smm}
5946231200Smm
5947231200Smmstatic void
5948231200Smmidr_set_num_beutf16(unsigned char *p, int num)
5949231200Smm{
5950231200Smm	static const uint16_t xdig[] = {
5951231200Smm		0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
5952231200Smm		0x0036, 0x0037, 0x0038, 0x0039,
5953231200Smm		0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
5954231200Smm		0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,
5955231200Smm		0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
5956231200Smm		0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
5957231200Smm		0x0059, 0x005A
5958231200Smm	};
5959231200Smm#define XDIG_CNT	(sizeof(xdig)/sizeof(xdig[0]))
5960231200Smm
5961231200Smm	num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;
5962231200Smm	archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);
5963231200Smm	num %= XDIG_CNT * XDIG_CNT;
5964231200Smm	archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);
5965231200Smm	num %= XDIG_CNT;
5966231200Smm	archive_be16enc(p+4, xdig[num]);
5967231200Smm}
5968231200Smm
5969231200Smm/*
5970231200Smm * Generate ISO9660 Identifier.
5971231200Smm */
5972231200Smmstatic int
5973231200Smmisoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
5974231200Smm    struct idr *idr)
5975231200Smm{
5976231200Smm	struct iso9660 *iso9660;
5977231200Smm	struct isoent *np;
5978231200Smm	char *p;
5979231200Smm	int l, r;
5980231200Smm	const char *char_map;
5981231200Smm	char allow_ldots, allow_multidot, allow_period, allow_vernum;
5982231200Smm	int fnmax, ffmax, dnmax;
5983231200Smm	static const struct archive_rb_tree_ops rb_ops = {
5984231200Smm		isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
5985231200Smm	};
5986231200Smm
5987231200Smm	if (isoent->children.cnt == 0)
5988231200Smm		return (0);
5989231200Smm
5990231200Smm	iso9660 = a->format_data;
5991231200Smm	char_map = idr->char_map;
5992231200Smm	if (iso9660->opt.iso_level <= 3) {
5993231200Smm		allow_ldots = 0;
5994231200Smm		allow_multidot = 0;
5995231200Smm		allow_period = 1;
5996231200Smm		allow_vernum = iso9660->opt.allow_vernum;
5997231200Smm		if (iso9660->opt.iso_level == 1) {
5998231200Smm			fnmax = 8;
5999231200Smm			ffmax = 12;/* fnmax + '.' + 3 */
6000231200Smm			dnmax = 8;
6001231200Smm		} else {
6002231200Smm			fnmax = 30;
6003231200Smm			ffmax = 31;
6004231200Smm			dnmax = 31;
6005231200Smm		}
6006231200Smm	} else {
6007231200Smm		allow_ldots = allow_multidot = 1;
6008231200Smm		allow_period = allow_vernum = 0;
6009231200Smm		if (iso9660->opt.rr)
6010231200Smm			/*
6011231200Smm			 * MDR : The maximum size of Directory Record(254).
6012231200Smm			 * DRL : A Directory Record Length(33).
6013231200Smm			 * CE  : A size of SUSP CE System Use Entry(28).
6014231200Smm			 * MDR - DRL - CE = 254 - 33 - 28 = 193.
6015231200Smm			 */
6016231200Smm			fnmax = ffmax = dnmax = 193;
6017231200Smm		else
6018231200Smm			/*
6019231200Smm			 * XA  : CD-ROM XA System Use Extension
6020231200Smm			 *       Information(14).
6021231200Smm			 * MDR - DRL - XA = 254 - 33 -14 = 207.
6022231200Smm			 */
6023231200Smm			fnmax = ffmax = dnmax = 207;
6024231200Smm	}
6025231200Smm
6026231200Smm	r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
6027231200Smm	if (r < 0)
6028231200Smm		return (r);
6029231200Smm
6030231200Smm	for (np = isoent->children.first; np != NULL; np = np->chnext) {
6031231200Smm		char *dot, *xdot;
6032231200Smm		int ext_off, noff, weight;
6033231200Smm
6034248616Smm		l = (int)np->file->basename.length;
6035231200Smm		p = malloc(l+31+2+1);
6036231200Smm		if (p == NULL) {
6037231200Smm			archive_set_error(&a->archive, ENOMEM,
6038231200Smm			    "Can't allocate memory");
6039231200Smm			return (ARCHIVE_FATAL);
6040231200Smm		}
6041231200Smm		memcpy(p, np->file->basename.s, l);
6042231200Smm		p[l] = '\0';
6043231200Smm		np->identifier = p;
6044231200Smm
6045231200Smm		dot = xdot = NULL;
6046231200Smm		if (!allow_ldots) {
6047231200Smm			/*
6048231200Smm			 * If there is a '.' character at the first byte,
6049231200Smm			 * it has to be replaced by '_' character.
6050231200Smm			 */
6051231200Smm			if (*p == '.')
6052231200Smm				*p++ = '_';
6053231200Smm		}
6054231200Smm		for (;*p; p++) {
6055231200Smm			if (*p & 0x80) {
6056231200Smm				*p = '_';
6057231200Smm				continue;
6058231200Smm			}
6059231200Smm			if (char_map[(unsigned char)*p]) {
6060231200Smm				/* if iso-level is '4', a character '.' is
6061231200Smm				 * allowed by char_map. */
6062231200Smm				if (*p == '.') {
6063231200Smm					xdot = dot;
6064231200Smm					dot = p;
6065231200Smm				}
6066231200Smm				continue;
6067231200Smm			}
6068231200Smm			if (*p >= 'a' && *p <= 'z') {
6069231200Smm				*p -= 'a' - 'A';
6070231200Smm				continue;
6071231200Smm			}
6072231200Smm			if (*p == '.') {
6073231200Smm				xdot = dot;
6074231200Smm				dot = p;
6075231200Smm				if (allow_multidot)
6076231200Smm					continue;
6077231200Smm			}
6078231200Smm			*p = '_';
6079231200Smm		}
6080231200Smm		p = np->identifier;
6081231200Smm		weight = -1;
6082231200Smm		if (dot == NULL) {
6083231200Smm			int nammax;
6084231200Smm
6085231200Smm			if (np->dir)
6086231200Smm				nammax = dnmax;
6087231200Smm			else
6088231200Smm				nammax = fnmax;
6089231200Smm
6090231200Smm			if (l > nammax) {
6091231200Smm				p[nammax] = '\0';
6092231200Smm				weight = nammax;
6093231200Smm				ext_off = nammax;
6094231200Smm			} else
6095231200Smm				ext_off = l;
6096231200Smm		} else {
6097231200Smm			*dot = '.';
6098248616Smm			ext_off = (int)(dot - p);
6099231200Smm
6100231200Smm			if (iso9660->opt.iso_level == 1) {
6101231200Smm				if (dot - p <= 8) {
6102231200Smm					if (strlen(dot) > 4) {
6103231200Smm						/* A length of a file extension
6104231200Smm						 * must be less than 4 */
6105231200Smm						dot[4] = '\0';
6106231200Smm						weight = 0;
6107231200Smm					}
6108231200Smm				} else {
6109231200Smm					p[8] = dot[0];
6110231200Smm					p[9] = dot[1];
6111231200Smm					p[10] = dot[2];
6112231200Smm					p[11] = dot[3];
6113231200Smm					p[12] = '\0';
6114231200Smm					weight = 8;
6115231200Smm					ext_off = 8;
6116231200Smm				}
6117231200Smm			} else if (np->dir) {
6118231200Smm				if (l > dnmax) {
6119231200Smm					p[dnmax] = '\0';
6120231200Smm					weight = dnmax;
6121231200Smm					if (ext_off > dnmax)
6122231200Smm						ext_off = dnmax;
6123231200Smm				}
6124231200Smm			} else if (l > ffmax) {
6125248616Smm				int extlen = (int)strlen(dot);
6126231200Smm				int xdoff;
6127231200Smm
6128231200Smm				if (xdot != NULL)
6129248616Smm					xdoff = (int)(xdot - p);
6130231200Smm				else
6131231200Smm					xdoff = 0;
6132231200Smm
6133231200Smm				if (extlen > 1 && xdoff < fnmax-1) {
6134231200Smm					int off;
6135231200Smm
6136231200Smm					if (extlen > ffmax)
6137231200Smm						extlen = ffmax;
6138231200Smm					off = ffmax - extlen;
6139231200Smm					if (off == 0) {
6140231200Smm						/* A dot('.')  character
6141313571Smm						 * doesn't place to the first
6142231200Smm						 * byte of identifier. */
6143231200Smm						off ++;
6144231200Smm						extlen --;
6145231200Smm					}
6146231200Smm					memmove(p+off, dot, extlen);
6147231200Smm					p[ffmax] = '\0';
6148231200Smm					ext_off = off;
6149231200Smm					weight = off;
6150231200Smm#ifdef COMPAT_MKISOFS
6151231200Smm				} else if (xdoff >= fnmax-1) {
6152231200Smm					/* Simulate a bug(?) of mkisofs. */
6153231200Smm					p[fnmax-1] = '\0';
6154231200Smm					ext_off = fnmax-1;
6155231200Smm					weight = fnmax-1;
6156231200Smm#endif
6157231200Smm				} else {
6158231200Smm					p[fnmax] = '\0';
6159231200Smm					ext_off = fnmax;
6160231200Smm					weight = fnmax;
6161231200Smm				}
6162231200Smm			}
6163231200Smm		}
6164231200Smm		/* Save an offset of a file name extension to sort files. */
6165231200Smm		np->ext_off = ext_off;
6166248616Smm		np->ext_len = (int)strlen(&p[ext_off]);
6167231200Smm		np->id_len = l = ext_off + np->ext_len;
6168231200Smm
6169231200Smm		/* Make an offset of the number which is used to be set
6170311042Smm		 * hexadecimal number to avoid duplicate identifier. */
6171231200Smm		if (iso9660->opt.iso_level == 1) {
6172231200Smm			if (ext_off >= 5)
6173231200Smm				noff = 5;
6174231200Smm			else
6175231200Smm				noff = ext_off;
6176231200Smm		} else {
6177231200Smm			if (l == ffmax)
6178231200Smm				noff = ext_off - 3;
6179231200Smm			else if (l == ffmax-1)
6180231200Smm				noff = ext_off - 2;
6181231200Smm			else if (l == ffmax-2)
6182231200Smm				noff = ext_off - 1;
6183231200Smm			else
6184231200Smm				noff = ext_off;
6185231200Smm		}
6186231200Smm		/* Register entry to the identifier resolver. */
6187231200Smm		idr_register(idr, np, weight, noff);
6188231200Smm	}
6189231200Smm
6190231200Smm	/* Resolve duplicate identifier. */
6191231200Smm	idr_resolve(idr, idr_set_num);
6192231200Smm
6193231200Smm	/* Add a period and a version number to identifiers. */
6194231200Smm	for (np = isoent->children.first; np != NULL; np = np->chnext) {
6195231200Smm		if (!np->dir && np->rr_child == NULL) {
6196231200Smm			p = np->identifier + np->ext_off + np->ext_len;
6197231200Smm			if (np->ext_len == 0 && allow_period) {
6198231200Smm				*p++ = '.';
6199231200Smm				np->ext_len = 1;
6200231200Smm			}
6201231200Smm			if (np->ext_len == 1 && !allow_period) {
6202231200Smm				*--p = '\0';
6203231200Smm				np->ext_len = 0;
6204231200Smm			}
6205231200Smm			np->id_len = np->ext_off + np->ext_len;
6206231200Smm			if (allow_vernum) {
6207231200Smm				*p++ = ';';
6208231200Smm				*p++ = '1';
6209231200Smm				np->id_len += 2;
6210231200Smm			}
6211231200Smm			*p = '\0';
6212231200Smm		} else
6213231200Smm			np->id_len = np->ext_off + np->ext_len;
6214231200Smm		np->mb_len = np->id_len;
6215231200Smm	}
6216231200Smm	return (ARCHIVE_OK);
6217231200Smm}
6218231200Smm
6219231200Smm/*
6220231200Smm * Generate Joliet Identifier.
6221231200Smm */
6222231200Smmstatic int
6223231200Smmisoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
6224231200Smm    struct idr *idr)
6225231200Smm{
6226231200Smm	struct iso9660 *iso9660;
6227231200Smm	struct isoent *np;
6228231200Smm	unsigned char *p;
6229231200Smm	size_t l;
6230231200Smm	int r;
6231302295Smm	size_t ffmax, parent_len;
6232231200Smm	static const struct archive_rb_tree_ops rb_ops = {
6233231200Smm		isoent_cmp_node_joliet, isoent_cmp_key_joliet
6234231200Smm	};
6235231200Smm
6236231200Smm	if (isoent->children.cnt == 0)
6237231200Smm		return (0);
6238231200Smm
6239231200Smm	iso9660 = a->format_data;
6240231200Smm	if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
6241231200Smm		ffmax = 206;
6242231200Smm	else
6243231200Smm		ffmax = 128;
6244231200Smm
6245302295Smm	r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
6246231200Smm	if (r < 0)
6247231200Smm		return (r);
6248231200Smm
6249231200Smm	parent_len = 1;
6250231200Smm	for (np = isoent; np->parent != np; np = np->parent)
6251231200Smm		parent_len += np->mb_len + 1;
6252231200Smm
6253231200Smm	for (np = isoent->children.first; np != NULL; np = np->chnext) {
6254231200Smm		unsigned char *dot;
6255231200Smm		int ext_off, noff, weight;
6256231200Smm		size_t lt;
6257231200Smm
6258302295Smm		if ((l = np->file->basename_utf16.length) > ffmax)
6259231200Smm			l = ffmax;
6260231200Smm
6261231200Smm		p = malloc((l+1)*2);
6262231200Smm		if (p == NULL) {
6263231200Smm			archive_set_error(&a->archive, ENOMEM,
6264231200Smm			    "Can't allocate memory");
6265231200Smm			return (ARCHIVE_FATAL);
6266231200Smm		}
6267231200Smm		memcpy(p, np->file->basename_utf16.s, l);
6268231200Smm		p[l] = 0;
6269231200Smm		p[l+1] = 0;
6270231200Smm
6271231200Smm		np->identifier = (char *)p;
6272231200Smm		lt = l;
6273231200Smm		dot = p + l;
6274231200Smm		weight = 0;
6275231200Smm		while (lt > 0) {
6276231200Smm			if (!joliet_allowed_char(p[0], p[1]))
6277231200Smm				archive_be16enc(p, 0x005F); /* '_' */
6278231200Smm			else if (p[0] == 0 && p[1] == 0x2E) /* '.' */
6279231200Smm				dot = p;
6280231200Smm			p += 2;
6281231200Smm			lt -= 2;
6282231200Smm		}
6283248616Smm		ext_off = (int)(dot - (unsigned char *)np->identifier);
6284231200Smm		np->ext_off = ext_off;
6285248616Smm		np->ext_len = (int)l - ext_off;
6286248616Smm		np->id_len = (int)l;
6287231200Smm
6288231200Smm		/*
6289231200Smm		 * Get a length of MBS of a full-pathname.
6290231200Smm		 */
6291302295Smm		if (np->file->basename_utf16.length > ffmax) {
6292238856Smm			if (archive_strncpy_l(&iso9660->mbs,
6293231200Smm			    (const char *)np->identifier, l,
6294238856Smm				iso9660->sconv_from_utf16be) != 0 &&
6295238856Smm			    errno == ENOMEM) {
6296238856Smm				archive_set_error(&a->archive, errno,
6297238856Smm				    "No memory");
6298238856Smm				return (ARCHIVE_FATAL);
6299238856Smm			}
6300248616Smm			np->mb_len = (int)iso9660->mbs.length;
6301231200Smm			if (np->mb_len != (int)np->file->basename.length)
6302231200Smm				weight = np->mb_len;
6303231200Smm		} else
6304248616Smm			np->mb_len = (int)np->file->basename.length;
6305231200Smm
6306231200Smm		/* If a length of full-pathname is longer than 240 bytes,
6307231200Smm		 * it violates Joliet extensions regulation. */
6308302295Smm		if (parent_len > 240
6309302295Smm		    || np->mb_len > 240
6310302295Smm		    || parent_len + np->mb_len > 240) {
6311231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
6312231200Smm			    "The regulation of Joliet extensions;"
6313231200Smm			    " A length of a full-pathname of `%s' is "
6314231200Smm			    "longer than 240 bytes, (p=%d, b=%d)",
6315231200Smm			    archive_entry_pathname(np->file->entry),
6316231200Smm			    (int)parent_len, (int)np->mb_len);
6317231200Smm			return (ARCHIVE_FATAL);
6318231200Smm		}
6319231200Smm
6320231200Smm		/* Make an offset of the number which is used to be set
6321231200Smm		 * hexadecimal number to avoid duplicate identifier. */
6322302295Smm		if (l == ffmax)
6323231200Smm			noff = ext_off - 6;
6324302295Smm		else if (l == ffmax-2)
6325231200Smm			noff = ext_off - 4;
6326302295Smm		else if (l == ffmax-4)
6327231200Smm			noff = ext_off - 2;
6328231200Smm		else
6329231200Smm			noff = ext_off;
6330231200Smm		/* Register entry to the identifier resolver. */
6331231200Smm		idr_register(idr, np, weight, noff);
6332231200Smm	}
6333231200Smm
6334231200Smm	/* Resolve duplicate identifier with Joliet Volume. */
6335231200Smm	idr_resolve(idr, idr_set_num_beutf16);
6336231200Smm
6337231200Smm	return (ARCHIVE_OK);
6338231200Smm}
6339231200Smm
6340231200Smm/*
6341231200Smm * This comparing rule is according to ISO9660 Standard 9.3
6342231200Smm */
6343231200Smmstatic int
6344231200Smmisoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
6345231200Smm{
6346231200Smm	const char *s1, *s2;
6347231200Smm	int cmp;
6348231200Smm	int l;
6349231200Smm
6350231200Smm	s1 = p1->identifier;
6351231200Smm	s2 = p2->identifier;
6352231200Smm
6353231200Smm	/* Compare File Name */
6354231200Smm	l = p1->ext_off;
6355231200Smm	if (l > p2->ext_off)
6356231200Smm		l = p2->ext_off;
6357231200Smm	cmp = memcmp(s1, s2, l);
6358231200Smm	if (cmp != 0)
6359231200Smm		return (cmp);
6360231200Smm	if (p1->ext_off < p2->ext_off) {
6361231200Smm		s2 += l;
6362231200Smm		l = p2->ext_off - p1->ext_off;
6363231200Smm		while (l--)
6364231200Smm			if (0x20 != *s2++)
6365231200Smm				return (0x20
6366231200Smm				    - *(const unsigned char *)(s2 - 1));
6367231200Smm	} else if (p1->ext_off > p2->ext_off) {
6368231200Smm		s1 += l;
6369231200Smm		l = p1->ext_off - p2->ext_off;
6370231200Smm		while (l--)
6371231200Smm			if (0x20 != *s1++)
6372231200Smm				return (*(const unsigned char *)(s1 - 1)
6373231200Smm				    - 0x20);
6374231200Smm	}
6375231200Smm	/* Compare File Name Extension */
6376231200Smm	if (p1->ext_len == 0 && p2->ext_len == 0)
6377231200Smm		return (0);
6378231200Smm	if (p1->ext_len == 1 && p2->ext_len == 1)
6379231200Smm		return (0);
6380231200Smm	if (p1->ext_len <= 1)
6381231200Smm		return (-1);
6382231200Smm	if (p2->ext_len <= 1)
6383231200Smm		return (1);
6384231200Smm	l = p1->ext_len;
6385231200Smm	if (l > p2->ext_len)
6386231200Smm		l = p2->ext_len;
6387231200Smm	s1 = p1->identifier + p1->ext_off;
6388231200Smm	s2 = p2->identifier + p2->ext_off;
6389231200Smm	if (l > 1) {
6390231200Smm		cmp = memcmp(s1, s2, l);
6391231200Smm		if (cmp != 0)
6392231200Smm			return (cmp);
6393231200Smm	}
6394231200Smm	if (p1->ext_len < p2->ext_len) {
6395231200Smm		s2 += l;
6396231200Smm		l = p2->ext_len - p1->ext_len;
6397231200Smm		while (l--)
6398231200Smm			if (0x20 != *s2++)
6399231200Smm				return (0x20
6400231200Smm				    - *(const unsigned char *)(s2 - 1));
6401238856Smm	} else if (p1->ext_len > p2->ext_len) {
6402231200Smm		s1 += l;
6403231200Smm		l = p1->ext_len - p2->ext_len;
6404231200Smm		while (l--)
6405231200Smm			if (0x20 != *s1++)
6406231200Smm				return (*(const unsigned char *)(s1 - 1)
6407231200Smm				    - 0x20);
6408231200Smm	}
6409231200Smm	/* Compare File Version Number */
6410231200Smm	/* No operation. The File Version Number is always one. */
6411231200Smm
6412231200Smm	return (cmp);
6413231200Smm}
6414231200Smm
6415231200Smmstatic int
6416231200Smmisoent_cmp_node_iso9660(const struct archive_rb_node *n1,
6417231200Smm    const struct archive_rb_node *n2)
6418231200Smm{
6419231200Smm	const struct idrent *e1 = (const struct idrent *)n1;
6420231200Smm	const struct idrent *e2 = (const struct idrent *)n2;
6421231200Smm
6422231200Smm	return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));
6423231200Smm}
6424231200Smm
6425231200Smmstatic int
6426231200Smmisoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)
6427231200Smm{
6428231200Smm	const struct isoent *isoent = (const struct isoent *)key;
6429231200Smm	const struct idrent *idrent = (const struct idrent *)node;
6430231200Smm
6431231200Smm	return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));
6432231200Smm}
6433231200Smm
6434231200Smmstatic int
6435231200Smmisoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
6436231200Smm{
6437231200Smm	const unsigned char *s1, *s2;
6438231200Smm	int cmp;
6439231200Smm	int l;
6440231200Smm
6441231200Smm	s1 = (const unsigned char *)p1->identifier;
6442231200Smm	s2 = (const unsigned char *)p2->identifier;
6443231200Smm
6444231200Smm	/* Compare File Name */
6445231200Smm	l = p1->ext_off;
6446231200Smm	if (l > p2->ext_off)
6447231200Smm		l = p2->ext_off;
6448231200Smm	cmp = memcmp(s1, s2, l);
6449231200Smm	if (cmp != 0)
6450231200Smm		return (cmp);
6451231200Smm	if (p1->ext_off < p2->ext_off) {
6452231200Smm		s2 += l;
6453231200Smm		l = p2->ext_off - p1->ext_off;
6454231200Smm		while (l--)
6455231200Smm			if (0 != *s2++)
6456231200Smm				return (- *(const unsigned char *)(s2 - 1));
6457231200Smm	} else if (p1->ext_off > p2->ext_off) {
6458231200Smm		s1 += l;
6459231200Smm		l = p1->ext_off - p2->ext_off;
6460231200Smm		while (l--)
6461231200Smm			if (0 != *s1++)
6462231200Smm				return (*(const unsigned char *)(s1 - 1));
6463231200Smm	}
6464231200Smm	/* Compare File Name Extension */
6465231200Smm	if (p1->ext_len == 0 && p2->ext_len == 0)
6466231200Smm		return (0);
6467231200Smm	if (p1->ext_len == 2 && p2->ext_len == 2)
6468231200Smm		return (0);
6469231200Smm	if (p1->ext_len <= 2)
6470231200Smm		return (-1);
6471231200Smm	if (p2->ext_len <= 2)
6472231200Smm		return (1);
6473231200Smm	l = p1->ext_len;
6474231200Smm	if (l > p2->ext_len)
6475231200Smm		l = p2->ext_len;
6476231200Smm	s1 = (unsigned char *)(p1->identifier + p1->ext_off);
6477231200Smm	s2 = (unsigned char *)(p2->identifier + p2->ext_off);
6478231200Smm	if (l > 1) {
6479231200Smm		cmp = memcmp(s1, s2, l);
6480231200Smm		if (cmp != 0)
6481231200Smm			return (cmp);
6482231200Smm	}
6483231200Smm	if (p1->ext_len < p2->ext_len) {
6484231200Smm		s2 += l;
6485231200Smm		l = p2->ext_len - p1->ext_len;
6486231200Smm		while (l--)
6487231200Smm			if (0 != *s2++)
6488231200Smm				return (- *(const unsigned char *)(s2 - 1));
6489238856Smm	} else if (p1->ext_len > p2->ext_len) {
6490231200Smm		s1 += l;
6491231200Smm		l = p1->ext_len - p2->ext_len;
6492231200Smm		while (l--)
6493231200Smm			if (0 != *s1++)
6494231200Smm				return (*(const unsigned char *)(s1 - 1));
6495231200Smm	}
6496231200Smm	/* Compare File Version Number */
6497231200Smm	/* No operation. The File Version Number is always one. */
6498231200Smm
6499231200Smm	return (cmp);
6500231200Smm}
6501231200Smm
6502231200Smmstatic int
6503231200Smmisoent_cmp_node_joliet(const struct archive_rb_node *n1,
6504231200Smm    const struct archive_rb_node *n2)
6505231200Smm{
6506231200Smm	const struct idrent *e1 = (const struct idrent *)n1;
6507231200Smm	const struct idrent *e2 = (const struct idrent *)n2;
6508231200Smm
6509231200Smm	return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));
6510231200Smm}
6511231200Smm
6512231200Smmstatic int
6513231200Smmisoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)
6514231200Smm{
6515231200Smm	const struct isoent *isoent = (const struct isoent *)key;
6516231200Smm	const struct idrent *idrent = (const struct idrent *)node;
6517231200Smm
6518231200Smm	return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));
6519231200Smm}
6520231200Smm
6521231200Smmstatic int
6522231200Smmisoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,
6523231200Smm    struct idr *idr)
6524231200Smm{
6525231200Smm	struct archive_rb_node *rn;
6526231200Smm	struct isoent **children;
6527231200Smm
6528231200Smm	children = malloc(isoent->children.cnt * sizeof(struct isoent *));
6529231200Smm	if (children == NULL) {
6530231200Smm		archive_set_error(&a->archive, ENOMEM,
6531231200Smm		    "Can't allocate memory");
6532231200Smm		return (ARCHIVE_FATAL);
6533231200Smm	}
6534231200Smm	isoent->children_sorted = children;
6535231200Smm
6536231200Smm	ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {
6537231200Smm		struct idrent *idrent = (struct idrent *)rn;
6538231200Smm		*children ++ = idrent->isoent;
6539231200Smm	}
6540231200Smm	return (ARCHIVE_OK);
6541231200Smm}
6542231200Smm
6543231200Smm/*
6544231200Smm * - Generate ISO9660 and Joliet identifiers from basenames.
6545231200Smm * - Sort files by each directory.
6546231200Smm */
6547231200Smmstatic int
6548231200Smmisoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
6549231200Smm{
6550231200Smm	struct iso9660 *iso9660 = a->format_data;
6551231200Smm	struct isoent *np;
6552231200Smm	struct idr idr;
6553231200Smm	int depth;
6554231200Smm	int r;
6555232153Smm	int (*genid)(struct archive_write *, struct isoent *, struct idr *);
6556231200Smm
6557231200Smm	idr_init(iso9660, vdd, &idr);
6558231200Smm	np = vdd->rootent;
6559231200Smm	depth = 0;
6560231200Smm	if (vdd->vdd_type == VDD_JOLIET)
6561231200Smm		genid = isoent_gen_joliet_identifier;
6562231200Smm	else
6563231200Smm		genid = isoent_gen_iso9660_identifier;
6564231200Smm	do {
6565231200Smm		if (np->virtual &&
6566231200Smm		    !archive_entry_mtime_is_set(np->file->entry)) {
6567231200Smm			/* Set properly times to virtual directory */
6568231200Smm			archive_entry_set_mtime(np->file->entry,
6569231200Smm			    iso9660->birth_time, 0);
6570231200Smm			archive_entry_set_atime(np->file->entry,
6571231200Smm			    iso9660->birth_time, 0);
6572231200Smm			archive_entry_set_ctime(np->file->entry,
6573231200Smm			    iso9660->birth_time, 0);
6574231200Smm		}
6575231200Smm		if (np->children.first != NULL) {
6576231200Smm			if (vdd->vdd_type != VDD_JOLIET &&
6577231200Smm			    !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {
6578231200Smm				if (np->children.cnt > 0)
6579231200Smm					iso9660->directories_too_deep = np;
6580231200Smm			} else {
6581231200Smm				/* Generate Identifier */
6582231200Smm				r = genid(a, np, &idr);
6583231200Smm				if (r < 0)
6584231200Smm					goto exit_traverse_tree;
6585231200Smm				r = isoent_make_sorted_files(a, np, &idr);
6586231200Smm				if (r < 0)
6587231200Smm					goto exit_traverse_tree;
6588231200Smm
6589231200Smm				if (np->subdirs.first != NULL &&
6590231200Smm				    depth + 1 < vdd->max_depth) {
6591231200Smm					/* Enter to sub directories. */
6592231200Smm					np = np->subdirs.first;
6593231200Smm					depth++;
6594231200Smm					continue;
6595231200Smm				}
6596231200Smm			}
6597231200Smm		}
6598231200Smm		while (np != np->parent) {
6599231200Smm			if (np->drnext == NULL) {
6600231200Smm				/* Return to the parent directory. */
6601231200Smm				np = np->parent;
6602231200Smm				depth--;
6603231200Smm			} else {
6604231200Smm				np = np->drnext;
6605231200Smm				break;
6606231200Smm			}
6607231200Smm		}
6608231200Smm	} while (np != np->parent);
6609231200Smm
6610231200Smm	r = ARCHIVE_OK;
6611231200Smmexit_traverse_tree:
6612231200Smm	idr_cleanup(&idr);
6613231200Smm
6614231200Smm	return (r);
6615231200Smm}
6616231200Smm
6617231200Smm/*
6618231200Smm * Collect directory entries into path_table by a directory depth.
6619231200Smm */
6620231200Smmstatic int
6621231200Smmisoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
6622231200Smm{
6623231200Smm	struct isoent *np;
6624231200Smm
6625231200Smm	if (rootent == NULL)
6626231200Smm		rootent = vdd->rootent;
6627231200Smm	np = rootent;
6628231200Smm	do {
6629231200Smm		/* Register current directory to pathtable. */
6630231200Smm		path_table_add_entry(&(vdd->pathtbl[depth]), np);
6631231200Smm
6632231200Smm		if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
6633231200Smm			/* Enter to sub directories. */
6634231200Smm			np = np->subdirs.first;
6635231200Smm			depth++;
6636231200Smm			continue;
6637231200Smm		}
6638231200Smm		while (np != rootent) {
6639231200Smm			if (np->drnext == NULL) {
6640231200Smm				/* Return to the parent directory. */
6641231200Smm				np = np->parent;
6642231200Smm				depth--;
6643231200Smm			} else {
6644231200Smm				np = np->drnext;
6645231200Smm				break;
6646231200Smm			}
6647231200Smm		}
6648231200Smm	} while (np != rootent);
6649231200Smm
6650231200Smm	return (ARCHIVE_OK);
6651231200Smm}
6652231200Smm
6653231200Smm/*
6654231200Smm * The entry whose number of levels in a directory hierarchy is
6655231200Smm * large than eight relocate to rr_move directory.
6656231200Smm */
6657231200Smmstatic int
6658231200Smmisoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
6659238856Smm    struct isoent *curent, struct isoent **newent)
6660231200Smm{
6661231200Smm	struct iso9660 *iso9660 = a->format_data;
6662231200Smm	struct isoent *rrmoved, *mvent, *np;
6663231200Smm
6664231200Smm	if ((rrmoved = *rr_moved) == NULL) {
6665231200Smm		struct isoent *rootent = iso9660->primary.rootent;
6666231200Smm		/* There isn't rr_move entry.
6667231200Smm		 * Create rr_move entry and insert it into the root entry.
6668231200Smm		 */
6669231200Smm		rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");
6670231200Smm		if (rrmoved == NULL) {
6671231200Smm			archive_set_error(&a->archive, ENOMEM,
6672231200Smm			    "Can't allocate memory");
6673231200Smm			return (ARCHIVE_FATAL);
6674231200Smm		}
6675231200Smm		/* Add "rr_moved" entry to the root entry. */
6676231200Smm		isoent_add_child_head(rootent, rrmoved);
6677231200Smm		archive_entry_set_nlink(rootent->file->entry,
6678231200Smm		    archive_entry_nlink(rootent->file->entry) + 1);
6679231200Smm		/* Register "rr_moved" entry to second level pathtable. */
6680231200Smm		path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);
6681231200Smm		/* Save rr_moved. */
6682231200Smm		*rr_moved = rrmoved;
6683231200Smm	}
6684231200Smm	/*
6685238856Smm	 * Make a clone of curent which is going to be relocated
6686231200Smm	 * to rr_moved.
6687231200Smm	 */
6688238856Smm	mvent = isoent_clone(curent);
6689231200Smm	if (mvent == NULL) {
6690231200Smm		archive_set_error(&a->archive, ENOMEM,
6691231200Smm		    "Can't allocate memory");
6692231200Smm		return (ARCHIVE_FATAL);
6693231200Smm	}
6694231200Smm	/* linking..  and use for creating "CL", "PL" and "RE" */
6695238856Smm	mvent->rr_parent = curent->parent;
6696238856Smm	curent->rr_child = mvent;
6697231200Smm	/*
6698238856Smm	 * Move subdirectories from the curent to mvent
6699231200Smm	 */
6700238856Smm	if (curent->children.first != NULL) {
6701238856Smm		*mvent->children.last = curent->children.first;
6702238856Smm		mvent->children.last = curent->children.last;
6703231200Smm	}
6704231200Smm	for (np = mvent->children.first; np != NULL; np = np->chnext)
6705231200Smm		np->parent = mvent;
6706238856Smm	mvent->children.cnt = curent->children.cnt;
6707238856Smm	curent->children.cnt = 0;
6708238856Smm	curent->children.first = NULL;
6709238856Smm	curent->children.last = &curent->children.first;
6710231200Smm
6711238856Smm	if (curent->subdirs.first != NULL) {
6712238856Smm		*mvent->subdirs.last = curent->subdirs.first;
6713238856Smm		mvent->subdirs.last = curent->subdirs.last;
6714231200Smm	}
6715238856Smm	mvent->subdirs.cnt = curent->subdirs.cnt;
6716238856Smm	curent->subdirs.cnt = 0;
6717238856Smm	curent->subdirs.first = NULL;
6718238856Smm	curent->subdirs.last = &curent->subdirs.first;
6719231200Smm
6720231200Smm	/*
6721231200Smm	 * The mvent becomes a child of the rr_moved entry.
6722231200Smm	 */
6723231200Smm	isoent_add_child_tail(rrmoved, mvent);
6724231200Smm	archive_entry_set_nlink(rrmoved->file->entry,
6725231200Smm	    archive_entry_nlink(rrmoved->file->entry) + 1);
6726231200Smm	/*
6727231200Smm	 * This entry which relocated to the rr_moved directory
6728231200Smm	 * has to set the flag as a file.
6729231200Smm	 * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
6730231200Smm	 */
6731238856Smm	curent->dir = 0;
6732231200Smm
6733231200Smm	*newent = mvent;
6734231200Smm
6735231200Smm	return (ARCHIVE_OK);
6736231200Smm}
6737231200Smm
6738231200Smmstatic int
6739231200Smmisoent_rr_move(struct archive_write *a)
6740231200Smm{
6741231200Smm	struct iso9660 *iso9660 = a->format_data;
6742231200Smm	struct path_table *pt;
6743231200Smm	struct isoent *rootent, *rr_moved;
6744231200Smm	struct isoent *np, *last;
6745231200Smm	int r;
6746231200Smm
6747231200Smm	pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
6748311042Smm	/* There aren't level 8 directories reaching a deeper level. */
6749231200Smm	if (pt->cnt == 0)
6750231200Smm		return (ARCHIVE_OK);
6751231200Smm
6752231200Smm	rootent = iso9660->primary.rootent;
6753231200Smm	/* If "rr_moved" directory is already existing,
6754231200Smm	 * we have to use it. */
6755231200Smm	rr_moved = isoent_find_child(rootent, "rr_moved");
6756231200Smm	if (rr_moved != NULL &&
6757231200Smm	    rr_moved != rootent->children.first) {
6758231200Smm		/*
6759231200Smm		 * It's necessary that rr_move is the first entry
6760231200Smm		 * of the root.
6761231200Smm		 */
6762231200Smm		/* Remove "rr_moved" entry from children chain. */
6763231200Smm		isoent_remove_child(rootent, rr_moved);
6764231200Smm
6765231200Smm		/* Add "rr_moved" entry into the head of children chain. */
6766231200Smm		isoent_add_child_head(rootent, rr_moved);
6767231200Smm	}
6768231200Smm
6769231200Smm	/*
6770231200Smm	 * Check level 8 path_table.
6771231200Smm	 * If find out sub directory entries, that entries move to rr_move.
6772231200Smm	 */
6773231200Smm	np = pt->first;
6774231200Smm	while (np != NULL) {
6775231200Smm		last = path_table_last_entry(pt);
6776231200Smm		for (; np != NULL; np = np->ptnext) {
6777231200Smm			struct isoent *mvent;
6778231200Smm			struct isoent *newent;
6779231200Smm
6780231200Smm			if (!np->dir)
6781231200Smm				continue;
6782231200Smm			for (mvent = np->subdirs.first;
6783231200Smm			    mvent != NULL; mvent = mvent->drnext) {
6784231200Smm				r = isoent_rr_move_dir(a, &rr_moved,
6785231200Smm				    mvent, &newent);
6786231200Smm				if (r < 0)
6787231200Smm					return (r);
6788231200Smm				isoent_collect_dirs(&(iso9660->primary),
6789231200Smm				    newent, 2);
6790231200Smm			}
6791231200Smm		}
6792231200Smm		/* If new entries are added to level 8 path_talbe,
6793231200Smm		 * its sub directory entries move to rr_move too.
6794231200Smm		 */
6795231200Smm		np = last->ptnext;
6796231200Smm	}
6797231200Smm
6798231200Smm	return (ARCHIVE_OK);
6799231200Smm}
6800231200Smm
6801231200Smm/*
6802231200Smm * This comparing rule is according to ISO9660 Standard 6.9.1
6803231200Smm */
6804231200Smmstatic int
6805231200Smm_compare_path_table(const void *v1, const void *v2)
6806231200Smm{
6807231200Smm	const struct isoent *p1, *p2;
6808231200Smm	const char *s1, *s2;
6809231200Smm	int cmp, l;
6810231200Smm
6811231200Smm	p1 = *((const struct isoent **)(uintptr_t)v1);
6812231200Smm	p2 = *((const struct isoent **)(uintptr_t)v2);
6813231200Smm
6814231200Smm	/* Compare parent directory number */
6815231200Smm	cmp = p1->parent->dir_number - p2->parent->dir_number;
6816231200Smm	if (cmp != 0)
6817231200Smm		return (cmp);
6818231200Smm
6819311042Smm	/* Compare identifier */
6820231200Smm	s1 = p1->identifier;
6821231200Smm	s2 = p2->identifier;
6822231200Smm	l = p1->ext_off;
6823231200Smm	if (l > p2->ext_off)
6824231200Smm		l = p2->ext_off;
6825231200Smm	cmp = strncmp(s1, s2, l);
6826231200Smm	if (cmp != 0)
6827231200Smm		return (cmp);
6828231200Smm	if (p1->ext_off < p2->ext_off) {
6829231200Smm		s2 += l;
6830231200Smm		l = p2->ext_off - p1->ext_off;
6831231200Smm		while (l--)
6832231200Smm			if (0x20 != *s2++)
6833231200Smm				return (0x20
6834231200Smm				    - *(const unsigned char *)(s2 - 1));
6835231200Smm	} else if (p1->ext_off > p2->ext_off) {
6836231200Smm		s1 += l;
6837231200Smm		l = p1->ext_off - p2->ext_off;
6838231200Smm		while (l--)
6839231200Smm			if (0x20 != *s1++)
6840231200Smm				return (*(const unsigned char *)(s1 - 1)
6841231200Smm				    - 0x20);
6842231200Smm	}
6843231200Smm	return (0);
6844231200Smm}
6845231200Smm
6846231200Smmstatic int
6847231200Smm_compare_path_table_joliet(const void *v1, const void *v2)
6848231200Smm{
6849231200Smm	const struct isoent *p1, *p2;
6850231200Smm	const unsigned char *s1, *s2;
6851231200Smm	int cmp, l;
6852231200Smm
6853231200Smm	p1 = *((const struct isoent **)(uintptr_t)v1);
6854231200Smm	p2 = *((const struct isoent **)(uintptr_t)v2);
6855231200Smm
6856231200Smm	/* Compare parent directory number */
6857231200Smm	cmp = p1->parent->dir_number - p2->parent->dir_number;
6858231200Smm	if (cmp != 0)
6859231200Smm		return (cmp);
6860231200Smm
6861311042Smm	/* Compare identifier */
6862231200Smm	s1 = (const unsigned char *)p1->identifier;
6863231200Smm	s2 = (const unsigned char *)p2->identifier;
6864231200Smm	l = p1->ext_off;
6865231200Smm	if (l > p2->ext_off)
6866231200Smm		l = p2->ext_off;
6867231200Smm	cmp = memcmp(s1, s2, l);
6868231200Smm	if (cmp != 0)
6869231200Smm		return (cmp);
6870231200Smm	if (p1->ext_off < p2->ext_off) {
6871231200Smm		s2 += l;
6872231200Smm		l = p2->ext_off - p1->ext_off;
6873231200Smm		while (l--)
6874231200Smm			if (0 != *s2++)
6875231200Smm				return (- *(const unsigned char *)(s2 - 1));
6876231200Smm	} else if (p1->ext_off > p2->ext_off) {
6877231200Smm		s1 += l;
6878231200Smm		l = p1->ext_off - p2->ext_off;
6879231200Smm		while (l--)
6880231200Smm			if (0 != *s1++)
6881231200Smm				return (*(const unsigned char *)(s1 - 1));
6882231200Smm	}
6883231200Smm	return (0);
6884231200Smm}
6885231200Smm
6886231200Smmstatic inline void
6887231200Smmpath_table_add_entry(struct path_table *pathtbl, struct isoent *ent)
6888231200Smm{
6889231200Smm	ent->ptnext = NULL;
6890231200Smm	*pathtbl->last = ent;
6891231200Smm	pathtbl->last = &(ent->ptnext);
6892231200Smm	pathtbl->cnt ++;
6893231200Smm}
6894231200Smm
6895231200Smmstatic inline struct isoent *
6896231200Smmpath_table_last_entry(struct path_table *pathtbl)
6897231200Smm{
6898231200Smm	if (pathtbl->first == NULL)
6899231200Smm		return (NULL);
6900231200Smm	return (((struct isoent *)(void *)
6901231200Smm		((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));
6902231200Smm}
6903231200Smm
6904231200Smm/*
6905231200Smm * Sort directory entries in path_table
6906231200Smm * and assign directory number to each entries.
6907231200Smm */
6908231200Smmstatic int
6909231200Smmisoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
6910231200Smm    int depth, int *dir_number)
6911231200Smm{
6912231200Smm	struct isoent *np;
6913231200Smm	struct isoent **enttbl;
6914231200Smm	struct path_table *pt;
6915231200Smm	int i;
6916231200Smm
6917231200Smm	pt = &vdd->pathtbl[depth];
6918231200Smm	if (pt->cnt == 0) {
6919231200Smm		pt->sorted = NULL;
6920231200Smm		return (ARCHIVE_OK);
6921231200Smm	}
6922231200Smm	enttbl = malloc(pt->cnt * sizeof(struct isoent *));
6923231200Smm	if (enttbl == NULL) {
6924231200Smm		archive_set_error(&a->archive, ENOMEM,
6925231200Smm		    "Can't allocate memory");
6926231200Smm		return (ARCHIVE_FATAL);
6927231200Smm	}
6928231200Smm	pt->sorted = enttbl;
6929231200Smm	for (np = pt->first; np != NULL; np = np->ptnext)
6930231200Smm		*enttbl ++ = np;
6931231200Smm	enttbl = pt->sorted;
6932231200Smm
6933231200Smm	switch (vdd->vdd_type) {
6934231200Smm	case VDD_PRIMARY:
6935231200Smm	case VDD_ENHANCED:
6936248616Smm#ifdef __COMPAR_FN_T
6937231200Smm		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6938248616Smm		    (__compar_fn_t)_compare_path_table);
6939248616Smm#else
6940248616Smm		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6941231200Smm		    _compare_path_table);
6942248616Smm#endif
6943231200Smm		break;
6944231200Smm	case VDD_JOLIET:
6945248616Smm#ifdef __COMPAR_FN_T
6946231200Smm		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6947248616Smm		    (__compar_fn_t)_compare_path_table_joliet);
6948248616Smm#else
6949248616Smm		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6950231200Smm		    _compare_path_table_joliet);
6951248616Smm#endif
6952231200Smm		break;
6953231200Smm	}
6954231200Smm	for (i = 0; i < pt->cnt; i++)
6955231200Smm		enttbl[i]->dir_number = (*dir_number)++;
6956231200Smm
6957231200Smm	return (ARCHIVE_OK);
6958231200Smm}
6959231200Smm
6960231200Smmstatic int
6961231200Smmisoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,
6962231200Smm    int max_depth)
6963231200Smm{
6964231200Smm	int i;
6965231200Smm
6966231200Smm	vdd->max_depth = max_depth;
6967231200Smm	vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);
6968231200Smm	if (vdd->pathtbl == NULL) {
6969231200Smm		archive_set_error(&a->archive, ENOMEM,
6970231200Smm		    "Can't allocate memory");
6971231200Smm		return (ARCHIVE_FATAL);
6972231200Smm	}
6973231200Smm	for (i = 0; i < vdd->max_depth; i++) {
6974231200Smm		vdd->pathtbl[i].first = NULL;
6975231200Smm		vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);
6976231200Smm		vdd->pathtbl[i].sorted = NULL;
6977231200Smm		vdd->pathtbl[i].cnt = 0;
6978231200Smm	}
6979231200Smm	return (ARCHIVE_OK);
6980231200Smm}
6981231200Smm
6982231200Smm/*
6983231200Smm * Make Path Tables
6984231200Smm */
6985231200Smmstatic int
6986231200Smmisoent_make_path_table(struct archive_write *a)
6987231200Smm{
6988231200Smm	struct iso9660 *iso9660 = a->format_data;
6989231200Smm	int depth, r;
6990231200Smm	int dir_number;
6991231200Smm
6992231200Smm	/*
6993231200Smm	 * Init Path Table.
6994231200Smm	 */
6995231200Smm	if (iso9660->dircnt_max >= MAX_DEPTH &&
6996231200Smm	    (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))
6997231200Smm		r = isoent_alloc_path_table(a, &(iso9660->primary),
6998231200Smm		    iso9660->dircnt_max + 1);
6999231200Smm	else
7000231200Smm		/* The number of levels in the hierarchy cannot exceed
7001231200Smm		 * eight. */
7002231200Smm		r = isoent_alloc_path_table(a, &(iso9660->primary),
7003231200Smm		    MAX_DEPTH);
7004231200Smm	if (r < 0)
7005231200Smm		return (r);
7006231200Smm	if (iso9660->opt.joliet) {
7007231200Smm		r = isoent_alloc_path_table(a, &(iso9660->joliet),
7008231200Smm		    iso9660->dircnt_max + 1);
7009231200Smm		if (r < 0)
7010231200Smm			return (r);
7011231200Smm	}
7012231200Smm
7013231200Smm	/* Step 0.
7014231200Smm	 * - Collect directories for primary and joliet.
7015231200Smm	 */
7016231200Smm	isoent_collect_dirs(&(iso9660->primary), NULL, 0);
7017231200Smm	if (iso9660->opt.joliet)
7018231200Smm		isoent_collect_dirs(&(iso9660->joliet), NULL, 0);
7019231200Smm	/*
7020231200Smm	 * Rockridge; move deeper depth directories to rr_moved.
7021231200Smm	 */
7022231200Smm	if (iso9660->opt.rr) {
7023231200Smm		r = isoent_rr_move(a);
7024231200Smm		if (r < 0)
7025231200Smm			return (r);
7026231200Smm	}
7027231200Smm
7028231200Smm 	/* Update nlink. */
7029231200Smm	isofile_connect_hardlink_files(iso9660);
7030231200Smm
7031231200Smm	/* Step 1.
7032231200Smm	 * - Renew a value of the depth of that directories.
7033231200Smm	 * - Resolve hardlinks.
7034231200Smm 	 * - Convert pathnames to ISO9660 name or UCS2(joliet).
7035231200Smm	 * - Sort files by each directory.
7036231200Smm	 */
7037231200Smm	r = isoent_traverse_tree(a, &(iso9660->primary));
7038231200Smm	if (r < 0)
7039231200Smm		return (r);
7040231200Smm	if (iso9660->opt.joliet) {
7041231200Smm		r = isoent_traverse_tree(a, &(iso9660->joliet));
7042231200Smm		if (r < 0)
7043231200Smm			return (r);
7044231200Smm	}
7045231200Smm
7046231200Smm	/* Step 2.
7047231200Smm	 * - Sort directories.
7048231200Smm	 * - Assign all directory number.
7049231200Smm	 */
7050231200Smm	dir_number = 1;
7051231200Smm	for (depth = 0; depth < iso9660->primary.max_depth; depth++) {
7052231200Smm		r = isoent_make_path_table_2(a, &(iso9660->primary),
7053231200Smm		    depth, &dir_number);
7054231200Smm		if (r < 0)
7055231200Smm			return (r);
7056231200Smm	}
7057231200Smm	if (iso9660->opt.joliet) {
7058231200Smm		dir_number = 1;
7059231200Smm		for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {
7060231200Smm			r = isoent_make_path_table_2(a, &(iso9660->joliet),
7061231200Smm			    depth, &dir_number);
7062231200Smm			if (r < 0)
7063231200Smm				return (r);
7064231200Smm		}
7065231200Smm	}
7066231200Smm	if (iso9660->opt.limit_dirs && dir_number > 0xffff) {
7067231200Smm		/*
7068231200Smm		 * Maximum number of directories is 65535(0xffff)
7069231200Smm		 * doe to size(16bit) of Parent Directory Number of
7070231200Smm		 * the Path Table.
7071231200Smm		 * See also ISO9660 Standard 9.4.
7072231200Smm		 */
7073231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7074231200Smm		    "Too many directories(%d) over 65535.", dir_number);
7075231200Smm		return (ARCHIVE_FATAL);
7076231200Smm	}
7077231200Smm
7078231200Smm	/* Get the size of the Path Table. */
7079231200Smm	calculate_path_table_size(&(iso9660->primary));
7080231200Smm	if (iso9660->opt.joliet)
7081231200Smm		calculate_path_table_size(&(iso9660->joliet));
7082231200Smm
7083231200Smm	return (ARCHIVE_OK);
7084231200Smm}
7085231200Smm
7086231200Smmstatic int
7087231200Smmisoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)
7088231200Smm{
7089231200Smm	struct iso9660 *iso9660 = a->format_data;
7090231200Smm
7091231200Smm	/* Find a isoent of the boot file. */
7092231200Smm	iso9660->el_torito.boot = isoent_find_entry(rootent,
7093231200Smm	    iso9660->el_torito.boot_filename.s);
7094231200Smm	if (iso9660->el_torito.boot == NULL) {
7095231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7096231200Smm		    "Can't find the boot image file ``%s''",
7097231200Smm		    iso9660->el_torito.boot_filename.s);
7098231200Smm		return (ARCHIVE_FATAL);
7099231200Smm	}
7100231200Smm	iso9660->el_torito.boot->file->boot = BOOT_IMAGE;
7101231200Smm	return (ARCHIVE_OK);
7102231200Smm}
7103231200Smm
7104231200Smmstatic int
7105231200Smmisoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
7106231200Smm{
7107231200Smm	struct iso9660 *iso9660 = a->format_data;
7108231200Smm	struct isofile *file;
7109231200Smm	struct isoent *isoent;
7110231200Smm	struct archive_entry *entry;
7111231200Smm
7112231200Smm	(void)rootent; /* UNUSED */
7113231200Smm	/*
7114231200Smm	 * Create the entry which is the "boot.catalog" file.
7115231200Smm	 */
7116231200Smm	file = isofile_new(a, NULL);
7117231200Smm	if (file == NULL) {
7118231200Smm		archive_set_error(&a->archive, ENOMEM,
7119231200Smm		    "Can't allocate memory");
7120231200Smm		return (ARCHIVE_FATAL);
7121231200Smm	}
7122231200Smm	archive_entry_set_pathname(file->entry,
7123231200Smm	    iso9660->el_torito.catalog_filename.s);
7124231200Smm	archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);
7125231200Smm	archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);
7126231200Smm	archive_entry_set_atime(file->entry, iso9660->birth_time, 0);
7127231200Smm	archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);
7128231200Smm	archive_entry_set_uid(file->entry, getuid());
7129231200Smm	archive_entry_set_gid(file->entry, getgid());
7130231200Smm	archive_entry_set_mode(file->entry, AE_IFREG | 0444);
7131231200Smm	archive_entry_set_nlink(file->entry, 1);
7132231200Smm
7133231200Smm	if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
7134231200Smm		isofile_free(file);
7135231200Smm		return (ARCHIVE_FATAL);
7136231200Smm	}
7137231200Smm	file->boot = BOOT_CATALOG;
7138231200Smm	file->content.size = LOGICAL_BLOCK_SIZE;
7139231200Smm	isofile_add_entry(iso9660, file);
7140231200Smm
7141231200Smm	isoent = isoent_new(file);
7142231200Smm	if (isoent == NULL) {
7143231200Smm		archive_set_error(&a->archive, ENOMEM,
7144231200Smm		    "Can't allocate memory");
7145231200Smm		return (ARCHIVE_FATAL);
7146231200Smm	}
7147231200Smm	isoent->virtual = 1;
7148231200Smm
7149231200Smm	/* Add the "boot.catalog" entry into tree */
7150231200Smm	if (isoent_tree(a, &isoent) != ARCHIVE_OK)
7151231200Smm		return (ARCHIVE_FATAL);
7152231200Smm
7153231200Smm	iso9660->el_torito.catalog = isoent;
7154231200Smm	/*
7155313571Smm	 * Get a boot media type.
7156231200Smm	 */
7157231200Smm	switch (iso9660->opt.boot_type) {
7158231200Smm	default:
7159231200Smm	case OPT_BOOT_TYPE_AUTO:
7160231200Smm		/* Try detecting a media type of the boot image. */
7161231200Smm		entry = iso9660->el_torito.boot->file->entry;
7162231200Smm		if (archive_entry_size(entry) == FD_1_2M_SIZE)
7163231200Smm			iso9660->el_torito.media_type =
7164231200Smm			    BOOT_MEDIA_1_2M_DISKETTE;
7165231200Smm		else if (archive_entry_size(entry) == FD_1_44M_SIZE)
7166231200Smm			iso9660->el_torito.media_type =
7167231200Smm			    BOOT_MEDIA_1_44M_DISKETTE;
7168231200Smm		else if (archive_entry_size(entry) == FD_2_88M_SIZE)
7169231200Smm			iso9660->el_torito.media_type =
7170231200Smm			    BOOT_MEDIA_2_88M_DISKETTE;
7171231200Smm		else
7172231200Smm			/* We cannot decide whether the boot image is
7173231200Smm			 * hard-disk. */
7174231200Smm			iso9660->el_torito.media_type =
7175231200Smm			    BOOT_MEDIA_NO_EMULATION;
7176231200Smm		break;
7177231200Smm	case OPT_BOOT_TYPE_NO_EMU:
7178231200Smm		iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;
7179231200Smm		break;
7180231200Smm	case OPT_BOOT_TYPE_HARD_DISK:
7181231200Smm		iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;
7182231200Smm		break;
7183231200Smm	case OPT_BOOT_TYPE_FD:
7184231200Smm		entry = iso9660->el_torito.boot->file->entry;
7185231200Smm		if (archive_entry_size(entry) <= FD_1_2M_SIZE)
7186231200Smm			iso9660->el_torito.media_type =
7187231200Smm			    BOOT_MEDIA_1_2M_DISKETTE;
7188231200Smm		else if (archive_entry_size(entry) <= FD_1_44M_SIZE)
7189231200Smm			iso9660->el_torito.media_type =
7190231200Smm			    BOOT_MEDIA_1_44M_DISKETTE;
7191231200Smm		else if (archive_entry_size(entry) <= FD_2_88M_SIZE)
7192231200Smm			iso9660->el_torito.media_type =
7193231200Smm			    BOOT_MEDIA_2_88M_DISKETTE;
7194231200Smm		else {
7195231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7196231200Smm			    "Boot image file(``%s'') size is too big "
7197231200Smm			    "for fd type.",
7198231200Smm			    iso9660->el_torito.boot_filename.s);
7199231200Smm			return (ARCHIVE_FATAL);
7200231200Smm		}
7201231200Smm		break;
7202231200Smm	}
7203231200Smm
7204231200Smm	/*
7205231200Smm	 * Get a system type.
7206231200Smm	 * TODO: `El Torito' specification says "A copy of byte 5 from the
7207231200Smm	 *       Partition Table found in the boot image".
7208231200Smm	 */
7209231200Smm	iso9660->el_torito.system_type = 0;
7210231200Smm
7211231200Smm	/*
7212231200Smm	 * Get an ID.
7213231200Smm	 */
7214231200Smm	if (iso9660->opt.publisher)
7215231200Smm		archive_string_copy(&(iso9660->el_torito.id),
7216231200Smm		    &(iso9660->publisher_identifier));
7217231200Smm
7218231200Smm
7219231200Smm	return (ARCHIVE_OK);
7220231200Smm}
7221231200Smm
7222231200Smm/*
7223231200Smm * If a media type is floppy, return its image size.
7224231200Smm * otherwise return 0.
7225231200Smm */
7226231200Smmstatic size_t
7227231200Smmfd_boot_image_size(int media_type)
7228231200Smm{
7229231200Smm	switch (media_type) {
7230231200Smm	case BOOT_MEDIA_1_2M_DISKETTE:
7231231200Smm		return (FD_1_2M_SIZE);
7232231200Smm	case BOOT_MEDIA_1_44M_DISKETTE:
7233231200Smm		return (FD_1_44M_SIZE);
7234231200Smm	case BOOT_MEDIA_2_88M_DISKETTE:
7235231200Smm		return (FD_2_88M_SIZE);
7236231200Smm	default:
7237231200Smm		return (0);
7238231200Smm	}
7239231200Smm}
7240231200Smm
7241231200Smm/*
7242231200Smm * Make a boot catalog image data.
7243231200Smm */
7244231200Smmstatic int
7245231200Smmmake_boot_catalog(struct archive_write *a)
7246231200Smm{
7247231200Smm	struct iso9660 *iso9660 = a->format_data;
7248231200Smm	unsigned char *block;
7249231200Smm	unsigned char *p;
7250231200Smm	uint16_t sum, *wp;
7251231200Smm
7252231200Smm	block = wb_buffptr(a);
7253231200Smm	memset(block, 0, LOGICAL_BLOCK_SIZE);
7254231200Smm	p = block;
7255231200Smm	/*
7256231200Smm	 * Validation Entry
7257231200Smm	 */
7258231200Smm	/* Header ID */
7259231200Smm	p[0] = 1;
7260231200Smm	/* Platform ID */
7261231200Smm	p[1] = iso9660->el_torito.platform_id;
7262231200Smm	/* Reserved */
7263231200Smm	p[2] = p[3] = 0;
7264231200Smm	/* ID */
7265231200Smm	if (archive_strlen(&(iso9660->el_torito.id)) > 0)
7266231200Smm		strncpy((char *)p+4, iso9660->el_torito.id.s, 23);
7267231200Smm	p[27] = 0;
7268231200Smm	/* Checksum */
7269231200Smm	p[28] = p[29] = 0;
7270231200Smm	/* Key */
7271231200Smm	p[30] = 0x55;
7272231200Smm	p[31] = 0xAA;
7273231200Smm
7274231200Smm	sum = 0;
7275231200Smm	wp = (uint16_t *)block;
7276231200Smm	while (wp < (uint16_t *)&block[32])
7277231200Smm		sum += archive_le16dec(wp++);
7278231200Smm	set_num_721(&block[28], (~sum) + 1);
7279231200Smm
7280231200Smm	/*
7281231200Smm	 * Initial/Default Entry
7282231200Smm	 */
7283231200Smm	p = &block[32];
7284231200Smm	/* Boot Indicator */
7285231200Smm	p[0] = 0x88;
7286231200Smm	/* Boot media type */
7287231200Smm	p[1] = iso9660->el_torito.media_type;
7288231200Smm	/* Load Segment */
7289231200Smm	if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
7290231200Smm		set_num_721(&p[2], iso9660->el_torito.boot_load_seg);
7291231200Smm	else
7292231200Smm		set_num_721(&p[2], 0);
7293231200Smm	/* System Type */
7294231200Smm	p[4] = iso9660->el_torito.system_type;
7295231200Smm	/* Unused */
7296231200Smm	p[5] = 0;
7297231200Smm	/* Sector Count */
7298231200Smm	if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
7299231200Smm		set_num_721(&p[6], iso9660->el_torito.boot_load_size);
7300231200Smm	else
7301231200Smm		set_num_721(&p[6], 1);
7302231200Smm	/* Load RBA */
7303231200Smm	set_num_731(&p[8],
7304231200Smm	    iso9660->el_torito.boot->file->content.location);
7305231200Smm	/* Unused */
7306231200Smm	memset(&p[12], 0, 20);
7307231200Smm
7308231200Smm	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
7309231200Smm}
7310231200Smm
7311231200Smmstatic int
7312231200Smmsetup_boot_information(struct archive_write *a)
7313231200Smm{
7314231200Smm	struct iso9660 *iso9660 = a->format_data;
7315231200Smm	struct isoent *np;
7316231200Smm	int64_t size;
7317231200Smm	uint32_t sum;
7318231200Smm	unsigned char buff[4096];
7319231200Smm
7320231200Smm	np = iso9660->el_torito.boot;
7321231200Smm	lseek(iso9660->temp_fd,
7322231200Smm	    np->file->content.offset_of_temp + 64, SEEK_SET);
7323231200Smm	size = archive_entry_size(np->file->entry) - 64;
7324231200Smm	if (size <= 0) {
7325231200Smm		archive_set_error(&a->archive, errno,
7326231200Smm		    "Boot file(%jd) is too small", (intmax_t)size + 64);
7327231200Smm		return (ARCHIVE_FATAL);
7328231200Smm	}
7329231200Smm	sum = 0;
7330231200Smm	while (size > 0) {
7331231200Smm		size_t rsize;
7332231200Smm		ssize_t i, rs;
7333231200Smm
7334232153Smm		if (size > (int64_t)sizeof(buff))
7335231200Smm			rsize = sizeof(buff);
7336231200Smm		else
7337231200Smm			rsize = (size_t)size;
7338231200Smm
7339231200Smm		rs = read(iso9660->temp_fd, buff, rsize);
7340231200Smm		if (rs <= 0) {
7341231200Smm			archive_set_error(&a->archive, errno,
7342231200Smm			    "Can't read temporary file(%jd)",
7343231200Smm			    (intmax_t)rs);
7344231200Smm			return (ARCHIVE_FATAL);
7345231200Smm		}
7346231200Smm		for (i = 0; i < rs; i += 4)
7347231200Smm			sum += archive_le32dec(buff + i);
7348231200Smm		size -= rs;
7349231200Smm	}
7350231200Smm	/* Set the location of Primary Volume Descriptor. */
7351231200Smm	set_num_731(buff, SYSTEM_AREA_BLOCK);
7352231200Smm	/* Set the location of the boot file. */
7353231200Smm	set_num_731(buff+4, np->file->content.location);
7354231200Smm	/* Set the size of the boot file. */
7355231200Smm	size = fd_boot_image_size(iso9660->el_torito.media_type);
7356231200Smm	if (size == 0)
7357231200Smm		size = archive_entry_size(np->file->entry);
7358231200Smm	set_num_731(buff+8, (uint32_t)size);
7359231200Smm	/* Set the sum of the boot file. */
7360231200Smm	set_num_731(buff+12, sum);
7361231200Smm	/* Clear reserved bytes. */
7362231200Smm	memset(buff+16, 0, 40);
7363231200Smm
7364231200Smm	/* Overwrite the boot file. */
7365231200Smm	lseek(iso9660->temp_fd,
7366231200Smm	    np->file->content.offset_of_temp + 8, SEEK_SET);
7367231200Smm	return (write_to_temp(a, buff, 56));
7368231200Smm}
7369231200Smm
7370231200Smm#ifdef HAVE_ZLIB_H
7371231200Smm
7372231200Smmstatic int
7373231200Smmzisofs_init_zstream(struct archive_write *a)
7374231200Smm{
7375231200Smm	struct iso9660 *iso9660 = a->format_data;
7376231200Smm	int r;
7377231200Smm
7378231200Smm	iso9660->zisofs.stream.next_in = NULL;
7379231200Smm	iso9660->zisofs.stream.avail_in = 0;
7380231200Smm	iso9660->zisofs.stream.total_in = 0;
7381231200Smm	iso9660->zisofs.stream.total_out = 0;
7382231200Smm	if (iso9660->zisofs.stream_valid)
7383231200Smm		r = deflateReset(&(iso9660->zisofs.stream));
7384231200Smm	else {
7385231200Smm		r = deflateInit(&(iso9660->zisofs.stream),
7386231200Smm		    iso9660->zisofs.compression_level);
7387231200Smm		iso9660->zisofs.stream_valid = 1;
7388231200Smm	}
7389231200Smm	switch (r) {
7390231200Smm	case Z_OK:
7391231200Smm		break;
7392231200Smm	default:
7393231200Smm	case Z_STREAM_ERROR:
7394231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7395231200Smm		    "Internal error initializing "
7396231200Smm		    "compression library: invalid setup parameter");
7397231200Smm		return (ARCHIVE_FATAL);
7398231200Smm	case Z_MEM_ERROR:
7399231200Smm		archive_set_error(&a->archive, ENOMEM,
7400231200Smm		    "Internal error initializing "
7401231200Smm		    "compression library");
7402231200Smm		return (ARCHIVE_FATAL);
7403231200Smm	case Z_VERSION_ERROR:
7404231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7405231200Smm		    "Internal error initializing "
7406231200Smm		    "compression library: invalid library version");
7407231200Smm		return (ARCHIVE_FATAL);
7408231200Smm	}
7409231200Smm	return (ARCHIVE_OK);
7410231200Smm}
7411231200Smm
7412231200Smm#endif /* HAVE_ZLIB_H */
7413231200Smm
7414231200Smmstatic int
7415231200Smmzisofs_init(struct archive_write *a,  struct isofile *file)
7416231200Smm{
7417231200Smm	struct iso9660 *iso9660 = a->format_data;
7418231200Smm#ifdef HAVE_ZLIB_H
7419231200Smm	uint64_t tsize;
7420248616Smm	size_t _ceil, bpsize;
7421231200Smm	int r;
7422231200Smm#endif
7423231200Smm
7424231200Smm	iso9660->zisofs.detect_magic = 0;
7425231200Smm	iso9660->zisofs.making = 0;
7426231200Smm
7427231200Smm	if (!iso9660->opt.rr || !iso9660->opt.zisofs)
7428231200Smm		return (ARCHIVE_OK);
7429231200Smm
7430231200Smm	if (archive_entry_size(file->entry) >= 24 &&
7431231200Smm	    archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {
7432231200Smm		/* Acceptable file size for zisofs. */
7433231200Smm		iso9660->zisofs.detect_magic = 1;
7434231200Smm		iso9660->zisofs.magic_cnt = 0;
7435231200Smm	}
7436231200Smm	if (!iso9660->zisofs.detect_magic)
7437231200Smm		return (ARCHIVE_OK);
7438231200Smm
7439231200Smm#ifdef HAVE_ZLIB_H
7440231200Smm	/* The number of Logical Blocks which uncompressed data
7441231200Smm	 * will use in iso-image file is the same as the number of
7442231200Smm	 * Logical Blocks which zisofs(compressed) data will use
7443231200Smm	 * in ISO-image file. It won't reduce iso-image file size. */
7444231200Smm	if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)
7445231200Smm		return (ARCHIVE_OK);
7446231200Smm
7447231200Smm	/* Initialize compression library */
7448231200Smm	r = zisofs_init_zstream(a);
7449231200Smm	if (r != ARCHIVE_OK)
7450231200Smm		return (ARCHIVE_FATAL);
7451231200Smm
7452231200Smm	/* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
7453231200Smm	file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
7454231200Smm	file->zisofs.log2_bs = ZF_LOG2_BS;
7455238856Smm	file->zisofs.uncompressed_size =
7456238856Smm		(uint32_t)archive_entry_size(file->entry);
7457231200Smm
7458231200Smm	/* Calculate a size of Block Pointers of zisofs. */
7459248616Smm	_ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
7460231200Smm		>> file->zisofs.log2_bs;
7461248616Smm	iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
7462231200Smm	iso9660->zisofs.block_pointers_idx = 0;
7463231200Smm
7464231200Smm	/* Ensure a buffer size used for Block Pointers */
7465231200Smm	bpsize = iso9660->zisofs.block_pointers_cnt *
7466231200Smm	    sizeof(iso9660->zisofs.block_pointers[0]);
7467231200Smm	if (iso9660->zisofs.block_pointers_allocated < bpsize) {
7468231200Smm		free(iso9660->zisofs.block_pointers);
7469231200Smm		iso9660->zisofs.block_pointers = malloc(bpsize);
7470231200Smm		if (iso9660->zisofs.block_pointers == NULL) {
7471231200Smm			archive_set_error(&a->archive, ENOMEM,
7472231200Smm			    "Can't allocate data");
7473231200Smm			return (ARCHIVE_FATAL);
7474231200Smm		}
7475231200Smm		iso9660->zisofs.block_pointers_allocated = bpsize;
7476231200Smm	}
7477231200Smm
7478231200Smm	/*
7479231200Smm	 * Skip zisofs header and Block Pointers, which we will write
7480231200Smm	 * after all compressed data of a file written to the temporary
7481231200Smm	 * file.
7482231200Smm	 */
7483231200Smm	tsize = ZF_HEADER_SIZE + bpsize;
7484238856Smm	if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
7485231200Smm		return (ARCHIVE_FATAL);
7486231200Smm
7487231200Smm	/*
7488231200Smm	 * Initialize some variables to make zisofs.
7489231200Smm	 */
7490238856Smm	archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
7491238856Smm		(uint32_t)tsize);
7492231200Smm	iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
7493231200Smm	iso9660->zisofs.making = 1;
7494231200Smm	iso9660->zisofs.allzero = 1;
7495231200Smm	iso9660->zisofs.block_offset = tsize;
7496231200Smm	iso9660->zisofs.total_size = tsize;
7497231200Smm	iso9660->cur_file->cur_content->size = tsize;
7498231200Smm#endif
7499231200Smm
7500231200Smm	return (ARCHIVE_OK);
7501231200Smm}
7502231200Smm
7503231200Smmstatic void
7504231200Smmzisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
7505231200Smm{
7506231200Smm	struct iso9660 *iso9660 = a->format_data;
7507231200Smm	struct isofile *file = iso9660->cur_file;
7508231200Smm	const unsigned char *p, *endp;
7509231200Smm	const unsigned char *magic_buff;
7510231200Smm	uint32_t uncompressed_size;
7511231200Smm	unsigned char header_size;
7512231200Smm	unsigned char log2_bs;
7513248616Smm	size_t _ceil, doff;
7514231200Smm	uint32_t bst, bed;
7515231200Smm	int magic_max;
7516231200Smm	int64_t entry_size;
7517231200Smm
7518231200Smm	entry_size = archive_entry_size(file->entry);
7519232153Smm	if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
7520238856Smm		magic_max = (int)entry_size;
7521231200Smm	else
7522231200Smm		magic_max = sizeof(iso9660->zisofs.magic_buffer);
7523231200Smm
7524231200Smm	if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)
7525231200Smm		/* It's unnecessary we copy buffer. */
7526231200Smm		magic_buff = buff;
7527231200Smm	else {
7528231200Smm		if (iso9660->zisofs.magic_cnt < magic_max) {
7529231200Smm			size_t l;
7530231200Smm
7531231200Smm			l = sizeof(iso9660->zisofs.magic_buffer)
7532231200Smm			    - iso9660->zisofs.magic_cnt;
7533231200Smm			if (l > s)
7534231200Smm				l = s;
7535231200Smm			memcpy(iso9660->zisofs.magic_buffer
7536231200Smm			    + iso9660->zisofs.magic_cnt, buff, l);
7537248616Smm			iso9660->zisofs.magic_cnt += (int)l;
7538231200Smm			if (iso9660->zisofs.magic_cnt < magic_max)
7539231200Smm				return;
7540231200Smm		}
7541231200Smm		magic_buff = iso9660->zisofs.magic_buffer;
7542231200Smm	}
7543231200Smm	iso9660->zisofs.detect_magic = 0;
7544231200Smm	p = magic_buff;
7545231200Smm
7546231200Smm	/* Check the magic code of zisofs. */
7547231200Smm	if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
7548231200Smm		/* This is not zisofs file which made by mkzftree. */
7549231200Smm		return;
7550231200Smm	p += sizeof(zisofs_magic);
7551231200Smm
7552231200Smm	/* Read a zisofs header. */
7553231200Smm	uncompressed_size = archive_le32dec(p);
7554231200Smm	header_size = p[4];
7555231200Smm	log2_bs = p[5];
7556231200Smm	if (uncompressed_size < 24 || header_size != 4 ||
7557231200Smm	    log2_bs > 30 || log2_bs < 7)
7558231200Smm		return;/* Invalid or not supported header. */
7559231200Smm
7560231200Smm	/* Calculate a size of Block Pointers of zisofs. */
7561248616Smm	_ceil = (uncompressed_size +
7562231200Smm	        (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
7563248616Smm	doff = (_ceil + 1) * 4 + 16;
7564232153Smm	if (entry_size < (int64_t)doff)
7565231200Smm		return;/* Invalid data. */
7566231200Smm
7567231200Smm	/* Check every Block Pointer has valid value. */
7568231200Smm	p = magic_buff + 16;
7569231200Smm	endp = magic_buff + magic_max;
7570248616Smm	while (_ceil && p + 8 <= endp) {
7571231200Smm		bst = archive_le32dec(p);
7572231200Smm		if (bst != doff)
7573231200Smm			return;/* Invalid data. */
7574231200Smm		p += 4;
7575231200Smm		bed = archive_le32dec(p);
7576231200Smm		if (bed < bst || bed > entry_size)
7577231200Smm			return;/* Invalid data. */
7578231200Smm		doff += bed - bst;
7579248616Smm		_ceil--;
7580231200Smm	}
7581231200Smm
7582231200Smm	file->zisofs.uncompressed_size = uncompressed_size;
7583231200Smm	file->zisofs.header_size = header_size;
7584231200Smm	file->zisofs.log2_bs = log2_bs;
7585231200Smm
7586231200Smm	/* Disable making a zisofs image. */
7587231200Smm	iso9660->zisofs.making = 0;
7588231200Smm}
7589231200Smm
7590231200Smm#ifdef HAVE_ZLIB_H
7591231200Smm
7592231200Smm/*
7593231200Smm * Compress data and write it to a temporary file.
7594231200Smm */
7595231200Smmstatic int
7596231200Smmzisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
7597231200Smm{
7598231200Smm	struct iso9660 *iso9660 = a->format_data;
7599231200Smm	struct isofile *file = iso9660->cur_file;
7600231200Smm	const unsigned char *b;
7601231200Smm	z_stream *zstrm;
7602231200Smm	size_t avail, csize;
7603231200Smm	int flush, r;
7604231200Smm
7605231200Smm	zstrm = &(iso9660->zisofs.stream);
7606231200Smm	zstrm->next_out = wb_buffptr(a);
7607248616Smm	zstrm->avail_out = (uInt)wb_remaining(a);
7608231200Smm	b = (const unsigned char *)buff;
7609231200Smm	do {
7610231200Smm		avail = ZF_BLOCK_SIZE - zstrm->total_in;
7611231200Smm		if (s < avail) {
7612231200Smm			avail = s;
7613231200Smm			flush = Z_NO_FLUSH;
7614231200Smm		} else
7615231200Smm			flush = Z_FINISH;
7616231200Smm		iso9660->zisofs.remaining -= avail;
7617231200Smm		if (iso9660->zisofs.remaining <= 0)
7618231200Smm			flush = Z_FINISH;
7619231200Smm
7620231200Smm		zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
7621248616Smm		zstrm->avail_in = (uInt)avail;
7622231200Smm
7623231200Smm		/*
7624231200Smm		 * Check if current data block are all zero.
7625231200Smm		 */
7626231200Smm		if (iso9660->zisofs.allzero) {
7627231200Smm			const unsigned char *nonzero = b;
7628231200Smm			const unsigned char *nonzeroend = b + avail;
7629231200Smm
7630231200Smm			while (nonzero < nonzeroend)
7631231200Smm				if (*nonzero++) {
7632231200Smm					iso9660->zisofs.allzero = 0;
7633231200Smm					break;
7634231200Smm				}
7635231200Smm		}
7636231200Smm		b += avail;
7637231200Smm		s -= avail;
7638231200Smm
7639231200Smm		/*
7640231200Smm		 * If current data block are all zero, we do not use
7641231200Smm		 * compressed data.
7642231200Smm		 */
7643231200Smm		if (flush == Z_FINISH && iso9660->zisofs.allzero &&
7644231200Smm		    avail + zstrm->total_in == ZF_BLOCK_SIZE) {
7645231200Smm			if (iso9660->zisofs.block_offset !=
7646231200Smm			    file->cur_content->size) {
7647231200Smm				int64_t diff;
7648231200Smm
7649231200Smm				r = wb_set_offset(a,
7650231200Smm				    file->cur_content->offset_of_temp +
7651231200Smm				        iso9660->zisofs.block_offset);
7652231200Smm				if (r != ARCHIVE_OK)
7653231200Smm					return (r);
7654231200Smm				diff = file->cur_content->size -
7655231200Smm				    iso9660->zisofs.block_offset;
7656231200Smm				file->cur_content->size -= diff;
7657231200Smm				iso9660->zisofs.total_size -= diff;
7658231200Smm			}
7659231200Smm			zstrm->avail_in = 0;
7660231200Smm		}
7661231200Smm
7662231200Smm		/*
7663231200Smm		 * Compress file data.
7664231200Smm		 */
7665231200Smm		while (zstrm->avail_in > 0) {
7666231200Smm			csize = zstrm->total_out;
7667231200Smm			r = deflate(zstrm, flush);
7668231200Smm			switch (r) {
7669231200Smm			case Z_OK:
7670231200Smm			case Z_STREAM_END:
7671231200Smm				csize = zstrm->total_out - csize;
7672231200Smm				if (wb_consume(a, csize) != ARCHIVE_OK)
7673231200Smm					return (ARCHIVE_FATAL);
7674231200Smm				iso9660->zisofs.total_size += csize;
7675231200Smm				iso9660->cur_file->cur_content->size += csize;
7676231200Smm				zstrm->next_out = wb_buffptr(a);
7677248616Smm				zstrm->avail_out = (uInt)wb_remaining(a);
7678231200Smm				break;
7679231200Smm			default:
7680231200Smm				archive_set_error(&a->archive,
7681231200Smm				    ARCHIVE_ERRNO_MISC,
7682231200Smm				    "Compression failed:"
7683231200Smm				    " deflate() call returned status %d",
7684231200Smm				    r);
7685231200Smm				return (ARCHIVE_FATAL);
7686231200Smm			}
7687231200Smm		}
7688231200Smm
7689231200Smm		if (flush == Z_FINISH) {
7690231200Smm			/*
7691231200Smm			 * Save the information of one zisofs block.
7692231200Smm			 */
7693231200Smm			iso9660->zisofs.block_pointers_idx ++;
7694231200Smm			archive_le32enc(&(iso9660->zisofs.block_pointers[
7695231200Smm			    iso9660->zisofs.block_pointers_idx]),
7696238856Smm				(uint32_t)iso9660->zisofs.total_size);
7697231200Smm			r = zisofs_init_zstream(a);
7698231200Smm			if (r != ARCHIVE_OK)
7699231200Smm				return (ARCHIVE_FATAL);
7700231200Smm			iso9660->zisofs.allzero = 1;
7701231200Smm			iso9660->zisofs.block_offset = file->cur_content->size;
7702231200Smm		}
7703231200Smm	} while (s);
7704231200Smm
7705231200Smm	return (ARCHIVE_OK);
7706231200Smm}
7707231200Smm
7708231200Smmstatic int
7709231200Smmzisofs_finish_entry(struct archive_write *a)
7710231200Smm{
7711231200Smm	struct iso9660 *iso9660 = a->format_data;
7712231200Smm	struct isofile *file = iso9660->cur_file;
7713231200Smm	unsigned char buff[16];
7714231200Smm	size_t s;
7715231200Smm	int64_t tail;
7716231200Smm
7717231200Smm	/* Direct temp file stream to zisofs temp file stream. */
7718231200Smm	archive_entry_set_size(file->entry, iso9660->zisofs.total_size);
7719231200Smm
7720231200Smm	/*
7721231200Smm	 * Save a file pointer which points the end of current zisofs data.
7722231200Smm	 */
7723231200Smm	tail = wb_offset(a);
7724231200Smm
7725231200Smm	/*
7726231200Smm	 * Make a header.
7727231200Smm	 *
7728231200Smm	 * +-----------------+----------------+-----------------+
7729231200Smm	 * | Header 16 bytes | Block Pointers | Compressed data |
7730231200Smm	 * +-----------------+----------------+-----------------+
7731231200Smm	 * 0                16               +X
7732231200Smm	 * Block Pointers :
7733231200Smm	 *   4 * (((Uncompressed file size + block_size -1) / block_size) + 1)
7734231200Smm	 *
7735231200Smm	 * Write zisofs header.
7736231200Smm	 *    Magic number
7737231200Smm	 * +----+----+----+----+----+----+----+----+
7738231200Smm	 * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |
7739231200Smm	 * +----+----+----+----+----+----+----+----+
7740231200Smm	 * 0    1    2    3    4    5    6    7    8
7741231200Smm	 *
7742231200Smm	 * +------------------------+------------------+
7743231200Smm	 * | Uncompressed file size | header_size >> 2 |
7744231200Smm	 * +------------------------+------------------+
7745231200Smm	 * 8                       12                 13
7746231200Smm	 *
7747231200Smm	 * +-----------------+----------------+
7748231200Smm	 * | log2 block_size | Reserved(0000) |
7749231200Smm	 * +-----------------+----------------+
7750231200Smm	 * 13               14               16
7751231200Smm	 */
7752231200Smm	memcpy(buff, zisofs_magic, 8);
7753231200Smm	set_num_731(buff+8, file->zisofs.uncompressed_size);
7754231200Smm	buff[12] = file->zisofs.header_size;
7755231200Smm	buff[13] = file->zisofs.log2_bs;
7756231200Smm	buff[14] = buff[15] = 0;/* Reserved */
7757231200Smm
7758231200Smm	/* Move to the right position to write the header. */
7759231200Smm	wb_set_offset(a, file->content.offset_of_temp);
7760231200Smm
7761231200Smm	/* Write the header. */
7762231200Smm	if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)
7763231200Smm		return (ARCHIVE_FATAL);
7764231200Smm
7765231200Smm	/*
7766231200Smm	 * Write zisofs Block Pointers.
7767231200Smm	 */
7768231200Smm	s = iso9660->zisofs.block_pointers_cnt *
7769231200Smm	    sizeof(iso9660->zisofs.block_pointers[0]);
7770231200Smm	if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)
7771231200Smm	    != ARCHIVE_OK)
7772231200Smm		return (ARCHIVE_FATAL);
7773231200Smm
7774231200Smm	/* Set a file pointer back to the end of the temporary file. */
7775231200Smm	wb_set_offset(a, tail);
7776231200Smm
7777231200Smm	return (ARCHIVE_OK);
7778231200Smm}
7779231200Smm
7780231200Smmstatic int
7781231200Smmzisofs_free(struct archive_write *a)
7782231200Smm{
7783231200Smm	struct iso9660 *iso9660 = a->format_data;
7784231200Smm	int ret = ARCHIVE_OK;
7785231200Smm
7786231200Smm	free(iso9660->zisofs.block_pointers);
7787231200Smm	if (iso9660->zisofs.stream_valid &&
7788231200Smm	    deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {
7789231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7790231200Smm		    "Failed to clean up compressor");
7791231200Smm		ret = ARCHIVE_FATAL;
7792231200Smm	}
7793231200Smm	iso9660->zisofs.block_pointers = NULL;
7794231200Smm	iso9660->zisofs.stream_valid = 0;
7795231200Smm	return (ret);
7796231200Smm}
7797231200Smm
7798231200Smmstruct zisofs_extract {
7799231200Smm	int		 pz_log2_bs; /* Log2 of block size */
7800231200Smm	uint64_t	 pz_uncompressed_size;
7801231200Smm	size_t		 uncompressed_buffer_size;
7802231200Smm
7803358090Smm	signed int	 initialized:1;
7804358090Smm	signed int	 header_passed:1;
7805231200Smm
7806231200Smm	uint32_t	 pz_offset;
7807231200Smm	unsigned char	*block_pointers;
7808231200Smm	size_t		 block_pointers_size;
7809231200Smm	size_t		 block_pointers_avail;
7810231200Smm	size_t		 block_off;
7811231200Smm	uint32_t	 block_avail;
7812231200Smm
7813231200Smm	z_stream	 stream;
7814231200Smm	int		 stream_valid;
7815231200Smm};
7816231200Smm
7817231200Smmstatic ssize_t
7818231200Smmzisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
7819231200Smm    const unsigned char *p, size_t bytes)
7820231200Smm{
7821231200Smm	size_t avail = bytes;
7822248616Smm	size_t _ceil, xsize;
7823231200Smm
7824231200Smm	/* Allocate block pointers buffer. */
7825248616Smm	_ceil = (size_t)((zisofs->pz_uncompressed_size +
7826238856Smm		(((int64_t)1) << zisofs->pz_log2_bs) - 1)
7827238856Smm		>> zisofs->pz_log2_bs);
7828248616Smm	xsize = (_ceil + 1) * 4;
7829231200Smm	if (zisofs->block_pointers == NULL) {
7830231200Smm		size_t alloc = ((xsize >> 10) + 1) << 10;
7831231200Smm		zisofs->block_pointers = malloc(alloc);
7832231200Smm		if (zisofs->block_pointers == NULL) {
7833231200Smm			archive_set_error(&a->archive, ENOMEM,
7834231200Smm			    "No memory for zisofs decompression");
7835231200Smm			return (ARCHIVE_FATAL);
7836231200Smm		}
7837231200Smm	}
7838231200Smm	zisofs->block_pointers_size = xsize;
7839231200Smm
7840231200Smm	/* Allocate uncompressed data buffer. */
7841248616Smm	zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
7842231200Smm
7843231200Smm	/*
7844231200Smm	 * Read the file header, and check the magic code of zisofs.
7845231200Smm	 */
7846231200Smm	if (!zisofs->header_passed) {
7847231200Smm		int err = 0;
7848231200Smm		if (avail < 16) {
7849231200Smm			archive_set_error(&a->archive,
7850231200Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
7851231200Smm			    "Illegal zisofs file body");
7852231200Smm			return (ARCHIVE_FATAL);
7853231200Smm		}
7854231200Smm
7855231200Smm		if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
7856231200Smm			err = 1;
7857231200Smm		else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)
7858231200Smm			err = 1;
7859231200Smm		else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)
7860231200Smm			err = 1;
7861231200Smm		if (err) {
7862231200Smm			archive_set_error(&a->archive,
7863231200Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
7864231200Smm			    "Illegal zisofs file body");
7865231200Smm			return (ARCHIVE_FATAL);
7866231200Smm		}
7867231200Smm		avail -= 16;
7868231200Smm		p += 16;
7869231200Smm		zisofs->header_passed = 1;
7870231200Smm	}
7871231200Smm
7872231200Smm	/*
7873231200Smm	 * Read block pointers.
7874231200Smm	 */
7875231200Smm	if (zisofs->header_passed &&
7876231200Smm	    zisofs->block_pointers_avail < zisofs->block_pointers_size) {
7877231200Smm		xsize = zisofs->block_pointers_size
7878231200Smm		    - zisofs->block_pointers_avail;
7879231200Smm		if (avail < xsize)
7880231200Smm			xsize = avail;
7881231200Smm		memcpy(zisofs->block_pointers
7882231200Smm		    + zisofs->block_pointers_avail, p, xsize);
7883231200Smm		zisofs->block_pointers_avail += xsize;
7884231200Smm		avail -= xsize;
7885231200Smm	    	if (zisofs->block_pointers_avail
7886231200Smm		    == zisofs->block_pointers_size) {
7887231200Smm			/* We've got all block pointers and initialize
7888231200Smm			 * related variables.	*/
7889231200Smm			zisofs->block_off = 0;
7890231200Smm			zisofs->block_avail = 0;
7891231200Smm			/* Complete a initialization */
7892231200Smm			zisofs->initialized = 1;
7893231200Smm		}
7894231200Smm	}
7895231200Smm	return ((ssize_t)avail);
7896231200Smm}
7897231200Smm
7898231200Smmstatic ssize_t
7899231200Smmzisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
7900231200Smm    const unsigned char *p, size_t bytes)
7901231200Smm{
7902231200Smm	size_t avail;
7903231200Smm	int r;
7904231200Smm
7905231200Smm	if (!zisofs->initialized) {
7906231200Smm		ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);
7907231200Smm		if (rs < 0)
7908231200Smm			return (rs);
7909231200Smm		if (!zisofs->initialized) {
7910231200Smm			/* We need more data. */
7911248616Smm			zisofs->pz_offset += (uint32_t)bytes;
7912231200Smm			return (bytes);
7913231200Smm		}
7914231200Smm		avail = rs;
7915231200Smm		p += bytes - avail;
7916231200Smm	} else
7917231200Smm		avail = bytes;
7918231200Smm
7919231200Smm	/*
7920231200Smm	 * Get block offsets from block pointers.
7921231200Smm	 */
7922231200Smm	if (zisofs->block_avail == 0) {
7923231200Smm		uint32_t bst, bed;
7924231200Smm
7925231200Smm		if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
7926231200Smm			/* There isn't a pair of offsets. */
7927231200Smm			archive_set_error(&a->archive,
7928231200Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
7929231200Smm			    "Illegal zisofs block pointers");
7930231200Smm			return (ARCHIVE_FATAL);
7931231200Smm		}
7932231200Smm		bst = archive_le32dec(
7933231200Smm		    zisofs->block_pointers + zisofs->block_off);
7934231200Smm		if (bst != zisofs->pz_offset + (bytes - avail)) {
7935231200Smm			archive_set_error(&a->archive,
7936231200Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
7937231200Smm			    "Illegal zisofs block pointers(cannot seek)");
7938231200Smm			return (ARCHIVE_FATAL);
7939231200Smm		}
7940231200Smm		bed = archive_le32dec(
7941231200Smm		    zisofs->block_pointers + zisofs->block_off + 4);
7942231200Smm		if (bed < bst) {
7943231200Smm			archive_set_error(&a->archive,
7944231200Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
7945231200Smm			    "Illegal zisofs block pointers");
7946231200Smm			return (ARCHIVE_FATAL);
7947231200Smm		}
7948231200Smm		zisofs->block_avail = bed - bst;
7949231200Smm		zisofs->block_off += 4;
7950231200Smm
7951231200Smm		/* Initialize compression library for new block. */
7952231200Smm		if (zisofs->stream_valid)
7953231200Smm			r = inflateReset(&zisofs->stream);
7954231200Smm		else
7955231200Smm			r = inflateInit(&zisofs->stream);
7956231200Smm		if (r != Z_OK) {
7957231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7958231200Smm			    "Can't initialize zisofs decompression.");
7959231200Smm			return (ARCHIVE_FATAL);
7960231200Smm		}
7961231200Smm		zisofs->stream_valid = 1;
7962231200Smm		zisofs->stream.total_in = 0;
7963231200Smm		zisofs->stream.total_out = 0;
7964231200Smm	}
7965231200Smm
7966231200Smm	/*
7967231200Smm	 * Make uncompressed data.
7968231200Smm	 */
7969231200Smm	if (zisofs->block_avail == 0) {
7970231200Smm		/*
7971231200Smm		 * It's basically 32K bytes NUL data.
7972231200Smm		 */
7973231200Smm		unsigned char *wb;
7974231200Smm		size_t size, wsize;
7975231200Smm
7976231200Smm		size = zisofs->uncompressed_buffer_size;
7977231200Smm		while (size) {
7978231200Smm			wb = wb_buffptr(a);
7979231200Smm			if (size > wb_remaining(a))
7980231200Smm				wsize = wb_remaining(a);
7981231200Smm			else
7982231200Smm				wsize = size;
7983231200Smm			memset(wb, 0, wsize);
7984231200Smm			r = wb_consume(a, wsize);
7985231200Smm			if (r < 0)
7986231200Smm				return (r);
7987231200Smm			size -= wsize;
7988231200Smm		}
7989231200Smm	} else {
7990231200Smm		zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
7991231200Smm		if (avail > zisofs->block_avail)
7992231200Smm			zisofs->stream.avail_in = zisofs->block_avail;
7993231200Smm		else
7994248616Smm			zisofs->stream.avail_in = (uInt)avail;
7995231200Smm		zisofs->stream.next_out = wb_buffptr(a);
7996248616Smm		zisofs->stream.avail_out = (uInt)wb_remaining(a);
7997231200Smm
7998231200Smm		r = inflate(&zisofs->stream, 0);
7999231200Smm		switch (r) {
8000231200Smm		case Z_OK: /* Decompressor made some progress.*/
8001231200Smm		case Z_STREAM_END: /* Found end of stream. */
8002231200Smm			break;
8003231200Smm		default:
8004231200Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8005231200Smm			    "zisofs decompression failed (%d)", r);
8006231200Smm			return (ARCHIVE_FATAL);
8007231200Smm		}
8008231200Smm		avail -= zisofs->stream.next_in - p;
8009248616Smm		zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
8010231200Smm		r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
8011231200Smm		if (r < 0)
8012231200Smm			return (r);
8013231200Smm	}
8014248616Smm	zisofs->pz_offset += (uint32_t)bytes;
8015231200Smm	return (bytes - avail);
8016231200Smm}
8017231200Smm
8018231200Smmstatic int
8019231200Smmzisofs_rewind_boot_file(struct archive_write *a)
8020231200Smm{
8021231200Smm	struct iso9660 *iso9660 = a->format_data;
8022231200Smm	struct isofile *file;
8023231200Smm	unsigned char *rbuff;
8024231200Smm	ssize_t r;
8025231200Smm	size_t remaining, rbuff_size;
8026231200Smm	struct zisofs_extract zext;
8027231200Smm	int64_t read_offset, write_offset, new_offset;
8028231200Smm	int fd, ret = ARCHIVE_OK;
8029231200Smm
8030231200Smm	file = iso9660->el_torito.boot->file;
8031231200Smm	/*
8032231200Smm	 * There is nothing to do if this boot file does not have
8033231200Smm	 * zisofs header.
8034231200Smm	 */
8035231200Smm	if (file->zisofs.header_size == 0)
8036231200Smm		return (ARCHIVE_OK);
8037231200Smm
8038231200Smm	/*
8039231200Smm	 * Uncompress the zisofs'ed file contents.
8040231200Smm	 */
8041231200Smm	memset(&zext, 0, sizeof(zext));
8042231200Smm	zext.pz_uncompressed_size = file->zisofs.uncompressed_size;
8043231200Smm	zext.pz_log2_bs = file->zisofs.log2_bs;
8044231200Smm
8045231200Smm	fd = iso9660->temp_fd;
8046231200Smm	new_offset = wb_offset(a);
8047231200Smm	read_offset = file->content.offset_of_temp;
8048238856Smm	remaining = (size_t)file->content.size;
8049231200Smm	if (remaining > 1024 * 32)
8050231200Smm		rbuff_size = 1024 * 32;
8051231200Smm	else
8052231200Smm		rbuff_size = remaining;
8053231200Smm
8054231200Smm	rbuff = malloc(rbuff_size);
8055231200Smm	if (rbuff == NULL) {
8056231200Smm		archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
8057231200Smm		return (ARCHIVE_FATAL);
8058231200Smm	}
8059231200Smm	while (remaining) {
8060231200Smm		size_t rsize;
8061231200Smm		ssize_t rs;
8062231200Smm
8063231200Smm		/* Get the current file pointer. */
8064231200Smm		write_offset = lseek(fd, 0, SEEK_CUR);
8065231200Smm
8066231200Smm		/* Change the file pointer to read. */
8067231200Smm		lseek(fd, read_offset, SEEK_SET);
8068231200Smm
8069231200Smm		rsize = rbuff_size;
8070231200Smm		if (rsize > remaining)
8071231200Smm			rsize = remaining;
8072231200Smm		rs = read(iso9660->temp_fd, rbuff, rsize);
8073231200Smm		if (rs <= 0) {
8074231200Smm			archive_set_error(&a->archive, errno,
8075231200Smm			    "Can't read temporary file(%jd)", (intmax_t)rs);
8076231200Smm			ret = ARCHIVE_FATAL;
8077231200Smm			break;
8078231200Smm		}
8079231200Smm		remaining -= rs;
8080231200Smm		read_offset += rs;
8081231200Smm
8082231200Smm		/* Put the file pointer back to write. */
8083231200Smm		lseek(fd, write_offset, SEEK_SET);
8084231200Smm
8085231200Smm		r = zisofs_extract(a, &zext, rbuff, rs);
8086231200Smm		if (r < 0) {
8087231200Smm			ret = (int)r;
8088231200Smm			break;
8089231200Smm		}
8090231200Smm	}
8091231200Smm
8092231200Smm	if (ret == ARCHIVE_OK) {
8093231200Smm		/*
8094231200Smm		 * Change the boot file content from zisofs'ed data
8095231200Smm		 * to plain data.
8096231200Smm		 */
8097231200Smm		file->content.offset_of_temp = new_offset;
8098231200Smm		file->content.size = file->zisofs.uncompressed_size;
8099231200Smm		archive_entry_set_size(file->entry, file->content.size);
8100231200Smm		/* Set to be no zisofs. */
8101231200Smm		file->zisofs.header_size = 0;
8102231200Smm		file->zisofs.log2_bs = 0;
8103231200Smm		file->zisofs.uncompressed_size = 0;
8104231200Smm		r = wb_write_padding_to_temp(a, file->content.size);
8105231200Smm		if (r < 0)
8106231200Smm			ret = ARCHIVE_FATAL;
8107231200Smm	}
8108231200Smm
8109231200Smm	/*
8110231200Smm	 * Free the resource we used in this function only.
8111231200Smm	 */
8112231200Smm	free(rbuff);
8113231200Smm	free(zext.block_pointers);
8114231200Smm	if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {
8115231200Smm        	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8116231200Smm		    "Failed to clean up compressor");
8117231200Smm		ret = ARCHIVE_FATAL;
8118231200Smm	}
8119231200Smm
8120231200Smm	return (ret);
8121231200Smm}
8122231200Smm
8123231200Smm#else
8124231200Smm
8125231200Smmstatic int
8126231200Smmzisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
8127231200Smm{
8128231200Smm	(void)buff; /* UNUSED */
8129231200Smm	(void)s; /* UNUSED */
8130353377Smm	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programming error");
8131231200Smm	return (ARCHIVE_FATAL);
8132231200Smm}
8133231200Smm
8134231200Smmstatic int
8135231200Smmzisofs_rewind_boot_file(struct archive_write *a)
8136231200Smm{
8137231200Smm	struct iso9660 *iso9660 = a->format_data;
8138231200Smm
8139231200Smm	if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {
8140231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8141231200Smm		    "We cannot extract the zisofs imaged boot file;"
8142231200Smm		    " this may not boot in being zisofs imaged");
8143231200Smm		return (ARCHIVE_FAILED);
8144231200Smm	}
8145231200Smm	return (ARCHIVE_OK);
8146231200Smm}
8147231200Smm
8148231200Smmstatic int
8149231200Smmzisofs_finish_entry(struct archive_write *a)
8150231200Smm{
8151231200Smm	(void)a; /* UNUSED */
8152231200Smm	return (ARCHIVE_OK);
8153231200Smm}
8154231200Smm
8155231200Smmstatic int
8156231200Smmzisofs_free(struct archive_write *a)
8157231200Smm{
8158231200Smm	(void)a; /* UNUSED */
8159231200Smm	return (ARCHIVE_OK);
8160231200Smm}
8161231200Smm
8162231200Smm#endif /* HAVE_ZLIB_H */
8163231200Smm
8164