xref: /dragonfly/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c (revision afd311f52496a4b5c3df02ea6d4bdab591886c60)
1 /*-
2  * Copyright (c) 2009-2012 Michihiro NAKAJIMA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "archive_platform.h"
27 
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_UTSNAME_H
32 #include <sys/utsname.h>
33 #endif
34 #ifdef HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #ifdef HAVE_LIMITS_H
38 #include <limits.h>
39 #endif
40 #include <stdio.h>
41 #include <stdarg.h>
42 #ifdef HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45 #include <time.h>
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #ifdef HAVE_ZLIB_H
50 #include <zlib.h>
51 #endif
52 
53 #include "archive.h"
54 #include "archive_endian.h"
55 #include "archive_entry.h"
56 #include "archive_entry_locale.h"
57 #include "archive_private.h"
58 #include "archive_rb.h"
59 #include "archive_write_private.h"
60 
61 #if defined(_WIN32) && !defined(__CYGWIN__)
62 #define getuid()                        0
63 #define getgid()                        0
64 #endif
65 
66 /*#define DEBUG 1*/
67 #ifdef DEBUG
68 /* To compare to the ISO image file made by mkisofs. */
69 #define COMPAT_MKISOFS                  1
70 #endif
71 
72 #define LOGICAL_BLOCK_BITS                        11
73 #define LOGICAL_BLOCK_SIZE                        2048
74 #define PATH_TABLE_BLOCK_SIZE                     4096
75 
76 #define SYSTEM_AREA_BLOCK                         16
77 #define PRIMARY_VOLUME_DESCRIPTOR_BLOCK           1
78 #define SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK     1
79 #define BOOT_RECORD_DESCRIPTOR_BLOCK              1
80 #define VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK    1
81 #define NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK     1
82 #define RRIP_ER_BLOCK                                       1
83 #define PADDING_BLOCK                                       150
84 
85 #define FD_1_2M_SIZE                    (1024 * 1200)
86 #define FD_1_44M_SIZE                   (1024 * 1440)
87 #define FD_2_88M_SIZE                   (1024 * 2880)
88 #define MULTI_EXTENT_SIZE     (ARCHIVE_LITERAL_LL(1) << 32) /* 4Gi bytes. */
89 #define MAX_DEPTH             8
90 #define RR_CE_SIZE            28                  /* SUSP "CE" extension size */
91 
92 #define FILE_FLAG_EXISTENCE   0x01
93 #define FILE_FLAG_DIRECTORY   0x02
94 #define FILE_FLAG_ASSOCIATED  0x04
95 #define FILE_FLAG_RECORD      0x08
96 #define FILE_FLAG_PROTECTION  0x10
97 #define FILE_FLAG_MULTI_EXTENT          0x80
98 
99 static const char rrip_identifier[] =
100           "RRIP_1991A";
101 static const char rrip_descriptor[] =
102           "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR "
103           "POSIX FILE SYSTEM SEMANTICS";
104 static const char rrip_source[] =
105           "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  "
106           "SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR "
107           "CONTACT INFORMATION.";
108 #define RRIP_ER_ID_SIZE                 (sizeof(rrip_identifier)-1)
109 #define RRIP_ER_DSC_SIZE      (sizeof(rrip_descriptor)-1)
110 #define RRIP_ER_SRC_SIZE      (sizeof(rrip_source)-1)
111 #define RRIP_ER_SIZE                    (8 + RRIP_ER_ID_SIZE + \
112                                         RRIP_ER_DSC_SIZE + RRIP_ER_SRC_SIZE)
113 
114 static const unsigned char zisofs_magic[8] = {
115           0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
116 };
117 
118 #define ZF_HEADER_SIZE        16        /* zisofs header size. */
119 #define ZF_LOG2_BS  15        /* log2 block size; 32K bytes. */
120 #define ZF_BLOCK_SIZE         (1UL << ZF_LOG2_BS)
121 
122 /*
123  * Manage extra records.
124  */
125 struct extr_rec {
126           int                  location;
127           int                  offset;
128           unsigned char        buf[LOGICAL_BLOCK_SIZE];
129           struct extr_rec     *next;
130 };
131 
132 struct ctl_extr_rec {
133           int                  use_extr;
134           unsigned char       *bp;
135           struct isoent       *isoent;
136           unsigned char       *ce_ptr;
137           int                  cur_len;
138           int                  dr_len;
139           int                  limit;
140           int                  extr_off;
141           int                  extr_loc;
142 };
143 #define DR_SAFETY   RR_CE_SIZE
144 #define DR_LIMIT    (254 - DR_SAFETY)
145 
146 /*
147  * The relation of struct isofile and isoent and archive_entry.
148  *
149  * Primary volume tree  --> struct isoent
150  *                                |
151  *                                v
152  *                          struct isofile --> archive_entry
153  *                                ^
154  *                                |
155  * Joliet volume tree   --> struct isoent
156  *
157  * struct isoent has specific information for volume.
158  */
159 
160 struct isofile {
161           /* Used for managing struct isofile list. */
162           struct isofile                *allnext;
163           struct isofile                *datanext;
164           /* Used for managing a hardlinked struct isofile list. */
165           struct isofile                *hlnext;
166           struct isofile                *hardlink_target;
167 
168           struct archive_entry          *entry;
169 
170           /*
171            * Used for making a directory tree.
172            */
173           struct archive_string          parentdir;
174           struct archive_string          basename;
175           struct archive_string          basename_utf16;
176           struct archive_string          symlink;
177           int                            dircnt;  /* The number of elements of
178                                                              * its parent directory */
179 
180           /*
181            * Used for a Directory Record.
182            */
183           struct content {
184                     int64_t              offset_of_temp;
185                     int64_t              size;
186                     int                  blocks;
187                     uint32_t   location;
188                     /*
189                      * One extent equals one content.
190                      * If this entry has multi extent, `next' variable points
191                      * next content data.
192                      */
193                     struct content      *next;              /* next content     */
194           } content, *cur_content;
195           int                            write_content;
196 
197           enum {
198                     NO = 0,
199                     BOOT_CATALOG,
200                     BOOT_IMAGE
201           } boot;
202 
203           /*
204            * Used for a zisofs.
205            */
206           struct {
207                     unsigned char        header_size;
208                     unsigned char        log2_bs;
209                     uint32_t   uncompressed_size;
210           } zisofs;
211 };
212 
213 struct isoent {
214           /* Keep `rbnode' at the first member of struct isoent. */
215           struct archive_rb_node         rbnode;
216 
217           struct isofile                *file;
218 
219           struct isoent                 *parent;
220           /* A list of children.(use chnext) */
221           struct {
222                     struct isoent       *first;
223                     struct isoent       **last;
224                     int                  cnt;
225           }                              children;
226           struct archive_rb_tree         rbtree;
227 
228           /* A list of sub directories.(use drnext) */
229           struct {
230                     struct isoent       *first;
231                     struct isoent       **last;
232                     int                  cnt;
233           }                              subdirs;
234           /* A sorted list of sub directories. */
235           struct isoent                 **children_sorted;
236           /* Used for managing struct isoent list. */
237           struct isoent                 *chnext;
238           struct isoent                 *drnext;
239           struct isoent                 *ptnext;
240 
241           /*
242            * Used for making a Directory Record.
243            */
244           int                            dir_number;
245           struct {
246                     int                  vd;
247                     int                  self;
248                     int                  parent;
249                     int                  normal;
250           }                              dr_len;
251           uint32_t             dir_location;
252           int                            dir_block;
253 
254           /*
255            * Identifier:
256            *   on primary, ISO9660 file/directory name.
257            *   on joliet, UCS2 file/directory name.
258            * ext_off   : offset of identifier extension.
259            * ext_len   : length of identifier extension.
260            * id_len    : byte size of identifier.
261            *   on primary, this is ext_off + ext_len + version length.
262            *   on joliet, this is ext_off + ext_len.
263            * mb_len    : length of multibyte-character of identifier.
264            *   on primary, mb_len and id_len are always the same.
265            *   on joliet, mb_len and id_len are different.
266            */
267           char                          *identifier;
268           int                            ext_off;
269           int                            ext_len;
270           int                            id_len;
271           int                            mb_len;
272 
273           /*
274            * Used for making a Rockridge extension.
275            * This is a part of Directory Records.
276            */
277           struct isoent                 *rr_parent;
278           struct isoent                 *rr_child;
279 
280           /* Extra Record.(which we call in this source file)
281            * A maximum size of the Directory Record is 254.
282            * so, if generated RRIP data of a file cannot into a Directory
283            * Record because of its size, that surplus data relocate this
284            * Extra Record.
285            */
286           struct {
287                     struct extr_rec     *first;
288                     struct extr_rec     **last;
289                     struct extr_rec     *current;
290           }                              extr_rec_list;
291 
292           signed int                     virtual:1;
293           /* If set to one, this file type is a directory.
294            * A convenience flag to be used as
295            * "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".
296            */
297           signed int                     dir:1;
298 };
299 
300 struct hardlink {
301           struct archive_rb_node         rbnode;
302           int                            nlink;
303           struct {
304                     struct isofile      *first;
305                     struct isofile      **last;
306           }                              file_list;
307 };
308 
309 /*
310  * ISO writer options
311  */
312 struct iso_option {
313           /*
314            * Usage  : abstract-file=<value>
315            * Type   : string, max 37 bytes
316            * Default: Not specified
317            * COMPAT : mkisofs -abstract <value>
318            *
319            * Specifies Abstract Filename.
320            * This file shall be described in the Root Directory
321            * and containing a abstract statement.
322            */
323           unsigned int         abstract_file:1;
324 #define OPT_ABSTRACT_FILE_DEFAULT       0         /* Not specified */
325 #define ABSTRACT_FILE_SIZE              37
326 
327           /*
328            * Usage  : application-id=<value>
329            * Type   : string, max 128 bytes
330            * Default: Not specified
331            * COMPAT : mkisofs -A/-appid <value>.
332            *
333            * Specifies Application Identifier.
334            * If the first byte is set to '_'(5F), the remaining
335            * bytes of this option shall specify an identifier
336            * for a file containing the identification of the
337            * application.
338            * This file shall be described in the Root Directory.
339            */
340           unsigned int         application_id:1;
341 #define OPT_APPLICATION_ID_DEFAULT      0         /* Use default identifier */
342 #define APPLICATION_IDENTIFIER_SIZE     128
343 
344           /*
345            * Usage : !allow-vernum
346            * Type  : boolean
347            * Default: Enabled
348            *          : Violates the ISO9660 standard if disable.
349            * COMPAT: mkisofs -N
350            *
351            * Allow filenames to use version numbers.
352            */
353           unsigned int         allow_vernum:1;
354 #define OPT_ALLOW_VERNUM_DEFAULT        1         /* Enabled */
355 
356           /*
357            * Usage  : biblio-file=<value>
358            * Type   : string, max 37 bytes
359            * Default: Not specified
360            * COMPAT : mkisofs -biblio <value>
361            *
362            * Specifies Bibliographic Filename.
363            * This file shall be described in the Root Directory
364            * and containing bibliographic records.
365            */
366           unsigned int         biblio_file:1;
367 #define OPT_BIBLIO_FILE_DEFAULT                   0         /* Not specified */
368 #define BIBLIO_FILE_SIZE                37
369 
370           /*
371            * Usage  : boot=<value>
372            * Type   : string
373            * Default: Not specified
374            * COMPAT : mkisofs -b/-eltorito-boot <value>
375            *
376            * Specifies "El Torito" boot image file to make
377            * a bootable CD.
378            */
379           unsigned int         boot:1;
380 #define OPT_BOOT_DEFAULT                0         /* Not specified */
381 
382           /*
383            * Usage  : boot-catalog=<value>
384            * Type   : string
385            * Default: "boot.catalog"
386            * COMPAT : mkisofs -c/-eltorito-catalog <value>
387            *
388            * Specifies a fullpath of El Torito boot catalog.
389            */
390           unsigned int         boot_catalog:1;
391 #define OPT_BOOT_CATALOG_DEFAULT        0         /* Not specified */
392 
393           /*
394            * Usage  : boot-info-table
395            * Type   : boolean
396            * Default: Disabled
397            * COMPAT : mkisofs -boot-info-table
398            *
399            * Modify the boot image file specified by `boot'
400            * option; ISO writer stores boot file information
401            * into the boot file in ISO image at offset 8
402            * through offset 64.
403            */
404           unsigned int         boot_info_table:1;
405 #define OPT_BOOT_INFO_TABLE_DEFAULT     0         /* Disabled */
406 
407           /*
408            * Usage  : boot-load-seg=<value>
409            * Type   : hexadecimal
410            * Default: Not specified
411            * COMPAT : mkisofs -boot-load-seg <value>
412            *
413            * Specifies a load segment for boot image.
414            * This is used with no-emulation mode.
415            */
416           unsigned int         boot_load_seg:1;
417 #define OPT_BOOT_LOAD_SEG_DEFAULT       0         /* Not specified */
418 
419           /*
420            * Usage  : boot-load-size=<value>
421            * Type   : decimal
422            * Default: Not specified
423            * COMPAT : mkisofs -boot-load-size <value>
424            *
425            * Specifies a sector count for boot image.
426            * This is used with no-emulation mode.
427            */
428           unsigned int         boot_load_size:1;
429 #define OPT_BOOT_LOAD_SIZE_DEFAULT      0         /* Not specified */
430 
431           /*
432            * Usage  : boot-type=<boot-media-type>
433            *        : 'no-emulation' : 'no emulation' image
434            *        :           'fd' : floppy disk image
435            *        :    'hard-disk' : hard disk image
436            * Type   : string
437            * Default: Auto detect
438            *        : We check a size of boot image;
439            *        : If the size is just 1.22M/1.44M/2.88M,
440            *        : we assume boot_type is 'fd';
441            *        : otherwise boot_type is 'no-emulation'.
442            * COMPAT :
443            *    boot=no-emulation
444            *        mkisofs -no-emul-boot
445            *    boot=fd
446            *        This is a default on the mkisofs.
447            *    boot=hard-disk
448            *        mkisofs -hard-disk-boot
449            *
450            * Specifies a type of "El Torito" boot image.
451            */
452           unsigned int         boot_type:2;
453 #define OPT_BOOT_TYPE_AUTO              0         /* auto detect                  */
454 #define OPT_BOOT_TYPE_NO_EMU            1         /* ``no emulation'' image */
455 #define OPT_BOOT_TYPE_FD                2         /* floppy disk image            */
456 #define OPT_BOOT_TYPE_HARD_DISK                   3         /* hard disk image    */
457 #define OPT_BOOT_TYPE_DEFAULT           OPT_BOOT_TYPE_AUTO
458 
459           /*
460            * Usage  : compression-level=<value>
461            * Type   : decimal
462            * Default: Not specified
463            * COMPAT : NONE
464            *
465            * Specifies compression level for option zisofs=direct.
466            */
467           unsigned int         compression_level:1;
468 #define OPT_COMPRESSION_LEVEL_DEFAULT   0         /* Not specified */
469 
470           /*
471            * Usage  : copyright-file=<value>
472            * Type   : string, max 37 bytes
473            * Default: Not specified
474            * COMPAT : mkisofs -copyright <value>
475            *
476            * Specifies Copyright Filename.
477            * This file shall be described in the Root Directory
478            * and containing a copyright statement.
479            */
480           unsigned int         copyright_file:1;
481 #define OPT_COPYRIGHT_FILE_DEFAULT      0         /* Not specified */
482 #define COPYRIGHT_FILE_SIZE             37
483 
484           /*
485            * Usage  : gid=<value>
486            * Type   : decimal
487            * Default: Not specified
488            * COMPAT : mkisofs -gid <value>
489            *
490            * Specifies a group id to rewrite the group id of all files.
491            */
492           unsigned int         gid:1;
493 #define OPT_GID_DEFAULT                           0         /* Not specified */
494 
495           /*
496            * Usage  : iso-level=[1234]
497            * Type   : decimal
498            * Default: 1
499            * COMPAT : mkisofs -iso-level <value>
500            *
501            * Specifies ISO9600 Level.
502            * Level 1: [DEFAULT]
503            *   - limits each file size less than 4Gi bytes;
504            *   - a File Name shall not contain more than eight
505            *     d-characters or eight d1-characters;
506            *   - a File Name Extension shall not contain more than
507            *     three d-characters or three d1-characters;
508            *   - a Directory Identifier shall not contain more
509            *     than eight d-characters or eight d1-characters.
510            * Level 2:
511            *   - limits each file size less than 4Giga bytes;
512            *   - a File Name shall not contain more than thirty
513            *     d-characters or thirty d1-characters;
514            *   - a File Name Extension shall not contain more than
515            *     thirty d-characters or thirty d1-characters;
516            *   - a Directory Identifier shall not contain more
517            *     than thirty-one d-characters or thirty-one
518            *     d1-characters.
519            * Level 3:
520            *   - no limit of file size; use multi extent.
521            * Level 4:
522            *   - this level 4 simulates mkisofs option
523            *     '-iso-level 4';
524            *   - crate a enhanced volume as mkisofs doing;
525            *   - allow a File Name to have leading dot;
526            *   - allow a File Name to have all ASCII letters;
527            *   - allow a File Name to have multiple dots;
528            *   - allow more then 8 depths of directory trees;
529            *   - disable a version number to a File Name;
530            *   - disable a forced period to the tail of a File Name;
531            *   - the maximum length of files and directories is raised to 193.
532            *     if rockridge option is disabled, raised to 207.
533            */
534           unsigned int         iso_level:3;
535 #define OPT_ISO_LEVEL_DEFAULT           1         /* ISO Level 1 */
536 
537           /*
538            * Usage  : joliet[=long]
539            *        : !joliet
540            *        :   Do not generate Joliet Volume and Records.
541            *        : joliet [DEFAULT]
542            *        :   Generates Joliet Volume and Directory Records.
543            *        :   [COMPAT: mkisofs -J/-joliet]
544            *        : joliet=long
545            *        :   The joliet filenames are up to 103 Unicode
546            *        :   characters.
547            *        :   This option breaks the Joliet specification.
548            *        :   [COMPAT: mkisofs -J -joliet-long]
549            * Type   : boolean/string
550            * Default: Enabled
551            * COMPAT : mkisofs -J / -joliet-long
552            *
553            * Generates Joliet Volume and Directory Records.
554            */
555           unsigned int         joliet:2;
556 #define OPT_JOLIET_DISABLE              0         /* Not generate Joliet Records. */
557 #define OPT_JOLIET_ENABLE               1         /* Generate Joliet Records.  */
558 #define OPT_JOLIET_LONGNAME             2         /* Use long joliet filenames.*/
559 #define OPT_JOLIET_DEFAULT              OPT_JOLIET_ENABLE
560 
561           /*
562            * Usage  : !limit-depth
563            * Type   : boolean
564            * Default: Enabled
565            *          : Violates the ISO9660 standard if disable.
566            * COMPAT : mkisofs -D/-disable-deep-relocation
567            *
568            * The number of levels in hierarchy cannot exceed eight.
569            */
570           unsigned int         limit_depth:1;
571 #define OPT_LIMIT_DEPTH_DEFAULT                   1         /* Enabled */
572 
573           /*
574            * Usage  : !limit-dirs
575            * Type   : boolean
576            * Default: Enabled
577            *          : Violates the ISO9660 standard if disable.
578            * COMPAT : mkisofs -no-limit-pathtables
579            *
580            * Limits the number of directories less than 65536 due
581            * to the size of the Parent Directory Number of Path
582            * Table.
583            */
584           unsigned int         limit_dirs:1;
585 #define OPT_LIMIT_DIRS_DEFAULT                    1         /* Enabled */
586 
587           /*
588            * Usage  : !pad
589            * Type   : boolean
590            * Default: Enabled
591            * COMPAT : -pad/-no-pad
592            *
593            * Pads the end of the ISO image by null of 300Ki bytes.
594            */
595           unsigned int         pad:1;
596 #define OPT_PAD_DEFAULT                           1         /* Enabled */
597 
598           /*
599            * Usage  : publisher=<value>
600            * Type   : string, max 128 bytes
601            * Default: Not specified
602            * COMPAT : mkisofs -publisher <value>
603            *
604            * Specifies Publisher Identifier.
605            * If the first byte is set to '_'(5F), the remaining
606            * bytes of this option shall specify an identifier
607            * for a file containing the identification of the user.
608            * This file shall be described in the Root Directory.
609            */
610           unsigned int         publisher:1;
611 #define OPT_PUBLISHER_DEFAULT           0         /* Not specified */
612 #define PUBLISHER_IDENTIFIER_SIZE       128
613 
614           /*
615            * Usage  : rockridge
616            *        : !rockridge
617            *        :    disable to generate SUSP and RR records.
618            *        : rockridge
619            *        :    the same as 'rockridge=useful'.
620            *        : rockridge=strict
621            *        :    generate SUSP and RR records.
622            *        :    [COMPAT: mkisofs -R]
623            *        : rockridge=useful [DEFAULT]
624            *        :    generate SUSP and RR records.
625            *        :    [COMPAT: mkisofs -r]
626            *        :    NOTE  Our rockridge=useful option does not set a zero
627            *        :          to uid and gid, you should use application
628            *        :          option such as --gid,--gname,--uid and --uname
629            *        :          bsdtar options instead.
630            * Type   : boolean/string
631            * Default: Enabled as rockridge=useful
632            * COMPAT : mkisofs -r / -R
633            *
634            * Generates SUSP and RR records.
635            */
636           unsigned int         rr:2;
637 #define OPT_RR_DISABLED                           0
638 #define OPT_RR_STRICT                             1
639 #define OPT_RR_USEFUL                             2
640 #define OPT_RR_DEFAULT                            OPT_RR_USEFUL
641 
642           /*
643            * Usage  : volume-id=<value>
644            * Type   : string, max 32 bytes
645            * Default: Not specified
646            * COMPAT : mkisofs -V <value>
647            *
648            * Specifies Volume Identifier.
649            */
650           unsigned int         volume_id:1;
651 #define OPT_VOLUME_ID_DEFAULT           0         /* Use default identifier */
652 #define VOLUME_IDENTIFIER_SIZE                    32
653 
654           /*
655            * Usage  : !zisofs [DEFAULT]
656            *        :    Disable to generate RRIP 'ZF' extension.
657            *        : zisofs
658            *        :    Make files zisofs file and generate RRIP 'ZF'
659            *        :    extension. So you do not need mkzftree utility
660            *        :    for making zisofs.
661            *        :    When the file size is less than one Logical Block
662            *        :    size, that file will not zisofs'ed since it does
663            *        :    reduce an ISO-image size.
664            *        :
665            *        :    When you specify option 'boot=<boot-image>', that
666            *        :    'boot-image' file won't be converted to zisofs file.
667            * Type   : boolean
668            * Default: Disabled
669            *
670            * Generates RRIP 'ZF' System Use Entry.
671            */
672           unsigned int         zisofs:1;
673 #define OPT_ZISOFS_DISABLED             0
674 #define OPT_ZISOFS_DIRECT               1
675 #define OPT_ZISOFS_DEFAULT              OPT_ZISOFS_DISABLED
676 
677 };
678 
679 struct iso9660 {
680           /* The creation time of ISO image. */
681           time_t                         birth_time;
682           /* A file stream of a temporary file, which file contents
683            * save to until ISO image can be created. */
684           int                            temp_fd;
685 
686           struct isofile                *cur_file;
687           struct isoent                 *cur_dirent;
688           struct archive_string          cur_dirstr;
689           uint64_t             bytes_remaining;
690           int                            need_multi_extent;
691 
692           /* Temporary string buffer for Joliet extension. */
693           struct archive_string          utf16be;
694           struct archive_string          mbs;
695 
696           struct archive_string_conv *sconv_to_utf16be;
697           struct archive_string_conv *sconv_from_utf16be;
698 
699           /* A list of all of struct isofile entries. */
700           struct {
701                     struct isofile      *first;
702                     struct isofile      **last;
703           }                              all_file_list;
704 
705           /* A list of struct isofile entries which have its
706            * contents and are not a directory, a hardlinked file
707            * and a symlink file. */
708           struct {
709                     struct isofile      *first;
710                     struct isofile      **last;
711           }                              data_file_list;
712 
713           /* Used for managing to find hardlinking files. */
714           struct archive_rb_tree         hardlink_rbtree;
715 
716           /* Used for making the Path Table Record. */
717           struct vdd {
718                     /* the root of entry tree. */
719                     struct isoent       *rootent;
720                     enum vdd_type {
721                               VDD_PRIMARY,
722                               VDD_JOLIET,
723                               VDD_ENHANCED
724                     } vdd_type;
725 
726                     struct path_table {
727                               struct isoent                 *first;
728                               struct isoent                 **last;
729                               struct isoent                 **sorted;
730                               int                            cnt;
731                     } *pathtbl;
732                     int                                      max_depth;
733 
734                     int                  path_table_block;
735                     int                  path_table_size;
736                     int                  location_type_L_path_table;
737                     int                  location_type_M_path_table;
738                     int                  total_dir_block;
739           } primary, joliet;
740 
741           /* Used for making a Volume Descriptor. */
742           int                            volume_space_size;
743           int                            volume_sequence_number;
744           int                            total_file_block;
745           struct archive_string          volume_identifier;
746           struct archive_string          publisher_identifier;
747           struct archive_string          data_preparer_identifier;
748           struct archive_string          application_identifier;
749           struct archive_string          copyright_file_identifier;
750           struct archive_string          abstract_file_identifier;
751           struct archive_string          bibliographic_file_identifier;
752 
753           /* Used for making rockridge extensions. */
754           int                            location_rrip_er;
755 
756           /* Used for making zisofs. */
757           struct {
758                     signed int           detect_magic:1;
759                     signed int           making:1;
760                     signed int           allzero:1;
761                     unsigned char        magic_buffer[64];
762                     int                  magic_cnt;
763 
764 #ifdef HAVE_ZLIB_H
765                     /*
766                      * Copy a compressed file to iso9660.zisofs.temp_fd
767                      * and also copy a uncompressed file(original file) to
768                      * iso9660.temp_fd . If the number of logical block
769                      * of the compressed file is less than the number of
770                      * logical block of the uncompressed file, use it and
771                      * remove the copy of the uncompressed file.
772                      * but if not, we use uncompressed file and remove
773                      * the copy of the compressed file.
774                      */
775                     uint32_t  *block_pointers;
776                     size_t               block_pointers_allocated;
777                     int                  block_pointers_cnt;
778                     int                  block_pointers_idx;
779                     int64_t              total_size;
780                     int64_t              block_offset;
781 
782                     z_stream   stream;
783                     int                  stream_valid;
784                     int64_t              remaining;
785                     int                  compression_level;
786 #endif
787           } zisofs;
788 
789           struct isoent                 *directories_too_deep;
790           int                            dircnt_max;
791 
792           /* Write buffer. */
793 #define wb_buffmax()          (LOGICAL_BLOCK_SIZE * 32)
794 #define wb_remaining(a)       (((struct iso9660 *)(a)->format_data)->wbuff_remaining)
795 #define wb_offset(a)          (((struct iso9660 *)(a)->format_data)->wbuff_offset \
796                     + wb_buffmax() - wb_remaining(a))
797           unsigned char                  wbuff[LOGICAL_BLOCK_SIZE * 32];
798           size_t                         wbuff_remaining;
799           enum {
800                     WB_TO_STREAM,
801                     WB_TO_TEMP
802           }                              wbuff_type;
803           int64_t                        wbuff_offset;
804           int64_t                        wbuff_written;
805           int64_t                        wbuff_tail;
806 
807           /* 'El Torito' boot data. */
808           struct {
809                     /* boot catalog file */
810                     struct archive_string          catalog_filename;
811                     struct isoent                 *catalog;
812                     /* boot image file */
813                     struct archive_string          boot_filename;
814                     struct isoent                 *boot;
815 
816                     unsigned char                  platform_id;
817 #define BOOT_PLATFORM_X86     0
818 #define BOOT_PLATFORM_PPC     1
819 #define BOOT_PLATFORM_MAC     2
820                     struct archive_string          id;
821                     unsigned char                  media_type;
822 #define BOOT_MEDIA_NO_EMULATION                   0
823 #define BOOT_MEDIA_1_2M_DISKETTE        1
824 #define BOOT_MEDIA_1_44M_DISKETTE       2
825 #define BOOT_MEDIA_2_88M_DISKETTE       3
826 #define BOOT_MEDIA_HARD_DISK            4
827                     unsigned char                  system_type;
828                     uint16_t             boot_load_seg;
829                     uint16_t             boot_load_size;
830 #define BOOT_LOAD_SIZE                  4
831           } el_torito;
832 
833           struct iso_option    opt;
834 };
835 
836 /*
837  * Types of Volume Descriptor
838  */
839 enum VD_type {
840           VDT_BOOT_RECORD=0,  /* Boot Record Volume Descriptor        */
841           VDT_PRIMARY=1,                /* Primary Volume Descriptor            */
842           VDT_SUPPLEMENTARY=2,          /* Supplementary Volume Descriptor      */
843           VDT_TERMINATOR=255  /* Volume Descriptor Set Terminator     */
844 };
845 
846 /*
847  * Types of Directory Record
848  */
849 enum dir_rec_type {
850           DIR_REC_VD,                   /* Stored in Volume Descriptor.         */
851           DIR_REC_SELF,                 /* Stored as Current Directory.         */
852           DIR_REC_PARENT,               /* Stored as Parent Directory.          */
853           DIR_REC_NORMAL                /* Stored as Child.           */
854 };
855 
856 /*
857  * Kinds of Volume Descriptor Character
858  */
859 enum vdc {
860           VDC_STD,
861           VDC_LOWERCASE,
862           VDC_UCS2,
863           VDC_UCS2_DIRECT
864 };
865 
866 /*
867  * IDentifier Resolver.
868  * Used for resolving duplicated filenames.
869  */
870 struct idr {
871           struct idrent {
872                     struct archive_rb_node        rbnode;
873                     /* Used in wait_list. */
874                     struct idrent                 *wnext;
875                     struct idrent                 *avail;
876 
877                     struct isoent                 *isoent;
878                     int                            weight;
879                     int                            noff;
880                     int                            rename_num;
881           } *idrent_pool;
882 
883           struct archive_rb_tree                   rbtree;
884 
885           struct {
886                     struct idrent                 *first;
887                     struct idrent                 **last;
888           } wait_list;
889 
890           int                                      pool_size;
891           int                                      pool_idx;
892           int                                      num_size;
893           int                                      null_size;
894 
895           char                                     char_map[0x80];
896 };
897 
898 enum char_type {
899           A_CHAR,
900           D_CHAR
901 };
902 
903 
904 static int          iso9660_options(struct archive_write *,
905                         const char *, const char *);
906 static int          iso9660_write_header(struct archive_write *,
907                         struct archive_entry *);
908 static ssize_t      iso9660_write_data(struct archive_write *,
909                         const void *, size_t);
910 static int          iso9660_finish_entry(struct archive_write *);
911 static int          iso9660_close(struct archive_write *);
912 static int          iso9660_free(struct archive_write *);
913 
914 static void         get_system_identitier(char *, size_t);
915 static void         set_str(unsigned char *, const char *, size_t, char,
916                         const char *);
917 static inline int joliet_allowed_char(unsigned char, unsigned char);
918 static int          set_str_utf16be(struct archive_write *, unsigned char *,
919                               const char *, size_t, uint16_t, enum vdc);
920 static int          set_str_a_characters_bp(struct archive_write *,
921                               unsigned char *, int, int, const char *, enum vdc);
922 static int          set_str_d_characters_bp(struct archive_write *,
923                               unsigned char *, int, int, const char *, enum  vdc);
924 static void         set_VD_bp(unsigned char *, enum VD_type, unsigned char);
925 static inline void set_unused_field_bp(unsigned char *, int, int);
926 
927 static unsigned char *extra_open_record(unsigned char *, int,
928                         struct isoent *, struct ctl_extr_rec *);
929 static void         extra_close_record(struct ctl_extr_rec *, int);
930 static unsigned char * extra_next_record(struct ctl_extr_rec *, int);
931 static unsigned char *extra_get_record(struct isoent *, int *, int *, int *);
932 static void         extra_tell_used_size(struct ctl_extr_rec *, int);
933 static int          extra_setup_location(struct isoent *, int);
934 static int          set_directory_record_rr(unsigned char *, int,
935                         struct isoent *, struct iso9660 *, enum dir_rec_type);
936 static int          set_directory_record(unsigned char *, size_t,
937                         struct isoent *, struct iso9660 *, enum dir_rec_type,
938                         enum vdd_type);
939 static inline int get_dir_rec_size(struct iso9660 *, struct isoent *,
940                         enum dir_rec_type, enum vdd_type);
941 static inline unsigned char *wb_buffptr(struct archive_write *);
942 static int          wb_write_out(struct archive_write *);
943 static int          wb_consume(struct archive_write *, size_t);
944 #ifdef HAVE_ZLIB_H
945 static int          wb_set_offset(struct archive_write *, int64_t);
946 #endif
947 static int          write_null(struct archive_write *, size_t);
948 static int          write_VD_terminator(struct archive_write *);
949 static int          set_file_identifier(unsigned char *, int, int, enum vdc,
950                         struct archive_write *, struct vdd *,
951                         struct archive_string *, const char *, int,
952                         enum char_type);
953 static int          write_VD(struct archive_write *, struct vdd *);
954 static int          write_VD_boot_record(struct archive_write *);
955 static int          write_information_block(struct archive_write *);
956 static int          write_path_table(struct archive_write *, int,
957                         struct vdd *);
958 static int          write_directory_descriptors(struct archive_write *,
959                         struct vdd *);
960 static int          write_file_descriptors(struct archive_write *);
961 static int          write_rr_ER(struct archive_write *);
962 static void         calculate_path_table_size(struct vdd *);
963 
964 static void         isofile_init_entry_list(struct iso9660 *);
965 static void         isofile_add_entry(struct iso9660 *, struct isofile *);
966 static void         isofile_free_all_entries(struct iso9660 *);
967 static void         isofile_init_entry_data_file_list(struct iso9660 *);
968 static void         isofile_add_data_file(struct iso9660 *, struct isofile *);
969 static struct isofile * isofile_new(struct archive_write *,
970                         struct archive_entry *);
971 static void         isofile_free(struct isofile *);
972 static int          isofile_gen_utility_names(struct archive_write *,
973                         struct isofile *);
974 static int          isofile_register_hardlink(struct archive_write *,
975                         struct isofile *);
976 static void         isofile_connect_hardlink_files(struct iso9660 *);
977 static void         isofile_init_hardlinks(struct iso9660 *);
978 static void         isofile_free_hardlinks(struct iso9660 *);
979 
980 static struct isoent *isoent_new(struct isofile *);
981 static int          isoent_clone_tree(struct archive_write *,
982                         struct isoent **, struct isoent *);
983 static void         _isoent_free(struct isoent *isoent);
984 static void         isoent_free_all(struct isoent *);
985 static struct isoent * isoent_create_virtual_dir(struct archive_write *,
986                         struct iso9660 *, const char *);
987 static int          isoent_cmp_node(const struct archive_rb_node *,
988                         const struct archive_rb_node *);
989 static int          isoent_cmp_key(const struct archive_rb_node *,
990                         const void *);
991 static int          isoent_add_child_head(struct isoent *, struct isoent *);
992 static int          isoent_add_child_tail(struct isoent *, struct isoent *);
993 static void         isoent_remove_child(struct isoent *, struct isoent *);
994 static void         isoent_setup_directory_location(struct iso9660 *,
995                         int, struct vdd *);
996 static void         isoent_setup_file_location(struct iso9660 *, int);
997 static int          get_path_component(char *, size_t, const char *);
998 static int          isoent_tree(struct archive_write *, struct isoent **);
999 static struct isoent *isoent_find_child(struct isoent *, const char *);
1000 static struct isoent *isoent_find_entry(struct isoent *, const char *);
1001 static void         idr_relaxed_filenames(char *);
1002 static void         idr_init(struct iso9660 *, struct vdd *, struct idr *);
1003 static void         idr_cleanup(struct idr *);
1004 static int          idr_ensure_poolsize(struct archive_write *, struct idr *,
1005                         int);
1006 static int          idr_start(struct archive_write *, struct idr *,
1007                         int, int, int, int, const struct archive_rb_tree_ops *);
1008 static void         idr_register(struct idr *, struct isoent *, int,
1009                         int);
1010 static void         idr_extend_identifier(struct idrent *, int, int);
1011 static void         idr_resolve(struct idr *, void (*)(unsigned char *, int));
1012 static void         idr_set_num(unsigned char *, int);
1013 static void         idr_set_num_beutf16(unsigned char *, int);
1014 static int          isoent_gen_iso9660_identifier(struct archive_write *,
1015                         struct isoent *, struct idr *);
1016 static int          isoent_gen_joliet_identifier(struct archive_write *,
1017                         struct isoent *, struct idr *);
1018 static int          isoent_cmp_iso9660_identifier(const struct isoent *,
1019                         const struct isoent *);
1020 static int          isoent_cmp_node_iso9660(const struct archive_rb_node *,
1021                         const struct archive_rb_node *);
1022 static int          isoent_cmp_key_iso9660(const struct archive_rb_node *,
1023                         const void *);
1024 static int          isoent_cmp_joliet_identifier(const struct isoent *,
1025                         const struct isoent *);
1026 static int          isoent_cmp_node_joliet(const struct archive_rb_node *,
1027                         const struct archive_rb_node *);
1028 static int          isoent_cmp_key_joliet(const struct archive_rb_node *,
1029                         const void *);
1030 static inline void path_table_add_entry(struct path_table *, struct isoent *);
1031 static inline struct isoent * path_table_last_entry(struct path_table *);
1032 static int          isoent_make_path_table(struct archive_write *);
1033 static int          isoent_find_out_boot_file(struct archive_write *,
1034                         struct isoent *);
1035 static int          isoent_create_boot_catalog(struct archive_write *,
1036                         struct isoent *);
1037 static size_t       fd_boot_image_size(int);
1038 static int          make_boot_catalog(struct archive_write *);
1039 static int          setup_boot_information(struct archive_write *);
1040 
1041 static int          zisofs_init(struct archive_write *, struct isofile *);
1042 static void         zisofs_detect_magic(struct archive_write *,
1043                         const void *, size_t);
1044 static int          zisofs_write_to_temp(struct archive_write *,
1045                         const void *, size_t);
1046 static int          zisofs_finish_entry(struct archive_write *);
1047 static int          zisofs_rewind_boot_file(struct archive_write *);
1048 static int          zisofs_free(struct archive_write *);
1049 
1050 int
archive_write_set_format_iso9660(struct archive * _a)1051 archive_write_set_format_iso9660(struct archive *_a)
1052 {
1053           struct archive_write *a = (struct archive_write *)_a;
1054           struct iso9660 *iso9660;
1055 
1056           archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
1057               ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");
1058 
1059           /* If another format was already registered, unregister it. */
1060           if (a->format_free != NULL)
1061                     (a->format_free)(a);
1062 
1063           iso9660 = calloc(1, sizeof(*iso9660));
1064           if (iso9660 == NULL) {
1065                     archive_set_error(&a->archive, ENOMEM,
1066                         "Can't allocate iso9660 data");
1067                     return (ARCHIVE_FATAL);
1068           }
1069           iso9660->birth_time = 0;
1070           iso9660->temp_fd = -1;
1071           iso9660->cur_file = NULL;
1072           iso9660->primary.max_depth = 0;
1073           iso9660->primary.vdd_type = VDD_PRIMARY;
1074           iso9660->primary.pathtbl = NULL;
1075           iso9660->joliet.rootent = NULL;
1076           iso9660->joliet.max_depth = 0;
1077           iso9660->joliet.vdd_type = VDD_JOLIET;
1078           iso9660->joliet.pathtbl = NULL;
1079           isofile_init_entry_list(iso9660);
1080           isofile_init_entry_data_file_list(iso9660);
1081           isofile_init_hardlinks(iso9660);
1082           iso9660->directories_too_deep = NULL;
1083           iso9660->dircnt_max = 1;
1084           iso9660->wbuff_remaining = wb_buffmax();
1085           iso9660->wbuff_type = WB_TO_TEMP;
1086           iso9660->wbuff_offset = 0;
1087           iso9660->wbuff_written = 0;
1088           iso9660->wbuff_tail = 0;
1089           archive_string_init(&(iso9660->utf16be));
1090           archive_string_init(&(iso9660->mbs));
1091 
1092           /*
1093            * Init Identifiers used for PVD and SVD.
1094            */
1095           archive_string_init(&(iso9660->volume_identifier));
1096           archive_strcpy(&(iso9660->volume_identifier), "CDROM");
1097           archive_string_init(&(iso9660->publisher_identifier));
1098           archive_string_init(&(iso9660->data_preparer_identifier));
1099           archive_string_init(&(iso9660->application_identifier));
1100           archive_strcpy(&(iso9660->application_identifier),
1101               archive_version_string());
1102           archive_string_init(&(iso9660->copyright_file_identifier));
1103           archive_string_init(&(iso9660->abstract_file_identifier));
1104           archive_string_init(&(iso9660->bibliographic_file_identifier));
1105 
1106           /*
1107            * Init El Torito bootable CD variables.
1108            */
1109           archive_string_init(&(iso9660->el_torito.catalog_filename));
1110           iso9660->el_torito.catalog = NULL;
1111           /* Set default file name of boot catalog  */
1112           archive_strcpy(&(iso9660->el_torito.catalog_filename),
1113               "boot.catalog");
1114           archive_string_init(&(iso9660->el_torito.boot_filename));
1115           iso9660->el_torito.boot = NULL;
1116           iso9660->el_torito.platform_id = BOOT_PLATFORM_X86;
1117           archive_string_init(&(iso9660->el_torito.id));
1118           iso9660->el_torito.boot_load_seg = 0;
1119           iso9660->el_torito.boot_load_size = BOOT_LOAD_SIZE;
1120 
1121           /*
1122            * Init zisofs variables.
1123            */
1124 #ifdef HAVE_ZLIB_H
1125           iso9660->zisofs.block_pointers = NULL;
1126           iso9660->zisofs.block_pointers_allocated = 0;
1127           iso9660->zisofs.stream_valid = 0;
1128           iso9660->zisofs.compression_level = 9;
1129           memset(&(iso9660->zisofs.stream), 0,
1130               sizeof(iso9660->zisofs.stream));
1131 #endif
1132 
1133           /*
1134            * Set default value of iso9660 options.
1135            */
1136           iso9660->opt.abstract_file = OPT_ABSTRACT_FILE_DEFAULT;
1137           iso9660->opt.application_id = OPT_APPLICATION_ID_DEFAULT;
1138           iso9660->opt.allow_vernum = OPT_ALLOW_VERNUM_DEFAULT;
1139           iso9660->opt.biblio_file = OPT_BIBLIO_FILE_DEFAULT;
1140           iso9660->opt.boot = OPT_BOOT_DEFAULT;
1141           iso9660->opt.boot_catalog = OPT_BOOT_CATALOG_DEFAULT;
1142           iso9660->opt.boot_info_table = OPT_BOOT_INFO_TABLE_DEFAULT;
1143           iso9660->opt.boot_load_seg = OPT_BOOT_LOAD_SEG_DEFAULT;
1144           iso9660->opt.boot_load_size = OPT_BOOT_LOAD_SIZE_DEFAULT;
1145           iso9660->opt.boot_type = OPT_BOOT_TYPE_DEFAULT;
1146           iso9660->opt.compression_level = OPT_COMPRESSION_LEVEL_DEFAULT;
1147           iso9660->opt.copyright_file = OPT_COPYRIGHT_FILE_DEFAULT;
1148           iso9660->opt.iso_level = OPT_ISO_LEVEL_DEFAULT;
1149           iso9660->opt.joliet = OPT_JOLIET_DEFAULT;
1150           iso9660->opt.limit_depth = OPT_LIMIT_DEPTH_DEFAULT;
1151           iso9660->opt.limit_dirs = OPT_LIMIT_DIRS_DEFAULT;
1152           iso9660->opt.pad = OPT_PAD_DEFAULT;
1153           iso9660->opt.publisher = OPT_PUBLISHER_DEFAULT;
1154           iso9660->opt.rr = OPT_RR_DEFAULT;
1155           iso9660->opt.volume_id = OPT_VOLUME_ID_DEFAULT;
1156           iso9660->opt.zisofs = OPT_ZISOFS_DEFAULT;
1157 
1158           /* Create the root directory. */
1159           iso9660->primary.rootent =
1160               isoent_create_virtual_dir(a, iso9660, "");
1161           if (iso9660->primary.rootent == NULL) {
1162                     free(iso9660);
1163                     archive_set_error(&a->archive, ENOMEM,
1164                         "Can't allocate memory");
1165                     return (ARCHIVE_FATAL);
1166           }
1167           iso9660->primary.rootent->parent = iso9660->primary.rootent;
1168           iso9660->cur_dirent = iso9660->primary.rootent;
1169           archive_string_init(&(iso9660->cur_dirstr));
1170           archive_string_ensure(&(iso9660->cur_dirstr), 1);
1171           iso9660->cur_dirstr.s[0] = 0;
1172           iso9660->sconv_to_utf16be = NULL;
1173           iso9660->sconv_from_utf16be = NULL;
1174 
1175           a->format_data = iso9660;
1176           a->format_name = "iso9660";
1177           a->format_options = iso9660_options;
1178           a->format_write_header = iso9660_write_header;
1179           a->format_write_data = iso9660_write_data;
1180           a->format_finish_entry = iso9660_finish_entry;
1181           a->format_close = iso9660_close;
1182           a->format_free = iso9660_free;
1183           a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
1184           a->archive.archive_format_name = "ISO9660";
1185 
1186           return (ARCHIVE_OK);
1187 }
1188 
1189 static int
get_str_opt(struct archive_write * a,struct archive_string * s,size_t maxsize,const char * key,const char * value)1190 get_str_opt(struct archive_write *a, struct archive_string *s,
1191     size_t maxsize, const char *key, const char *value)
1192 {
1193 
1194           if (strlen(value) > maxsize) {
1195                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1196                         "Value is longer than %zu characters "
1197                         "for option ``%s''", maxsize, key);
1198                     return (ARCHIVE_FATAL);
1199           }
1200           archive_strcpy(s, value);
1201           return (ARCHIVE_OK);
1202 }
1203 
1204 static int
get_num_opt(struct archive_write * a,int * num,int high,int low,const char * key,const char * value)1205 get_num_opt(struct archive_write *a, int *num, int high, int low,
1206     const char *key, const char *value)
1207 {
1208           const char *p = value;
1209           int data = 0;
1210           int neg = 0;
1211 
1212           if (p == NULL) {
1213                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1214                         "Invalid value(empty) for option ``%s''", key);
1215                     return (ARCHIVE_FATAL);
1216           }
1217           if (*p == '-') {
1218                     neg = 1;
1219                     p++;
1220           }
1221           while (*p) {
1222                     if (*p >= '0' && *p <= '9')
1223                               data = data * 10 + *p - '0';
1224                     else {
1225                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1226                                   "Invalid value for option ``%s''", key);
1227                               return (ARCHIVE_FATAL);
1228                     }
1229                     if (data > high) {
1230                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1231                                   "Invalid value(over %d) for "
1232                                   "option ``%s''", high, key);
1233                               return (ARCHIVE_FATAL);
1234                     }
1235                     if (data < low) {
1236                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1237                                   "Invalid value(under %d) for "
1238                                   "option ``%s''", low, key);
1239                               return (ARCHIVE_FATAL);
1240                     }
1241                     p++;
1242           }
1243           if (neg)
1244                     data *= -1;
1245           *num = data;
1246 
1247           return (ARCHIVE_OK);
1248 }
1249 
1250 static int
iso9660_options(struct archive_write * a,const char * key,const char * value)1251 iso9660_options(struct archive_write *a, const char *key, const char *value)
1252 {
1253           struct iso9660 *iso9660 = a->format_data;
1254           const char *p;
1255           int r;
1256 
1257           switch (key[0]) {
1258           case 'a':
1259                     if (strcmp(key, "abstract-file") == 0) {
1260                               r = get_str_opt(a,
1261                                   &(iso9660->abstract_file_identifier),
1262                                   ABSTRACT_FILE_SIZE, key, value);
1263                               iso9660->opt.abstract_file = r == ARCHIVE_OK;
1264                               return (r);
1265                     }
1266                     if (strcmp(key, "application-id") == 0) {
1267                               r = get_str_opt(a,
1268                                   &(iso9660->application_identifier),
1269                                   APPLICATION_IDENTIFIER_SIZE, key, value);
1270                               iso9660->opt.application_id = r == ARCHIVE_OK;
1271                               return (r);
1272                     }
1273                     if (strcmp(key, "allow-vernum") == 0) {
1274                               iso9660->opt.allow_vernum = value != NULL;
1275                               return (ARCHIVE_OK);
1276                     }
1277                     break;
1278           case 'b':
1279                     if (strcmp(key, "biblio-file") == 0) {
1280                               r = get_str_opt(a,
1281                                   &(iso9660->bibliographic_file_identifier),
1282                                   BIBLIO_FILE_SIZE, key, value);
1283                               iso9660->opt.biblio_file = r == ARCHIVE_OK;
1284                               return (r);
1285                     }
1286                     if (strcmp(key, "boot") == 0) {
1287                               if (value == NULL)
1288                                         iso9660->opt.boot = 0;
1289                               else {
1290                                         iso9660->opt.boot = 1;
1291                                         archive_strcpy(
1292                                             &(iso9660->el_torito.boot_filename),
1293                                             value);
1294                               }
1295                               return (ARCHIVE_OK);
1296                     }
1297                     if (strcmp(key, "boot-catalog") == 0) {
1298                               r = get_str_opt(a,
1299                                   &(iso9660->el_torito.catalog_filename),
1300                                   1024, key, value);
1301                               iso9660->opt.boot_catalog = r == ARCHIVE_OK;
1302                               return (r);
1303                     }
1304                     if (strcmp(key, "boot-info-table") == 0) {
1305                               iso9660->opt.boot_info_table = value != NULL;
1306                               return (ARCHIVE_OK);
1307                     }
1308                     if (strcmp(key, "boot-load-seg") == 0) {
1309                               uint32_t seg;
1310 
1311                               iso9660->opt.boot_load_seg = 0;
1312                               if (value == NULL)
1313                                         goto invalid_value;
1314                               seg = 0;
1315                               p = value;
1316                               if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
1317                                         p += 2;
1318                               while (*p) {
1319                                         if (seg)
1320                                                   seg <<= 4;
1321                                         if (*p >= 'A' && *p <= 'F')
1322                                                   seg += *p - 'A' + 0x0a;
1323                                         else if (*p >= 'a' && *p <= 'f')
1324                                                   seg += *p - 'a' + 0x0a;
1325                                         else if (*p >= '0' && *p <= '9')
1326                                                   seg += *p - '0';
1327                                         else
1328                                                   goto invalid_value;
1329                                         if (seg > 0xffff) {
1330                                                   archive_set_error(&a->archive,
1331                                                       ARCHIVE_ERRNO_MISC,
1332                                                       "Invalid value(over 0xffff) for "
1333                                                       "option ``%s''", key);
1334                                                   return (ARCHIVE_FATAL);
1335                                         }
1336                                         p++;
1337                               }
1338                               iso9660->el_torito.boot_load_seg = (uint16_t)seg;
1339                               iso9660->opt.boot_load_seg = 1;
1340                               return (ARCHIVE_OK);
1341                     }
1342                     if (strcmp(key, "boot-load-size") == 0) {
1343                               int num = 0;
1344                               r = get_num_opt(a, &num, 0xffff, 1, key, value);
1345                               iso9660->opt.boot_load_size = r == ARCHIVE_OK;
1346                               if (r != ARCHIVE_OK)
1347                                         return (ARCHIVE_FATAL);
1348                               iso9660->el_torito.boot_load_size = (uint16_t)num;
1349                               return (ARCHIVE_OK);
1350                     }
1351                     if (strcmp(key, "boot-type") == 0) {
1352                               if (value == NULL)
1353                                         goto invalid_value;
1354                               if (strcmp(value, "no-emulation") == 0)
1355                                         iso9660->opt.boot_type = OPT_BOOT_TYPE_NO_EMU;
1356                               else if (strcmp(value, "fd") == 0)
1357                                         iso9660->opt.boot_type = OPT_BOOT_TYPE_FD;
1358                               else if (strcmp(value, "hard-disk") == 0)
1359                                         iso9660->opt.boot_type = OPT_BOOT_TYPE_HARD_DISK;
1360                               else
1361                                         goto invalid_value;
1362                               return (ARCHIVE_OK);
1363                     }
1364                     break;
1365           case 'c':
1366                     if (strcmp(key, "compression-level") == 0) {
1367 #ifdef HAVE_ZLIB_H
1368                               if (value == NULL ||
1369                                   !(value[0] >= '0' && value[0] <= '9') ||
1370                                   value[1] != '\0')
1371                                         goto invalid_value;
1372                     iso9660->zisofs.compression_level = value[0] - '0';
1373                               iso9660->opt.compression_level = 1;
1374                     return (ARCHIVE_OK);
1375 #else
1376                               archive_set_error(&a->archive,
1377                                   ARCHIVE_ERRNO_MISC,
1378                                   "Option ``%s'' "
1379                                   "is not supported on this platform.", key);
1380                               return (ARCHIVE_FATAL);
1381 #endif
1382                     }
1383                     if (strcmp(key, "copyright-file") == 0) {
1384                               r = get_str_opt(a,
1385                                   &(iso9660->copyright_file_identifier),
1386                                   COPYRIGHT_FILE_SIZE, key, value);
1387                               iso9660->opt.copyright_file = r == ARCHIVE_OK;
1388                               return (r);
1389                     }
1390 #ifdef DEBUG
1391                     /* Specifies Volume creation date and time;
1392                      * year(4),month(2),day(2),hour(2),minute(2),second(2).
1393                      * e.g. "20090929033757"
1394                      */
1395                     if (strcmp(key, "creation") == 0) {
1396                               struct tm tm;
1397                               char buf[5];
1398 
1399                               p = value;
1400                               if (p == NULL || strlen(p) < 14)
1401                                         goto invalid_value;
1402                               memset(&tm, 0, sizeof(tm));
1403                               memcpy(buf, p, 4); buf[4] = '\0'; p += 4;
1404                               tm.tm_year = strtol(buf, NULL, 10) - 1900;
1405                               memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1406                               tm.tm_mon = strtol(buf, NULL, 10) - 1;
1407                               memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1408                               tm.tm_mday = strtol(buf, NULL, 10);
1409                               memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1410                               tm.tm_hour = strtol(buf, NULL, 10);
1411                               memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
1412                               tm.tm_min = strtol(buf, NULL, 10);
1413                               memcpy(buf, p, 2); buf[2] = '\0';
1414                               tm.tm_sec = strtol(buf, NULL, 10);
1415                               iso9660->birth_time = mktime(&tm);
1416                               return (ARCHIVE_OK);
1417                     }
1418 #endif
1419                     break;
1420           case 'i':
1421                     if (strcmp(key, "iso-level") == 0) {
1422                               if (value != NULL && value[1] == '\0' &&
1423                                   (value[0] >= '1' && value[0] <= '4')) {
1424                                         iso9660->opt.iso_level = value[0]-'0';
1425                                         return (ARCHIVE_OK);
1426                               }
1427                               goto invalid_value;
1428                     }
1429                     break;
1430           case 'j':
1431                     if (strcmp(key, "joliet") == 0) {
1432                               if (value == NULL)
1433                                         iso9660->opt.joliet = OPT_JOLIET_DISABLE;
1434                               else if (strcmp(value, "1") == 0)
1435                                         iso9660->opt.joliet = OPT_JOLIET_ENABLE;
1436                               else if (strcmp(value, "long") == 0)
1437                                         iso9660->opt.joliet = OPT_JOLIET_LONGNAME;
1438                               else
1439                                         goto invalid_value;
1440                               return (ARCHIVE_OK);
1441                     }
1442                     break;
1443           case 'l':
1444                     if (strcmp(key, "limit-depth") == 0) {
1445                               iso9660->opt.limit_depth = value != NULL;
1446                               return (ARCHIVE_OK);
1447                     }
1448                     if (strcmp(key, "limit-dirs") == 0) {
1449                               iso9660->opt.limit_dirs = value != NULL;
1450                               return (ARCHIVE_OK);
1451                     }
1452                     break;
1453           case 'p':
1454                     if (strcmp(key, "pad") == 0) {
1455                               iso9660->opt.pad = value != NULL;
1456                               return (ARCHIVE_OK);
1457                     }
1458                     if (strcmp(key, "publisher") == 0) {
1459                               r = get_str_opt(a,
1460                                   &(iso9660->publisher_identifier),
1461                                   PUBLISHER_IDENTIFIER_SIZE, key, value);
1462                               iso9660->opt.publisher = r == ARCHIVE_OK;
1463                               return (r);
1464                     }
1465                     break;
1466           case 'r':
1467                     if (strcmp(key, "rockridge") == 0 ||
1468                         strcmp(key, "Rockridge") == 0) {
1469                               if (value == NULL)
1470                                         iso9660->opt.rr = OPT_RR_DISABLED;
1471                               else if (strcmp(value, "1") == 0)
1472                                         iso9660->opt.rr = OPT_RR_USEFUL;
1473                               else if (strcmp(value, "strict") == 0)
1474                                         iso9660->opt.rr = OPT_RR_STRICT;
1475                               else if (strcmp(value, "useful") == 0)
1476                                         iso9660->opt.rr = OPT_RR_USEFUL;
1477                               else
1478                                         goto invalid_value;
1479                               return (ARCHIVE_OK);
1480                     }
1481                     break;
1482           case 'v':
1483                     if (strcmp(key, "volume-id") == 0) {
1484                               r = get_str_opt(a, &(iso9660->volume_identifier),
1485                                   VOLUME_IDENTIFIER_SIZE, key, value);
1486                               iso9660->opt.volume_id = r == ARCHIVE_OK;
1487                               return (r);
1488                     }
1489                     break;
1490           case 'z':
1491                     if (strcmp(key, "zisofs") == 0) {
1492                               if (value == NULL)
1493                                         iso9660->opt.zisofs = OPT_ZISOFS_DISABLED;
1494                               else {
1495 #ifdef HAVE_ZLIB_H
1496                                         iso9660->opt.zisofs = OPT_ZISOFS_DIRECT;
1497 #else
1498                                         archive_set_error(&a->archive,
1499                                             ARCHIVE_ERRNO_MISC,
1500                                             "``zisofs'' "
1501                                             "is not supported on this platform.");
1502                                         return (ARCHIVE_FATAL);
1503 #endif
1504                               }
1505                               return (ARCHIVE_OK);
1506                     }
1507                     break;
1508           }
1509 
1510           /* Note: The "warn" return is just to inform the options
1511            * supervisor that we didn't handle it.  It will generate
1512            * a suitable error if no one used this option. */
1513           return (ARCHIVE_WARN);
1514 
1515 invalid_value:
1516           archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1517               "Invalid value for option ``%s''", key);
1518           return (ARCHIVE_FAILED);
1519 }
1520 
1521 static int
iso9660_write_header(struct archive_write * a,struct archive_entry * entry)1522 iso9660_write_header(struct archive_write *a, struct archive_entry *entry)
1523 {
1524           struct iso9660 *iso9660;
1525           struct isofile *file;
1526           struct isoent *isoent;
1527           int r, ret = ARCHIVE_OK;
1528 
1529           iso9660 = a->format_data;
1530 
1531           iso9660->cur_file = NULL;
1532           iso9660->bytes_remaining = 0;
1533           iso9660->need_multi_extent = 0;
1534           if (archive_entry_filetype(entry) == AE_IFLNK
1535               && iso9660->opt.rr == OPT_RR_DISABLED) {
1536                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1537                         "Ignore symlink file.");
1538                     iso9660->cur_file = NULL;
1539                     return (ARCHIVE_WARN);
1540           }
1541           if (archive_entry_filetype(entry) == AE_IFREG &&
1542               archive_entry_size(entry) >= MULTI_EXTENT_SIZE) {
1543                     if (iso9660->opt.iso_level < 3) {
1544                               archive_set_error(&a->archive,
1545                                   ARCHIVE_ERRNO_MISC,
1546                                   "Ignore over %lld bytes file. "
1547                                   "This file too large.",
1548                                   MULTI_EXTENT_SIZE);
1549                                         iso9660->cur_file = NULL;
1550                               return (ARCHIVE_WARN);
1551                     }
1552                     iso9660->need_multi_extent = 1;
1553           }
1554 
1555           file = isofile_new(a, entry);
1556           if (file == NULL) {
1557                     archive_set_error(&a->archive, ENOMEM,
1558                         "Can't allocate data");
1559                     return (ARCHIVE_FATAL);
1560           }
1561           r = isofile_gen_utility_names(a, file);
1562           if (r < ARCHIVE_WARN) {
1563                     isofile_free(file);
1564                     return (r);
1565           }
1566           else if (r < ret)
1567                     ret = r;
1568 
1569           /*
1570            * Ignore a path which looks like the top of directory name
1571            * since we have already made the root directory of an ISO image.
1572            */
1573           if (archive_strlen(&(file->parentdir)) == 0 &&
1574               archive_strlen(&(file->basename)) == 0) {
1575                     isofile_free(file);
1576                     return (r);
1577           }
1578 
1579           isofile_add_entry(iso9660, file);
1580           isoent = isoent_new(file);
1581           if (isoent == NULL) {
1582                     archive_set_error(&a->archive, ENOMEM,
1583                         "Can't allocate data");
1584                     return (ARCHIVE_FATAL);
1585           }
1586           if (isoent->file->dircnt > iso9660->dircnt_max)
1587                     iso9660->dircnt_max = isoent->file->dircnt;
1588 
1589           /* Add the current file into tree */
1590           r = isoent_tree(a, &isoent);
1591           if (r != ARCHIVE_OK)
1592                     return (r);
1593 
1594           /* If there is the same file in tree and
1595            * the current file is older than the file in tree.
1596            * So we don't need the current file data anymore. */
1597           if (isoent->file != file)
1598                     return (ARCHIVE_OK);
1599 
1600           /* Non regular files contents are unneeded to be saved to
1601            * temporary files. */
1602           if (archive_entry_filetype(file->entry) != AE_IFREG)
1603                     return (ret);
1604 
1605           /*
1606            * Set the current file to cur_file to read its contents.
1607            */
1608           iso9660->cur_file = file;
1609 
1610           if (archive_entry_nlink(file->entry) > 1) {
1611                     r = isofile_register_hardlink(a, file);
1612                     if (r != ARCHIVE_OK)
1613                               return (ARCHIVE_FATAL);
1614           }
1615 
1616           /*
1617            * Prepare to save the contents of the file.
1618            */
1619           if (iso9660->temp_fd < 0) {
1620                     iso9660->temp_fd = __archive_mktemp(NULL);
1621                     if (iso9660->temp_fd < 0) {
1622                               archive_set_error(&a->archive, errno,
1623                                   "Couldn't create temporary file");
1624                               return (ARCHIVE_FATAL);
1625                     }
1626           }
1627 
1628           /* Save an offset of current file in temporary file. */
1629           file->content.offset_of_temp = wb_offset(a);
1630           file->cur_content = &(file->content);
1631           r = zisofs_init(a, file);
1632           if (r < ret)
1633                     ret = r;
1634           iso9660->bytes_remaining =  archive_entry_size(file->entry);
1635 
1636           return (ret);
1637 }
1638 
1639 static int
write_to_temp(struct archive_write * a,const void * buff,size_t s)1640 write_to_temp(struct archive_write *a, const void *buff, size_t s)
1641 {
1642           struct iso9660 *iso9660 = a->format_data;
1643           ssize_t written;
1644           const unsigned char *b;
1645 
1646           b = (const unsigned char *)buff;
1647           while (s) {
1648                     written = write(iso9660->temp_fd, b, s);
1649                     if (written < 0) {
1650                               archive_set_error(&a->archive, errno,
1651                                   "Can't write to temporary file");
1652                               return (ARCHIVE_FATAL);
1653                     }
1654                     s -= written;
1655                     b += written;
1656           }
1657           return (ARCHIVE_OK);
1658 }
1659 
1660 static int
wb_write_to_temp(struct archive_write * a,const void * buff,size_t s)1661 wb_write_to_temp(struct archive_write *a, const void *buff, size_t s)
1662 {
1663           const char *xp = buff;
1664           size_t xs = s;
1665 
1666           /*
1667            * If a written data size is big enough to use system-call
1668            * and there is no waiting data, this calls write_to_temp() in
1669            * order to reduce a extra memory copy.
1670            */
1671           if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {
1672                     struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
1673                     xs = s % LOGICAL_BLOCK_SIZE;
1674                     iso9660->wbuff_offset += s - xs;
1675                     if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)
1676                               return (ARCHIVE_FATAL);
1677                     if (xs == 0)
1678                               return (ARCHIVE_OK);
1679                     xp += s - xs;
1680           }
1681 
1682           while (xs) {
1683                     size_t size = xs;
1684                     if (size > wb_remaining(a))
1685                               size = wb_remaining(a);
1686                     memcpy(wb_buffptr(a), xp, size);
1687                     if (wb_consume(a, size) != ARCHIVE_OK)
1688                               return (ARCHIVE_FATAL);
1689                     xs -= size;
1690                     xp += size;
1691           }
1692           return (ARCHIVE_OK);
1693 }
1694 
1695 static int
wb_write_padding_to_temp(struct archive_write * a,int64_t csize)1696 wb_write_padding_to_temp(struct archive_write *a, int64_t csize)
1697 {
1698           size_t ns;
1699           int ret;
1700 
1701           ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);
1702           if (ns != 0)
1703                     ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);
1704           else
1705                     ret = ARCHIVE_OK;
1706           return (ret);
1707 }
1708 
1709 static ssize_t
write_iso9660_data(struct archive_write * a,const void * buff,size_t s)1710 write_iso9660_data(struct archive_write *a, const void *buff, size_t s)
1711 {
1712           struct iso9660 *iso9660 = a->format_data;
1713           size_t ws;
1714 
1715           if (iso9660->temp_fd < 0) {
1716                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1717                         "Couldn't create temporary file");
1718                     return (ARCHIVE_FATAL);
1719           }
1720 
1721           ws = s;
1722           if (iso9660->need_multi_extent &&
1723               (iso9660->cur_file->cur_content->size + ws) >=
1724                 (MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE)) {
1725                     struct content *con;
1726                     size_t ts;
1727 
1728                     ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
1729                         iso9660->cur_file->cur_content->size);
1730 
1731                     if (iso9660->zisofs.detect_magic)
1732                               zisofs_detect_magic(a, buff, ts);
1733 
1734                     if (iso9660->zisofs.making) {
1735                               if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK)
1736                                         return (ARCHIVE_FATAL);
1737                     } else {
1738                               if (wb_write_to_temp(a, buff, ts) != ARCHIVE_OK)
1739                                         return (ARCHIVE_FATAL);
1740                               iso9660->cur_file->cur_content->size += ts;
1741                     }
1742 
1743                     /* Write padding. */
1744                     if (wb_write_padding_to_temp(a,
1745                         iso9660->cur_file->cur_content->size) != ARCHIVE_OK)
1746                               return (ARCHIVE_FATAL);
1747 
1748                     /* Compute the logical block number. */
1749                     iso9660->cur_file->cur_content->blocks = (int)
1750                         ((iso9660->cur_file->cur_content->size
1751                          + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
1752 
1753                     /*
1754                      * Make next extent.
1755                      */
1756                     ws -= ts;
1757                     buff = (const void *)(((const unsigned char *)buff) + ts);
1758                     /* Make a content for next extent. */
1759                     con = calloc(1, sizeof(*con));
1760                     if (con == NULL) {
1761                               archive_set_error(&a->archive, ENOMEM,
1762                                   "Can't allocate content data");
1763                               return (ARCHIVE_FATAL);
1764                     }
1765                     con->offset_of_temp = wb_offset(a);
1766                     iso9660->cur_file->cur_content->next = con;
1767                     iso9660->cur_file->cur_content = con;
1768 #ifdef HAVE_ZLIB_H
1769                     iso9660->zisofs.block_offset = 0;
1770 #endif
1771           }
1772 
1773           if (iso9660->zisofs.detect_magic)
1774                     zisofs_detect_magic(a, buff, ws);
1775 
1776           if (iso9660->zisofs.making) {
1777                     if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK)
1778                               return (ARCHIVE_FATAL);
1779           } else {
1780                     if (wb_write_to_temp(a, buff, ws) != ARCHIVE_OK)
1781                               return (ARCHIVE_FATAL);
1782                     iso9660->cur_file->cur_content->size += ws;
1783           }
1784 
1785           return (s);
1786 }
1787 
1788 static ssize_t
iso9660_write_data(struct archive_write * a,const void * buff,size_t s)1789 iso9660_write_data(struct archive_write *a, const void *buff, size_t s)
1790 {
1791           struct iso9660 *iso9660 = a->format_data;
1792           ssize_t r;
1793 
1794           if (iso9660->cur_file == NULL)
1795                     return (0);
1796           if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
1797                     return (0);
1798           if (s > iso9660->bytes_remaining)
1799                     s = (size_t)iso9660->bytes_remaining;
1800           if (s == 0)
1801                     return (0);
1802 
1803           r = write_iso9660_data(a, buff, s);
1804           if (r > 0)
1805                     iso9660->bytes_remaining -= r;
1806           return (r);
1807 }
1808 
1809 static int
iso9660_finish_entry(struct archive_write * a)1810 iso9660_finish_entry(struct archive_write *a)
1811 {
1812           struct iso9660 *iso9660 = a->format_data;
1813 
1814           if (iso9660->cur_file == NULL)
1815                     return (ARCHIVE_OK);
1816           if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
1817                     return (ARCHIVE_OK);
1818           if (iso9660->cur_file->content.size == 0)
1819                     return (ARCHIVE_OK);
1820 
1821           /* If there are unwritten data, write null data instead. */
1822           while (iso9660->bytes_remaining > 0) {
1823                     size_t s;
1824 
1825                     s = (iso9660->bytes_remaining > a->null_length)?
1826                         a->null_length: (size_t)iso9660->bytes_remaining;
1827                     if (write_iso9660_data(a, a->nulls, s) < 0)
1828                               return (ARCHIVE_FATAL);
1829                     iso9660->bytes_remaining -= s;
1830           }
1831 
1832           if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK)
1833                     return (ARCHIVE_FATAL);
1834 
1835           /* Write padding. */
1836           if (wb_write_padding_to_temp(a, iso9660->cur_file->cur_content->size)
1837               != ARCHIVE_OK)
1838                     return (ARCHIVE_FATAL);
1839 
1840           /* Compute the logical block number. */
1841           iso9660->cur_file->cur_content->blocks = (int)
1842               ((iso9660->cur_file->cur_content->size
1843                + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
1844 
1845           /* Add the current file to data file list. */
1846           isofile_add_data_file(iso9660, iso9660->cur_file);
1847 
1848           return (ARCHIVE_OK);
1849 }
1850 
1851 static int
iso9660_close(struct archive_write * a)1852 iso9660_close(struct archive_write *a)
1853 {
1854           struct iso9660 *iso9660;
1855           int ret, blocks;
1856 
1857           iso9660 = a->format_data;
1858 
1859           /*
1860            * Write remaining data out to the temporary file.
1861            */
1862           if (wb_remaining(a) > 0) {
1863                     ret = wb_write_out(a);
1864                     if (ret < 0)
1865                               return (ret);
1866           }
1867 
1868           /*
1869            * Preparations...
1870            */
1871 #ifdef DEBUG
1872           if (iso9660->birth_time == 0)
1873 #endif
1874                     time(&(iso9660->birth_time));
1875 
1876           /*
1877            * Prepare a bootable ISO image.
1878            */
1879           if (iso9660->opt.boot) {
1880                     /* Find out the boot file entry. */
1881                     ret = isoent_find_out_boot_file(a, iso9660->primary.rootent);
1882                     if (ret < 0)
1883                               return (ret);
1884                     /* Reconvert the boot file from zisofs'ed form to
1885                      * plain form. */
1886                     ret = zisofs_rewind_boot_file(a);
1887                     if (ret < 0)
1888                               return (ret);
1889                     /* Write remaining data out to the temporary file. */
1890                     if (wb_remaining(a) > 0) {
1891                               ret = wb_write_out(a);
1892                               if (ret < 0)
1893                                         return (ret);
1894                     }
1895                     /* Create the boot catalog. */
1896                     ret = isoent_create_boot_catalog(a, iso9660->primary.rootent);
1897                     if (ret < 0)
1898                               return (ret);
1899           }
1900 
1901           /*
1902            * Prepare joliet extensions.
1903            */
1904           if (iso9660->opt.joliet) {
1905                     /* Make a new tree for joliet. */
1906                     ret = isoent_clone_tree(a, &(iso9660->joliet.rootent),
1907                         iso9660->primary.rootent);
1908                     if (ret < 0)
1909                               return (ret);
1910                     /* Make sure we have UTF-16BE converters.
1911                      * if there is no file entry, converters are still
1912                      * uninitialized. */
1913                     if (iso9660->sconv_to_utf16be == NULL) {
1914                               iso9660->sconv_to_utf16be =
1915                                   archive_string_conversion_to_charset(
1916                                         &(a->archive), "UTF-16BE", 1);
1917                               if (iso9660->sconv_to_utf16be == NULL)
1918                                         /* Couldn't allocate memory */
1919                                         return (ARCHIVE_FATAL);
1920                               iso9660->sconv_from_utf16be =
1921                                   archive_string_conversion_from_charset(
1922                                         &(a->archive), "UTF-16BE", 1);
1923                               if (iso9660->sconv_from_utf16be == NULL)
1924                                         /* Couldn't allocate memory */
1925                                         return (ARCHIVE_FATAL);
1926                     }
1927           }
1928 
1929           /*
1930            * Make Path Tables.
1931            */
1932           ret = isoent_make_path_table(a);
1933           if (ret < 0)
1934                     return (ret);
1935 
1936           /*
1937            * Calculate a total volume size and setup all locations of
1938            * contents of an iso9660 image.
1939            */
1940           blocks = SYSTEM_AREA_BLOCK
1941                     + PRIMARY_VOLUME_DESCRIPTOR_BLOCK
1942                     + VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK
1943                     + NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
1944           if (iso9660->opt.boot)
1945                     blocks += BOOT_RECORD_DESCRIPTOR_BLOCK;
1946           if (iso9660->opt.joliet)
1947                     blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
1948           if (iso9660->opt.iso_level == 4)
1949                     blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
1950 
1951           /* Setup the locations of Path Table. */
1952           iso9660->primary.location_type_L_path_table = blocks;
1953           blocks += iso9660->primary.path_table_block;
1954           iso9660->primary.location_type_M_path_table = blocks;
1955           blocks += iso9660->primary.path_table_block;
1956           if (iso9660->opt.joliet) {
1957                     iso9660->joliet.location_type_L_path_table = blocks;
1958                     blocks += iso9660->joliet.path_table_block;
1959                     iso9660->joliet.location_type_M_path_table = blocks;
1960                     blocks += iso9660->joliet.path_table_block;
1961           }
1962 
1963           /* Setup the locations of directories. */
1964           isoent_setup_directory_location(iso9660, blocks,
1965               &(iso9660->primary));
1966           blocks += iso9660->primary.total_dir_block;
1967           if (iso9660->opt.joliet) {
1968                     isoent_setup_directory_location(iso9660, blocks,
1969                         &(iso9660->joliet));
1970                     blocks += iso9660->joliet.total_dir_block;
1971           }
1972 
1973           if (iso9660->opt.rr) {
1974                     iso9660->location_rrip_er = blocks;
1975                     blocks += RRIP_ER_BLOCK;
1976           }
1977 
1978           /* Setup the locations of all file contents. */
1979           isoent_setup_file_location(iso9660, blocks);
1980           blocks += iso9660->total_file_block;
1981           if (iso9660->opt.boot && iso9660->opt.boot_info_table) {
1982                     ret = setup_boot_information(a);
1983                     if (ret < 0)
1984                               return (ret);
1985           }
1986 
1987           /* Now we have a total volume size. */
1988           iso9660->volume_space_size = blocks;
1989           if (iso9660->opt.pad)
1990                     iso9660->volume_space_size += PADDING_BLOCK;
1991           iso9660->volume_sequence_number = 1;
1992 
1993 
1994           /*
1995            * Write an ISO 9660 image.
1996            */
1997 
1998           /* Switch to start using wbuff as file buffer. */
1999           iso9660->wbuff_remaining = wb_buffmax();
2000           iso9660->wbuff_type = WB_TO_STREAM;
2001           iso9660->wbuff_offset = 0;
2002           iso9660->wbuff_written = 0;
2003           iso9660->wbuff_tail = 0;
2004 
2005           /* Write The System Area */
2006           ret = write_null(a, SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE);
2007           if (ret != ARCHIVE_OK)
2008                     return (ARCHIVE_FATAL);
2009 
2010           /* Write Primary Volume Descriptor */
2011           ret = write_VD(a, &(iso9660->primary));
2012           if (ret != ARCHIVE_OK)
2013                     return (ARCHIVE_FATAL);
2014 
2015           if (iso9660->opt.boot) {
2016                     /* Write Boot Record Volume Descriptor */
2017                     ret = write_VD_boot_record(a);
2018                     if (ret != ARCHIVE_OK)
2019                               return (ARCHIVE_FATAL);
2020           }
2021 
2022           if (iso9660->opt.iso_level == 4) {
2023                     /* Write Enhanced Volume Descriptor */
2024                     iso9660->primary.vdd_type = VDD_ENHANCED;
2025                     ret = write_VD(a, &(iso9660->primary));
2026                     iso9660->primary.vdd_type = VDD_PRIMARY;
2027                     if (ret != ARCHIVE_OK)
2028                               return (ARCHIVE_FATAL);
2029           }
2030 
2031           if (iso9660->opt.joliet) {
2032                     ret = write_VD(a, &(iso9660->joliet));
2033                     if (ret != ARCHIVE_OK)
2034                               return (ARCHIVE_FATAL);
2035           }
2036 
2037           /* Write Volume Descriptor Set Terminator */
2038           ret = write_VD_terminator(a);
2039           if (ret != ARCHIVE_OK)
2040                     return (ARCHIVE_FATAL);
2041 
2042           /* Write Non-ISO File System Information */
2043           ret = write_information_block(a);
2044           if (ret != ARCHIVE_OK)
2045                     return (ARCHIVE_FATAL);
2046 
2047           /* Write Type L Path Table */
2048           ret = write_path_table(a, 0, &(iso9660->primary));
2049           if (ret != ARCHIVE_OK)
2050                     return (ARCHIVE_FATAL);
2051 
2052           /* Write Type M Path Table */
2053           ret = write_path_table(a, 1, &(iso9660->primary));
2054           if (ret != ARCHIVE_OK)
2055                     return (ARCHIVE_FATAL);
2056 
2057           if (iso9660->opt.joliet) {
2058                     /* Write Type L Path Table */
2059                     ret = write_path_table(a, 0, &(iso9660->joliet));
2060                     if (ret != ARCHIVE_OK)
2061                               return (ARCHIVE_FATAL);
2062 
2063                     /* Write Type M Path Table */
2064                     ret = write_path_table(a, 1, &(iso9660->joliet));
2065                     if (ret != ARCHIVE_OK)
2066                               return (ARCHIVE_FATAL);
2067           }
2068 
2069           /* Write Directory Descriptors */
2070           ret = write_directory_descriptors(a, &(iso9660->primary));
2071           if (ret != ARCHIVE_OK)
2072                     return (ARCHIVE_FATAL);
2073 
2074           if (iso9660->opt.joliet) {
2075                     ret = write_directory_descriptors(a, &(iso9660->joliet));
2076                     if (ret != ARCHIVE_OK)
2077                               return (ARCHIVE_FATAL);
2078           }
2079 
2080           if (iso9660->opt.rr) {
2081                     /* Write Rockridge ER(Extensions Reference) */
2082                     ret = write_rr_ER(a);
2083                     if (ret != ARCHIVE_OK)
2084                               return (ARCHIVE_FATAL);
2085           }
2086 
2087           /* Write File Descriptors */
2088           ret = write_file_descriptors(a);
2089           if (ret != ARCHIVE_OK)
2090                     return (ARCHIVE_FATAL);
2091 
2092           /* Write Padding  */
2093           if (iso9660->opt.pad) {
2094                     ret = write_null(a, PADDING_BLOCK * LOGICAL_BLOCK_SIZE);
2095                     if (ret != ARCHIVE_OK)
2096                               return (ARCHIVE_FATAL);
2097           }
2098 
2099           if (iso9660->directories_too_deep != NULL) {
2100                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2101                         "%s: Directories too deep.",
2102                         archive_entry_pathname(
2103                               iso9660->directories_too_deep->file->entry));
2104                     return (ARCHIVE_WARN);
2105           }
2106 
2107           /* Write remaining data out. */
2108           ret = wb_write_out(a);
2109 
2110           return (ret);
2111 }
2112 
2113 static int
iso9660_free(struct archive_write * a)2114 iso9660_free(struct archive_write *a)
2115 {
2116           struct iso9660 *iso9660;
2117           int i, ret;
2118 
2119           iso9660 = a->format_data;
2120 
2121           /* Close the temporary file. */
2122           if (iso9660->temp_fd >= 0)
2123                     close(iso9660->temp_fd);
2124 
2125           /* Free some stuff for zisofs operations. */
2126           ret = zisofs_free(a);
2127 
2128           /* Remove directory entries in tree which includes file entries. */
2129           isoent_free_all(iso9660->primary.rootent);
2130           for (i = 0; i < iso9660->primary.max_depth; i++)
2131                     free(iso9660->primary.pathtbl[i].sorted);
2132           free(iso9660->primary.pathtbl);
2133 
2134           if (iso9660->opt.joliet) {
2135                     isoent_free_all(iso9660->joliet.rootent);
2136                     for (i = 0; i < iso9660->joliet.max_depth; i++)
2137                               free(iso9660->joliet.pathtbl[i].sorted);
2138                     free(iso9660->joliet.pathtbl);
2139           }
2140 
2141           /* Remove isofile entries. */
2142           isofile_free_all_entries(iso9660);
2143           isofile_free_hardlinks(iso9660);
2144 
2145           archive_string_free(&(iso9660->cur_dirstr));
2146           archive_string_free(&(iso9660->volume_identifier));
2147           archive_string_free(&(iso9660->publisher_identifier));
2148           archive_string_free(&(iso9660->data_preparer_identifier));
2149           archive_string_free(&(iso9660->application_identifier));
2150           archive_string_free(&(iso9660->copyright_file_identifier));
2151           archive_string_free(&(iso9660->abstract_file_identifier));
2152           archive_string_free(&(iso9660->bibliographic_file_identifier));
2153           archive_string_free(&(iso9660->el_torito.catalog_filename));
2154           archive_string_free(&(iso9660->el_torito.boot_filename));
2155           archive_string_free(&(iso9660->el_torito.id));
2156           archive_string_free(&(iso9660->utf16be));
2157           archive_string_free(&(iso9660->mbs));
2158 
2159           free(iso9660);
2160           a->format_data = NULL;
2161 
2162           return (ret);
2163 }
2164 
2165 /*
2166  * Get the System Identifier
2167  */
2168 static void
get_system_identitier(char * system_id,size_t size)2169 get_system_identitier(char *system_id, size_t size)
2170 {
2171 #if defined(HAVE_SYS_UTSNAME_H)
2172           struct utsname u;
2173 
2174           uname(&u);
2175           strncpy(system_id, u.sysname, size-1);
2176           system_id[size-1] = '\0';
2177 #elif defined(_WIN32) && !defined(__CYGWIN__)
2178           strncpy(system_id, "Windows", size-1);
2179           system_id[size-1] = '\0';
2180 #else
2181           strncpy(system_id, "Unknown", size-1);
2182           system_id[size-1] = '\0';
2183 #endif
2184 }
2185 
2186 static void
set_str(unsigned char * p,const char * s,size_t l,char f,const char * map)2187 set_str(unsigned char *p, const char *s, size_t l, char f, const char *map)
2188 {
2189           unsigned char c;
2190 
2191           if (s == NULL)
2192                     s = "";
2193           while ((c = *s++) != 0 && l > 0) {
2194                     if (c >= 0x80 || map[c] == 0)
2195                      {
2196                               /* illegal character */
2197                               if (c >= 'a' && c <= 'z') {
2198                                         /* convert c from a-z to A-Z */
2199                                         c -= 0x20;
2200                               } else
2201                                         c = 0x5f;
2202                     }
2203                     *p++ = c;
2204                     l--;
2205           }
2206           /* If l isn't zero, fill p buffer by the character
2207            * which indicated by f. */
2208           if (l > 0)
2209                     memset(p , f, l);
2210 }
2211 
2212 static inline int
joliet_allowed_char(unsigned char high,unsigned char low)2213 joliet_allowed_char(unsigned char high, unsigned char low)
2214 {
2215           int utf16 = (high << 8) | low;
2216 
2217           if (utf16 <= 0x001F)
2218                     return (0);
2219 
2220           switch (utf16) {
2221           case 0x002A: /* '*' */
2222           case 0x002F: /* '/' */
2223           case 0x003A: /* ':' */
2224           case 0x003B: /* ';' */
2225           case 0x003F: /* '?' */
2226           case 0x005C: /* '\' */
2227                     return (0);/* Not allowed. */
2228           }
2229           return (1);
2230 }
2231 
2232 static int
set_str_utf16be(struct archive_write * a,unsigned char * p,const char * s,size_t l,uint16_t uf,enum vdc vdc)2233 set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,
2234     size_t l, uint16_t uf, enum vdc vdc)
2235 {
2236           size_t size, i;
2237           int onepad;
2238 
2239           if (s == NULL)
2240                     s = "";
2241           if (l & 0x01) {
2242                     onepad = 1;
2243                     l &= ~1;
2244           } else
2245                     onepad = 0;
2246           if (vdc == VDC_UCS2) {
2247                     struct iso9660 *iso9660 = a->format_data;
2248                     if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),
2249                         iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {
2250                               archive_set_error(&a->archive, ENOMEM,
2251                                   "Can't allocate memory for UTF-16BE");
2252                               return (ARCHIVE_FATAL);
2253                     }
2254                     size = iso9660->utf16be.length;
2255                     if (size > l)
2256                               size = l;
2257                     memcpy(p, iso9660->utf16be.s, size);
2258           } else {
2259                     const uint16_t *u16 = (const uint16_t *)s;
2260 
2261                     size = 0;
2262                     while (*u16++)
2263                               size += 2;
2264                     if (size > l)
2265                               size = l;
2266                     memcpy(p, s, size);
2267           }
2268           for (i = 0; i < size; i += 2, p += 2) {
2269                     if (!joliet_allowed_char(p[0], p[1]))
2270                               archive_be16enc(p, 0x005F);/* '_' */
2271           }
2272           l -= size;
2273           while (l > 0) {
2274                     archive_be16enc(p, uf);
2275                     p += 2;
2276                     l -= 2;
2277           }
2278           if (onepad)
2279                     *p = 0;
2280           return (ARCHIVE_OK);
2281 }
2282 
2283 static const char a_characters_map[0x80] = {
2284 /*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2285     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2286     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2287     1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
2288     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
2289     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2290     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2291     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
2292     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
2293 };
2294 
2295 static const char a1_characters_map[0x80] = {
2296 /*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2297     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2298     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2299     1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
2300     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
2301     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2302     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2303     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
2304     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
2305 };
2306 
2307 static const char d_characters_map[0x80] = {
2308 /*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2309     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2310     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2311     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
2312     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
2313     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2314     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2315     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
2316     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
2317 };
2318 
2319 static const char d1_characters_map[0x80] = {
2320 /*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
2321     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
2322     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
2323     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
2324     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
2325     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
2326     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
2327     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
2328     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
2329 };
2330 
2331 static int
set_str_a_characters_bp(struct archive_write * a,unsigned char * bp,int from,int to,const char * s,enum vdc vdc)2332 set_str_a_characters_bp(struct archive_write *a, unsigned char *bp,
2333     int from, int to, const char *s, enum vdc vdc)
2334 {
2335           int r;
2336 
2337           switch (vdc) {
2338           case VDC_STD:
2339                     set_str(bp+from, s, to - from + 1, 0x20,
2340                         a_characters_map);
2341                     r = ARCHIVE_OK;
2342                     break;
2343           case VDC_LOWERCASE:
2344                     set_str(bp+from, s, to - from + 1, 0x20,
2345                         a1_characters_map);
2346                     r = ARCHIVE_OK;
2347                     break;
2348           case VDC_UCS2:
2349           case VDC_UCS2_DIRECT:
2350                     r = set_str_utf16be(a, bp+from, s, to - from + 1,
2351                         0x0020, vdc);
2352                     break;
2353           default:
2354                     r = ARCHIVE_FATAL;
2355           }
2356           return (r);
2357 }
2358 
2359 static int
set_str_d_characters_bp(struct archive_write * a,unsigned char * bp,int from,int to,const char * s,enum vdc vdc)2360 set_str_d_characters_bp(struct archive_write *a, unsigned char *bp,
2361     int from, int to, const char *s, enum  vdc vdc)
2362 {
2363           int r;
2364 
2365           switch (vdc) {
2366           case VDC_STD:
2367                     set_str(bp+from, s, to - from + 1, 0x20,
2368                         d_characters_map);
2369                     r = ARCHIVE_OK;
2370                     break;
2371           case VDC_LOWERCASE:
2372                     set_str(bp+from, s, to - from + 1, 0x20,
2373                         d1_characters_map);
2374                     r = ARCHIVE_OK;
2375                     break;
2376           case VDC_UCS2:
2377           case VDC_UCS2_DIRECT:
2378                     r = set_str_utf16be(a, bp+from, s, to - from + 1,
2379                         0x0020, vdc);
2380                     break;
2381           default:
2382                     r = ARCHIVE_FATAL;
2383           }
2384           return (r);
2385 }
2386 
2387 static void
set_VD_bp(unsigned char * bp,enum VD_type type,unsigned char ver)2388 set_VD_bp(unsigned char *bp, enum VD_type type, unsigned char ver)
2389 {
2390 
2391           /* Volume Descriptor Type */
2392           bp[1] = (unsigned char)type;
2393           /* Standard Identifier */
2394           memcpy(bp + 2, "CD001", 5);
2395           /* Volume Descriptor Version */
2396           bp[7] = ver;
2397 }
2398 
2399 static inline void
set_unused_field_bp(unsigned char * bp,int from,int to)2400 set_unused_field_bp(unsigned char *bp, int from, int to)
2401 {
2402           memset(bp + from, 0, to - from + 1);
2403 }
2404 
2405 /*
2406  * 8-bit unsigned numerical values.
2407  * ISO9660 Standard 7.1.1
2408  */
2409 static inline void
set_num_711(unsigned char * p,unsigned char value)2410 set_num_711(unsigned char *p, unsigned char value)
2411 {
2412           *p = value;
2413 }
2414 
2415 /*
2416  * 8-bit signed numerical values.
2417  * ISO9660 Standard 7.1.2
2418  */
2419 static inline void
set_num_712(unsigned char * p,char value)2420 set_num_712(unsigned char *p, char value)
2421 {
2422           *((char *)p) = value;
2423 }
2424 
2425 /*
2426  * Least significant byte first.
2427  * ISO9660 Standard 7.2.1
2428  */
2429 static inline void
set_num_721(unsigned char * p,uint16_t value)2430 set_num_721(unsigned char *p, uint16_t value)
2431 {
2432           archive_le16enc(p, value);
2433 }
2434 
2435 /*
2436  * Most significant byte first.
2437  * ISO9660 Standard 7.2.2
2438  */
2439 static inline void
set_num_722(unsigned char * p,uint16_t value)2440 set_num_722(unsigned char *p, uint16_t value)
2441 {
2442           archive_be16enc(p, value);
2443 }
2444 
2445 /*
2446  * Both-byte orders.
2447  * ISO9660 Standard 7.2.3
2448  */
2449 static void
set_num_723(unsigned char * p,uint16_t value)2450 set_num_723(unsigned char *p, uint16_t value)
2451 {
2452           archive_le16enc(p, value);
2453           archive_be16enc(p+2, value);
2454 }
2455 
2456 /*
2457  * Least significant byte first.
2458  * ISO9660 Standard 7.3.1
2459  */
2460 static inline void
set_num_731(unsigned char * p,uint32_t value)2461 set_num_731(unsigned char *p, uint32_t value)
2462 {
2463           archive_le32enc(p, value);
2464 }
2465 
2466 /*
2467  * Most significant byte first.
2468  * ISO9660 Standard 7.3.2
2469  */
2470 static inline void
set_num_732(unsigned char * p,uint32_t value)2471 set_num_732(unsigned char *p, uint32_t value)
2472 {
2473           archive_be32enc(p, value);
2474 }
2475 
2476 /*
2477  * Both-byte orders.
2478  * ISO9660 Standard 7.3.3
2479  */
2480 static inline void
set_num_733(unsigned char * p,uint32_t value)2481 set_num_733(unsigned char *p, uint32_t value)
2482 {
2483           archive_le32enc(p, value);
2484           archive_be32enc(p+4, value);
2485 }
2486 
2487 static void
set_digit(unsigned char * p,size_t s,int value)2488 set_digit(unsigned char *p, size_t s, int value)
2489 {
2490 
2491           while (s--) {
2492                     p[s] = '0' + (value % 10);
2493                     value /= 10;
2494           }
2495 }
2496 
2497 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
2498 #define get_gmoffset(tm)      ((tm)->tm_gmtoff)
2499 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
2500 #define get_gmoffset(tm)      ((tm)->__tm_gmtoff)
2501 #else
2502 static long
get_gmoffset(struct tm * tm)2503 get_gmoffset(struct tm *tm)
2504 {
2505           long offset;
2506 
2507 #if defined(HAVE__GET_TIMEZONE)
2508           _get_timezone(&offset);
2509 #elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
2510           offset = _timezone;
2511 #else
2512           offset = timezone;
2513 #endif
2514           offset *= -1;
2515           if (tm->tm_isdst)
2516                     offset += 3600;
2517           return (offset);
2518 }
2519 #endif
2520 
2521 static void
get_tmfromtime(struct tm * tm,time_t * t)2522 get_tmfromtime(struct tm *tm, time_t *t)
2523 {
2524 #if HAVE_LOCALTIME_R
2525           tzset();
2526           localtime_r(t, tm);
2527 #elif HAVE__LOCALTIME64_S
2528           __time64_t tmp_t = (__time64_t) *t; //time_t may be shorter than 64 bits
2529           _localtime64_s(tm, &tmp_t);
2530 #else
2531           memcpy(tm, localtime(t), sizeof(*tm));
2532 #endif
2533 }
2534 
2535 /*
2536  * Date and Time Format.
2537  * ISO9660 Standard 8.4.26.1
2538  */
2539 static void
set_date_time(unsigned char * p,time_t t)2540 set_date_time(unsigned char *p, time_t t)
2541 {
2542           struct tm tm;
2543 
2544           get_tmfromtime(&tm, &t);
2545           set_digit(p, 4, tm.tm_year + 1900);
2546           set_digit(p+4, 2, tm.tm_mon + 1);
2547           set_digit(p+6, 2, tm.tm_mday);
2548           set_digit(p+8, 2, tm.tm_hour);
2549           set_digit(p+10, 2, tm.tm_min);
2550           set_digit(p+12, 2, tm.tm_sec);
2551           set_digit(p+14, 2, 0);
2552           set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
2553 }
2554 
2555 static void
set_date_time_null(unsigned char * p)2556 set_date_time_null(unsigned char *p)
2557 {
2558           memset(p, (int)'0', 16);
2559           p[16] = 0;
2560 }
2561 
2562 static void
set_time_915(unsigned char * p,time_t t)2563 set_time_915(unsigned char *p, time_t t)
2564 {
2565           struct tm tm;
2566 
2567           get_tmfromtime(&tm, &t);
2568           set_num_711(p+0, tm.tm_year);
2569           set_num_711(p+1, tm.tm_mon+1);
2570           set_num_711(p+2, tm.tm_mday);
2571           set_num_711(p+3, tm.tm_hour);
2572           set_num_711(p+4, tm.tm_min);
2573           set_num_711(p+5, tm.tm_sec);
2574           set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
2575 }
2576 
2577 
2578 /*
2579  * Write SUSP "CE" System Use Entry.
2580  */
2581 static int
set_SUSP_CE(unsigned char * p,int location,int offset,int size)2582 set_SUSP_CE(unsigned char *p, int location, int offset, int size)
2583 {
2584           unsigned char *bp = p -1;
2585           /*  Extend the System Use Area
2586            *   "CE" Format:
2587            *               len  ver
2588            *    +----+----+----+----+-----------+-----------+
2589            *    | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |
2590            *    +----+----+----+----+-----------+-----------+
2591            *    0    1    2    3    4          12          20
2592            *    +-----------+
2593            *    | LOCATION3 |
2594            *    +-----------+
2595            *   20          28
2596            *   LOCATION1 : Location of Continuation of System Use Area.
2597            *   LOCATION2 : Offset to Start of Continuation.
2598            *   LOCATION3 : Length of the Continuation.
2599            */
2600 
2601           bp[1] = 'C';
2602           bp[2] = 'E';
2603           bp[3] = RR_CE_SIZE; /* length */
2604           bp[4] = 1;                    /* version          */
2605           set_num_733(bp+5, location);
2606           set_num_733(bp+13, offset);
2607           set_num_733(bp+21, size);
2608           return (RR_CE_SIZE);
2609 }
2610 
2611 /*
2612  * The functions, which names are beginning with extra_, are used to
2613  * control extra records.
2614  * The maximum size of a Directory Record is 254. When a filename is
2615  * very long, all of RRIP data of a file won't stored to the Directory
2616  * Record and so remaining RRIP data store to an extra record instead.
2617  */
2618 static unsigned char *
extra_open_record(unsigned char * bp,int dr_len,struct isoent * isoent,struct ctl_extr_rec * ctl)2619 extra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,
2620     struct ctl_extr_rec *ctl)
2621 {
2622           ctl->bp = bp;
2623           if (bp != NULL)
2624                     bp += dr_len;
2625           ctl->use_extr = 0;
2626           ctl->isoent = isoent;
2627           ctl->ce_ptr = NULL;
2628           ctl->cur_len = ctl->dr_len = dr_len;
2629           ctl->limit = DR_LIMIT;
2630 
2631           return (bp);
2632 }
2633 
2634 static void
extra_close_record(struct ctl_extr_rec * ctl,int ce_size)2635 extra_close_record(struct ctl_extr_rec *ctl, int ce_size)
2636 {
2637           int padding = 0;
2638 
2639           if (ce_size > 0)
2640                     extra_tell_used_size(ctl, ce_size);
2641           /* Padding. */
2642           if (ctl->cur_len & 0x01) {
2643                     ctl->cur_len++;
2644                     if (ctl->bp != NULL)
2645                               ctl->bp[ctl->cur_len] = 0;
2646                     padding = 1;
2647           }
2648           if (ctl->use_extr) {
2649                     if (ctl->ce_ptr != NULL)
2650                               set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,
2651                                   ctl->extr_off, ctl->cur_len - padding);
2652           } else
2653                     ctl->dr_len = ctl->cur_len;
2654 }
2655 
2656 #define extra_space(ctl)      ((ctl)->limit - (ctl)->cur_len)
2657 
2658 static unsigned char *
extra_next_record(struct ctl_extr_rec * ctl,int length)2659 extra_next_record(struct ctl_extr_rec *ctl, int length)
2660 {
2661           int cur_len = ctl->cur_len;/* save cur_len */
2662 
2663           /* Close the current extra record or Directory Record. */
2664           extra_close_record(ctl, RR_CE_SIZE);
2665 
2666           /* Get a next extra record. */
2667           ctl->use_extr = 1;
2668           if (ctl->bp != NULL) {
2669                     /* Storing data into an extra record. */
2670                     unsigned char *p;
2671 
2672                     /* Save the pointer where a CE extension will be
2673                      * stored to. */
2674                     ctl->ce_ptr = &ctl->bp[cur_len+1];
2675                     p = extra_get_record(ctl->isoent,
2676                         &ctl->limit, &ctl->extr_off, &ctl->extr_loc);
2677                     ctl->bp = p - 1;/* the base of bp offset is 1. */
2678           } else
2679                     /* Calculating the size of an extra record. */
2680                     (void)extra_get_record(ctl->isoent,
2681                         &ctl->limit, NULL, NULL);
2682           ctl->cur_len = 0;
2683           /* Check if an extra record is almost full.
2684            * If so, get a next one. */
2685           if (extra_space(ctl) < length)
2686                     (void)extra_next_record(ctl, length);
2687 
2688           return (ctl->bp);
2689 }
2690 
2691 static inline struct extr_rec *
extra_last_record(struct isoent * isoent)2692 extra_last_record(struct isoent *isoent)
2693 {
2694           if (isoent->extr_rec_list.first == NULL)
2695                     return (NULL);
2696           return ((struct extr_rec *)(void *)
2697                     ((char *)(isoent->extr_rec_list.last)
2698                         - offsetof(struct extr_rec, next)));
2699 }
2700 
2701 static unsigned char *
extra_get_record(struct isoent * isoent,int * space,int * off,int * loc)2702 extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
2703 {
2704           struct extr_rec *rec;
2705 
2706           isoent = isoent->parent;
2707           if (off != NULL) {
2708                     /* Storing data into an extra record. */
2709                     rec = isoent->extr_rec_list.current;
2710                     if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)
2711                               rec = rec->next;
2712           } else {
2713                     /* Calculating the size of an extra record. */
2714                     rec = extra_last_record(isoent);
2715                     if (rec == NULL ||
2716                         DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {
2717                               rec = malloc(sizeof(*rec));
2718                               if (rec == NULL)
2719                                         return (NULL);
2720                               rec->location = 0;
2721                               rec->offset = 0;
2722                               /* Insert `rec` into the tail of isoent->extr_rec_list */
2723                               rec->next = NULL;
2724                               /*
2725                                * Note: testing isoent->extr_rec_list.last == NULL
2726                                * here is really unneeded since it has been already
2727                                * initialized at isoent_new function but Clang Static
2728                                * Analyzer claims that it is dereference of null
2729                                * pointer.
2730                                */
2731                               if (isoent->extr_rec_list.last == NULL)
2732                                         isoent->extr_rec_list.last =
2733                                                   &(isoent->extr_rec_list.first);
2734                               *isoent->extr_rec_list.last = rec;
2735                               isoent->extr_rec_list.last = &(rec->next);
2736                     }
2737           }
2738           *space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;
2739           if (*space & 0x01)
2740                     *space -= 1;/* Keep padding space. */
2741           if (off != NULL)
2742                     *off = rec->offset;
2743           if (loc != NULL)
2744                     *loc = rec->location;
2745           isoent->extr_rec_list.current = rec;
2746 
2747           return (&rec->buf[rec->offset]);
2748 }
2749 
2750 static void
extra_tell_used_size(struct ctl_extr_rec * ctl,int size)2751 extra_tell_used_size(struct ctl_extr_rec *ctl, int size)
2752 {
2753           struct isoent *isoent;
2754           struct extr_rec *rec;
2755 
2756           if (ctl->use_extr) {
2757                     isoent = ctl->isoent->parent;
2758                     rec = isoent->extr_rec_list.current;
2759                     if (rec != NULL)
2760                               rec->offset += size;
2761           }
2762           ctl->cur_len += size;
2763 }
2764 
2765 static int
extra_setup_location(struct isoent * isoent,int location)2766 extra_setup_location(struct isoent *isoent, int location)
2767 {
2768           struct extr_rec *rec;
2769           int cnt;
2770 
2771           cnt = 0;
2772           rec = isoent->extr_rec_list.first;
2773           isoent->extr_rec_list.current = rec;
2774           while (rec) {
2775                     cnt++;
2776                     rec->location = location++;
2777                     rec->offset = 0;
2778                     rec = rec->next;
2779           }
2780           return (cnt);
2781 }
2782 
2783 /*
2784  * Create the RRIP entries.
2785  */
2786 static int
set_directory_record_rr(unsigned char * bp,int dr_len,struct isoent * isoent,struct iso9660 * iso9660,enum dir_rec_type t)2787 set_directory_record_rr(unsigned char *bp, int dr_len,
2788     struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)
2789 {
2790           /* Flags(BP 5) of the Rockridge "RR" System Use Field */
2791           unsigned char rr_flag;
2792 #define RR_USE_PX   0x01
2793 #define RR_USE_PN   0x02
2794 #define RR_USE_SL   0x04
2795 #define RR_USE_NM   0x08
2796 #define RR_USE_CL   0x10
2797 #define RR_USE_PL   0x20
2798 #define RR_USE_RE   0x40
2799 #define RR_USE_TF   0x80
2800           int length;
2801           struct ctl_extr_rec ctl;
2802           struct isoent *rr_parent, *pxent;
2803           struct isofile *file;
2804 
2805           bp = extra_open_record(bp, dr_len, isoent, &ctl);
2806 
2807           if (t == DIR_REC_PARENT) {
2808                     rr_parent = isoent->rr_parent;
2809                     pxent = isoent->parent;
2810                     if (rr_parent != NULL)
2811                               isoent = rr_parent;
2812                     else
2813                               isoent = isoent->parent;
2814           } else {
2815                     rr_parent = NULL;
2816                     pxent = isoent;
2817           }
2818           file = isoent->file;
2819 
2820           if (t != DIR_REC_NORMAL) {
2821                     rr_flag = RR_USE_PX | RR_USE_TF;
2822                     if (rr_parent != NULL)
2823                               rr_flag |= RR_USE_PL;
2824           } else {
2825                     rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;
2826                     if (archive_entry_filetype(file->entry) == AE_IFLNK)
2827                               rr_flag |= RR_USE_SL;
2828                     if (isoent->rr_parent != NULL)
2829                               rr_flag |= RR_USE_RE;
2830                     if (isoent->rr_child != NULL)
2831                               rr_flag |= RR_USE_CL;
2832                     if (archive_entry_filetype(file->entry) == AE_IFCHR ||
2833                         archive_entry_filetype(file->entry) == AE_IFBLK)
2834                               rr_flag |= RR_USE_PN;
2835 #ifdef COMPAT_MKISOFS
2836                     /*
2837                      * mkisofs 2.01.01a63 records "RE" extension to
2838                      * the entry of "rr_moved" directory.
2839                      * I don't understand this behavior.
2840                      */
2841                     if (isoent->virtual &&
2842                         isoent->parent == iso9660->primary.rootent &&
2843                         strcmp(isoent->file->basename.s, "rr_moved") == 0)
2844                               rr_flag |= RR_USE_RE;
2845 #endif
2846           }
2847 
2848           /* Write "SP" System Use Entry. */
2849           if (t == DIR_REC_SELF && isoent == isoent->parent) {
2850                     length = 7;
2851                     if (bp != NULL) {
2852                               bp[1] = 'S';
2853                               bp[2] = 'P';
2854                               bp[3] = length;
2855                               bp[4] = 1;          /* version          */
2856                               bp[5] = 0xBE;  /* Check Byte  */
2857                               bp[6] = 0xEF;  /* Check Byte  */
2858                               bp[7] = 0;
2859                               bp += length;
2860                     }
2861                     extra_tell_used_size(&ctl, length);
2862           }
2863 
2864           /* Write "RR" System Use Entry. */
2865           length = 5;
2866           if (extra_space(&ctl) < length)
2867                     bp = extra_next_record(&ctl, length);
2868           if (bp != NULL) {
2869                     bp[1] = 'R';
2870                     bp[2] = 'R';
2871                     bp[3] = length;
2872                     bp[4] = 1;          /* version */
2873                     bp[5] = rr_flag;
2874                     bp += length;
2875           }
2876           extra_tell_used_size(&ctl, length);
2877 
2878           /* Write "NM" System Use Entry. */
2879           if (rr_flag & RR_USE_NM) {
2880                     /*
2881                      *   "NM" Format:
2882                      *     e.g. a basename is 'foo'
2883                      *               len  ver  flg
2884                      *    +----+----+----+----+----+----+----+----+
2885                      *    | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|
2886                      *    +----+----+----+----+----+----+----+----+
2887                      *    <----------------- len ----------------->
2888                      */
2889                     size_t nmlen = file->basename.length;
2890                     const char *nm = file->basename.s;
2891                     size_t nmmax;
2892 
2893                     if (extra_space(&ctl) < 6)
2894                               bp = extra_next_record(&ctl, 6);
2895                     if (bp != NULL) {
2896                               bp[1] = 'N';
2897                               bp[2] = 'M';
2898                               bp[4] = 1;              /* version      */
2899                     }
2900                     nmmax = extra_space(&ctl);
2901                     if (nmmax > 0xff)
2902                               nmmax = 0xff;
2903                     while (nmlen + 5 > nmmax) {
2904                               length = (int)nmmax;
2905                               if (bp != NULL) {
2906                                         bp[3] = length;
2907                                         bp[5] = 0x01;/* Alternate Name continues
2908                                                          * in next "NM" field */
2909                                         memcpy(bp+6, nm, length - 5);
2910                                         bp += length;
2911                               }
2912                               nmlen -= length - 5;
2913                               nm += length - 5;
2914                               extra_tell_used_size(&ctl, length);
2915                               if (extra_space(&ctl) < 6) {
2916                                         bp = extra_next_record(&ctl, 6);
2917                                         nmmax = extra_space(&ctl);
2918                                         if (nmmax > 0xff)
2919                                                   nmmax = 0xff;
2920                               }
2921                               if (bp != NULL) {
2922                                         bp[1] = 'N';
2923                                         bp[2] = 'M';
2924                                         bp[4] = 1;    /* version */
2925                               }
2926                     }
2927                     length = 5 + (int)nmlen;
2928                     if (bp != NULL) {
2929                               bp[3] = length;
2930                               bp[5] = 0;
2931                               memcpy(bp+6, nm, nmlen);
2932                               bp += length;
2933                     }
2934                     extra_tell_used_size(&ctl, length);
2935           }
2936 
2937           /* Write "PX" System Use Entry. */
2938           if (rr_flag & RR_USE_PX) {
2939                     /*
2940                      *   "PX" Format:
2941                      *               len  ver
2942                      *    +----+----+----+----+-----------+-----------+
2943                      *    | 'P'| 'X'| 2C | 01 | FILE MODE |   LINKS   |
2944                      *    +----+----+----+----+-----------+-----------+
2945                      *    0    1    2    3    4          12          20
2946                      *    +-----------+-----------+------------------+
2947                      *    |  USER ID  | GROUP ID  |FILE SERIAL NUMBER|
2948                      *    +-----------+-----------+------------------+
2949                      *   20          28          36                 44
2950                      */
2951                     length = 44;
2952                     if (extra_space(&ctl) < length)
2953                               bp = extra_next_record(&ctl, length);
2954                     if (bp != NULL) {
2955                               mode_t mode;
2956                               int64_t uid;
2957                               int64_t gid;
2958 
2959                               mode = archive_entry_mode(file->entry);
2960                               uid = archive_entry_uid(file->entry);
2961                               gid = archive_entry_gid(file->entry);
2962                               if (iso9660->opt.rr == OPT_RR_USEFUL) {
2963                                         /*
2964                                          * This action is similar to mkisofs -r option
2965                                          * but our rockridge=useful option does not
2966                                          * set a zero to uid and gid.
2967                                          */
2968                                         /* set all read bit ON */
2969                                         mode |= 0444;
2970 #if !defined(_WIN32) && !defined(__CYGWIN__)
2971                                         if (mode & 0111)
2972 #endif
2973                                                   /* set all exec bit ON */
2974                                                   mode |= 0111;
2975                                         /* clear all write bits. */
2976                                         mode &= ~0222;
2977                                         /* clear setuid,setgid,sticky bits. */
2978                                         mode &= ~07000;
2979                               }
2980 
2981                               bp[1] = 'P';
2982                               bp[2] = 'X';
2983                               bp[3] = length;
2984                               bp[4] = 1;          /* version          */
2985                               /* file mode */
2986                               set_num_733(bp+5, mode);
2987                               /* file links (stat.st_nlink) */
2988                               set_num_733(bp+13,
2989                                   archive_entry_nlink(file->entry));
2990                               set_num_733(bp+21, (uint32_t)uid);
2991                               set_num_733(bp+29, (uint32_t)gid);
2992                               /* File Serial Number */
2993                               if (pxent->dir)
2994                                         set_num_733(bp+37, pxent->dir_location);
2995                               else if (file->hardlink_target != NULL)
2996                                         set_num_733(bp+37,
2997                                             file->hardlink_target->cur_content->location);
2998                               else
2999                                         set_num_733(bp+37,
3000                                             file->cur_content->location);
3001                               bp += length;
3002                     }
3003                     extra_tell_used_size(&ctl, length);
3004           }
3005 
3006           /* Write "SL" System Use Entry. */
3007           if (rr_flag & RR_USE_SL) {
3008                     /*
3009                      *   "SL" Format:
3010                      *     e.g. a symbolic name is 'foo/bar'
3011                      *               len  ver  flg
3012                      *    +----+----+----+----+----+------------+
3013                      *    | 'S'| 'L'| 0F | 01 | 00 | components |
3014                      *    +----+----+----+----+----+-----+------+
3015                      *    0    1    2    3    4    5  ...|...  15
3016                      *    <----------------- len --------+------>
3017                      *    components :                   |
3018                      *     cflg clen                     |
3019                      *    +----+----+----+----+----+     |
3020                      *    | 00 | 03 | 'f'| 'o'| 'o'| <---+
3021                      *    +----+----+----+----+----+     |
3022                      *    5    6    7    8    9   10     |
3023                      *     cflg clen                     |
3024                      *    +----+----+----+----+----+     |
3025                      *    | 00 | 03 | 'b'| 'a'| 'r'| <---+
3026                      *    +----+----+----+----+----+
3027                      *   10   11   12   13   14   15
3028                      *
3029                      *    - cflg : flag of component
3030                      *    - clen : length of component
3031                      */
3032                     const char *sl;
3033                     char sl_last;
3034 
3035                     if (extra_space(&ctl) < 7)
3036                               bp = extra_next_record(&ctl, 7);
3037                     sl = file->symlink.s;
3038                     sl_last = '\0';
3039                     if (bp != NULL) {
3040                               bp[1] = 'S';
3041                               bp[2] = 'L';
3042                               bp[4] = 1;          /* version          */
3043                     }
3044                     for (;;) {
3045                               unsigned char *nc, *cf,  *cl, cldmy = 0;
3046                               int sllen, slmax;
3047 
3048                               slmax = extra_space(&ctl);
3049                               if (slmax > 0xff)
3050                                         slmax = 0xff;
3051                               if (bp != NULL)
3052                                         nc = &bp[6];
3053                               else
3054                                         nc = NULL;
3055                               cf = cl = NULL;
3056                               sllen = 0;
3057                               while (*sl && sllen + 11 < slmax) {
3058                                         if (sl_last == '\0' && sl[0] == '/') {
3059                                                   /*
3060                                                    *     flg  len
3061                                                    *    +----+----+
3062                                                    *    | 08 | 00 | ROOT component.
3063                                                    *    +----+----+ ("/")
3064                                                    *
3065                                                    * Root component has to appear
3066                                                    * at the first component only.
3067                                                    */
3068                                                   if (nc != NULL) {
3069                                                             cf = nc++;
3070                                                             *cf = 0x08; /* ROOT */
3071                                                             *nc++ = 0;
3072                                                   }
3073                                                   sllen += 2;
3074                                                   sl++;
3075                                                   sl_last = '/';
3076                                                   cl = NULL;
3077                                                   continue;
3078                                         }
3079                                         if (((sl_last == '\0' || sl_last == '/') &&
3080                                               sl[0] == '.' && sl[1] == '.' &&
3081                                              (sl[2] == '/' || sl[2] == '\0')) ||
3082                                             (sl[0] == '/' &&
3083                                               sl[1] == '.' && sl[2] == '.' &&
3084                                              (sl[3] == '/' || sl[3] == '\0'))) {
3085                                                   /*
3086                                                    *     flg  len
3087                                                    *    +----+----+
3088                                                    *    | 04 | 00 | PARENT component.
3089                                                    *    +----+----+ ("..")
3090                                                    */
3091                                                   if (nc != NULL) {
3092                                                             cf = nc++;
3093                                                             *cf = 0x04; /* PARENT */
3094                                                             *nc++ = 0;
3095                                                   }
3096                                                   sllen += 2;
3097                                                   if (sl[0] == '/')
3098                                                             sl += 3;/* skip "/.." */
3099                                                   else
3100                                                             sl += 2;/* skip ".." */
3101                                                   sl_last = '.';
3102                                                   cl = NULL;
3103                                                   continue;
3104                                         }
3105                                         if (((sl_last == '\0' || sl_last == '/') &&
3106                                               sl[0] == '.' &&
3107                                              (sl[1] == '/' || sl[1] == '\0')) ||
3108                                             (sl[0] == '/' && sl[1] == '.' &&
3109                                              (sl[2] == '/' || sl[2] == '\0'))) {
3110                                                   /*
3111                                                    *     flg  len
3112                                                    *    +----+----+
3113                                                    *    | 02 | 00 | CURRENT component.
3114                                                    *    +----+----+ (".")
3115                                                    */
3116                                                   if (nc != NULL) {
3117                                                             cf = nc++;
3118                                                             *cf = 0x02; /* CURRENT */
3119                                                             *nc++ = 0;
3120                                                   }
3121                                                   sllen += 2;
3122                                                   if (sl[0] == '/')
3123                                                             sl += 2;/* skip "/." */
3124                                                   else
3125                                                             sl ++;  /* skip "." */
3126                                                   sl_last = '.';
3127                                                   cl = NULL;
3128                                                   continue;
3129                                         }
3130                                         if (sl[0] == '/' || cl == NULL) {
3131                                                   if (nc != NULL) {
3132                                                             cf = nc++;
3133                                                             *cf = 0;
3134                                                             cl = nc++;
3135                                                             *cl = 0;
3136                                                   } else
3137                                                             cl = &cldmy;
3138                                                   sllen += 2;
3139                                                   if (sl[0] == '/') {
3140                                                             sl_last = *sl++;
3141                                                             continue;
3142                                                   }
3143                                         }
3144                                         sl_last = *sl++;
3145                                         if (nc != NULL) {
3146                                                   *nc++ = sl_last;
3147                                                   (*cl) ++;
3148                                         }
3149                                         sllen++;
3150                               }
3151                               if (*sl) {
3152                                         length = 5 + sllen;
3153                                         if (bp != NULL) {
3154                                                   /*
3155                                                    * Mark flg as CONTINUE component.
3156                                                    */
3157                                                   *cf |= 0x01;
3158                                                   /*
3159                                                    *               len  ver  flg
3160                                                    *    +----+----+----+----+----+-
3161                                                    *    | 'S'| 'L'| XX | 01 | 01 |
3162                                                    *    +----+----+----+----+----+-
3163                                                    *                           ^
3164                                                    *           continues in next "SL"
3165                                                    */
3166                                                   bp[3] = length;
3167                                                   bp[5] = 0x01;/* This Symbolic Link
3168                                                                   * continues in next
3169                                                                   * "SL" field */
3170                                                   bp += length;
3171                                         }
3172                                         extra_tell_used_size(&ctl, length);
3173                                         if (extra_space(&ctl) < 11)
3174                                                   bp = extra_next_record(&ctl, 11);
3175                                         if (bp != NULL) {
3176                                                   /* Next 'SL' */
3177                                                   bp[1] = 'S';
3178                                                   bp[2] = 'L';
3179                                                   bp[4] = 1;    /* version */
3180                                         }
3181                               } else {
3182                                         length = 5 + sllen;
3183                                         if (bp != NULL) {
3184                                                   bp[3] = length;
3185                                                   bp[5] = 0;
3186                                                   bp += length;
3187                                         }
3188                                         extra_tell_used_size(&ctl, length);
3189                                         break;
3190                               }
3191                     }
3192           }
3193 
3194           /* Write "TF" System Use Entry. */
3195           if (rr_flag & RR_USE_TF) {
3196                     /*
3197                      *   "TF" Format:
3198                      *               len  ver
3199                      *    +----+----+----+----+-----+-------------+
3200                      *    | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |
3201                      *    +----+----+----+----+-----+-------------+
3202                      *    0    1    2    3    4     5            XX
3203                      *    TIME STAMPS : ISO 9660 Standard 9.1.5.
3204                      *                  If TF_LONG_FORM FLAGS is set,
3205                      *                  use ISO9660 Standard 8.4.26.1.
3206                      */
3207 #define TF_CREATION 0x01      /* Creation time recorded               */
3208 #define TF_MODIFY   0x02      /* Modification time recorded           */
3209 #define TF_ACCESS   0x04      /* Last Access time recorded            */
3210 #define TF_ATTRIBUTES         0x08      /* Last Attribute Change time recorded  */
3211 #define TF_BACKUP   0x10      /* Last Backup time recorded            */
3212 #define TF_EXPIRATION         0x20      /* Expiration time recorded             */
3213 #define TF_EFFECTIVE          0x40      /* Effective time recorded              */
3214 #define TF_LONG_FORM          0x80      /* ISO 9660 17-byte time format used    */
3215                     unsigned char tf_flags;
3216 
3217                     length = 5;
3218                     tf_flags = 0;
3219 #ifndef COMPAT_MKISOFS
3220                     if (archive_entry_birthtime_is_set(file->entry) &&
3221                         archive_entry_birthtime(file->entry) <=
3222                         archive_entry_mtime(file->entry)) {
3223                               length += 7;
3224                               tf_flags |= TF_CREATION;
3225                     }
3226 #endif
3227                     if (archive_entry_mtime_is_set(file->entry)) {
3228                               length += 7;
3229                               tf_flags |= TF_MODIFY;
3230                     }
3231                     if (archive_entry_atime_is_set(file->entry)) {
3232                               length += 7;
3233                               tf_flags |= TF_ACCESS;
3234                     }
3235                     if (archive_entry_ctime_is_set(file->entry)) {
3236                               length += 7;
3237                               tf_flags |= TF_ATTRIBUTES;
3238                     }
3239                     if (extra_space(&ctl) < length)
3240                               bp = extra_next_record(&ctl, length);
3241                     if (bp != NULL) {
3242                               bp[1] = 'T';
3243                               bp[2] = 'F';
3244                               bp[3] = length;
3245                               bp[4] = 1;          /* version          */
3246                               bp[5] = tf_flags;
3247                               bp += 5;
3248                               /* Creation time */
3249                               if (tf_flags & TF_CREATION) {
3250                                         set_time_915(bp+1,
3251                                             archive_entry_birthtime(file->entry));
3252                                         bp += 7;
3253                               }
3254                               /* Modification time */
3255                               if (tf_flags & TF_MODIFY) {
3256                                         set_time_915(bp+1,
3257                                             archive_entry_mtime(file->entry));
3258                                         bp += 7;
3259                               }
3260                               /* Last Access time */
3261                               if (tf_flags & TF_ACCESS) {
3262                                         set_time_915(bp+1,
3263                                             archive_entry_atime(file->entry));
3264                                         bp += 7;
3265                               }
3266                               /* Last Attribute Change time */
3267                               if (tf_flags & TF_ATTRIBUTES) {
3268                                         set_time_915(bp+1,
3269                                             archive_entry_ctime(file->entry));
3270                                         bp += 7;
3271                               }
3272                     }
3273                     extra_tell_used_size(&ctl, length);
3274           }
3275 
3276           /* Write "RE" System Use Entry. */
3277           if (rr_flag & RR_USE_RE) {
3278                     /*
3279                      *   "RE" Format:
3280                      *               len  ver
3281                      *    +----+----+----+----+
3282                      *    | 'R'| 'E'| 04 | 01 |
3283                      *    +----+----+----+----+
3284                      *    0    1    2    3    4
3285                      */
3286                     length = 4;
3287                     if (extra_space(&ctl) < length)
3288                               bp = extra_next_record(&ctl, length);
3289                     if (bp != NULL) {
3290                               bp[1] = 'R';
3291                               bp[2] = 'E';
3292                               bp[3] = length;
3293                               bp[4] = 1;          /* version          */
3294                               bp += length;
3295                     }
3296                     extra_tell_used_size(&ctl, length);
3297           }
3298 
3299           /* Write "PL" System Use Entry. */
3300           if (rr_flag & RR_USE_PL) {
3301                     /*
3302                      *   "PL" Format:
3303                      *               len  ver
3304                      *    +----+----+----+----+------------+
3305                      *    | 'P'| 'L'| 0C | 01 | *LOCATION  |
3306                      *    +----+----+----+----+------------+
3307                      *    0    1    2    3    4           12
3308                      *    *LOCATION: location of parent directory
3309                      */
3310                     length = 12;
3311                     if (extra_space(&ctl) < length)
3312                               bp = extra_next_record(&ctl, length);
3313                     if (bp != NULL) {
3314                               bp[1] = 'P';
3315                               bp[2] = 'L';
3316                               bp[3] = length;
3317                               bp[4] = 1;          /* version          */
3318                               set_num_733(bp + 5,
3319                                   rr_parent->dir_location);
3320                               bp += length;
3321                     }
3322                     extra_tell_used_size(&ctl, length);
3323           }
3324 
3325           /* Write "CL" System Use Entry. */
3326           if (rr_flag & RR_USE_CL) {
3327                     /*
3328                      *   "CL" Format:
3329                      *               len  ver
3330                      *    +----+----+----+----+------------+
3331                      *    | 'C'| 'L'| 0C | 01 | *LOCATION  |
3332                      *    +----+----+----+----+------------+
3333                      *    0    1    2    3    4           12
3334                      *    *LOCATION: location of child directory
3335                      */
3336                     length = 12;
3337                     if (extra_space(&ctl) < length)
3338                               bp = extra_next_record(&ctl, length);
3339                     if (bp != NULL) {
3340                               bp[1] = 'C';
3341                               bp[2] = 'L';
3342                               bp[3] = length;
3343                               bp[4] = 1;          /* version          */
3344                               set_num_733(bp + 5,
3345                                   isoent->rr_child->dir_location);
3346                               bp += length;
3347                     }
3348                     extra_tell_used_size(&ctl, length);
3349           }
3350 
3351           /* Write "PN" System Use Entry. */
3352           if (rr_flag & RR_USE_PN) {
3353                     /*
3354                      *   "PN" Format:
3355                      *               len  ver
3356                      *    +----+----+----+----+------------+------------+
3357                      *    | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low  |
3358                      *    +----+----+----+----+------------+------------+
3359                      *    0    1    2    3    4           12           20
3360                      */
3361                     length = 20;
3362                     if (extra_space(&ctl) < length)
3363                               bp = extra_next_record(&ctl, length);
3364                     if (bp != NULL) {
3365                               uint64_t dev;
3366 
3367                               bp[1] = 'P';
3368                               bp[2] = 'N';
3369                               bp[3] = length;
3370                               bp[4] = 1;          /* version          */
3371                               dev = (uint64_t)archive_entry_rdev(file->entry);
3372                               set_num_733(bp + 5, (uint32_t)(dev >> 32));
3373                               set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
3374                               bp += length;
3375                     }
3376                     extra_tell_used_size(&ctl, length);
3377           }
3378 
3379           /* Write "ZF" System Use Entry. */
3380           if (file->zisofs.header_size) {
3381                     /*
3382                      *   "ZF" Format:
3383                      *               len  ver
3384                      *    +----+----+----+----+----+----+-------------+
3385                      *    | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |
3386                      *    +----+----+----+----+----+----+-------------+
3387                      *    0    1    2    3    4    5    6             7
3388                      *    +--------------------+-------------------+
3389                      *    | Log2 of block Size | Uncompressed Size |
3390                      *    +--------------------+-------------------+
3391                      *    7                    8                   16
3392                      */
3393                     length = 16;
3394                     if (extra_space(&ctl) < length)
3395                               bp = extra_next_record(&ctl, length);
3396                     if (bp != NULL) {
3397                               bp[1] = 'Z';
3398                               bp[2] = 'F';
3399                               bp[3] = length;
3400                               bp[4] = 1;          /* version          */
3401                               bp[5] = 'p';
3402                               bp[6] = 'z';
3403                               bp[7] = file->zisofs.header_size;
3404                               bp[8] = file->zisofs.log2_bs;
3405                               set_num_733(bp + 9, file->zisofs.uncompressed_size);
3406                               bp += length;
3407                     }
3408                     extra_tell_used_size(&ctl, length);
3409           }
3410 
3411           /* Write "CE" System Use Entry. */
3412           if (t == DIR_REC_SELF && isoent == isoent->parent) {
3413                     length = RR_CE_SIZE;
3414                     if (bp != NULL)
3415                               set_SUSP_CE(bp+1, iso9660->location_rrip_er,
3416                                   0, RRIP_ER_SIZE);
3417                     extra_tell_used_size(&ctl, length);
3418           }
3419 
3420           extra_close_record(&ctl, 0);
3421 
3422           return (ctl.dr_len);
3423 }
3424 
3425 /*
3426  * Write data of a Directory Record or calculate writing bytes itself.
3427  * If parameter `p' is NULL, calculates the size of writing data, which
3428  * a Directory Record needs to write, then it saved and return
3429  * the calculated size.
3430  * Parameter `n' is a remaining size of buffer. when parameter `p' is
3431  * not NULL, check whether that `n' is not less than the saved size.
3432  * if that `n' is small, return zero.
3433  *
3434  * This format of the Directory Record is according to
3435  * ISO9660 Standard 9.1
3436  */
3437 static int
set_directory_record(unsigned char * p,size_t n,struct isoent * isoent,struct iso9660 * iso9660,enum dir_rec_type t,enum vdd_type vdd_type)3438 set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
3439     struct iso9660 *iso9660, enum dir_rec_type t,
3440     enum vdd_type vdd_type)
3441 {
3442           unsigned char *bp;
3443           size_t dr_len;
3444           size_t fi_len;
3445 
3446           if (p != NULL) {
3447                     /*
3448                      * Check whether a write buffer size is less than the
3449                      * saved size which is needed to write this Directory
3450                      * Record.
3451                      */
3452                     switch (t) {
3453                     case DIR_REC_VD:
3454                               dr_len = isoent->dr_len.vd; break;
3455                     case DIR_REC_SELF:
3456                               dr_len = isoent->dr_len.self; break;
3457                     case DIR_REC_PARENT:
3458                               dr_len = isoent->dr_len.parent; break;
3459                     case DIR_REC_NORMAL:
3460                     default:
3461                               dr_len = isoent->dr_len.normal; break;
3462                     }
3463                     if (dr_len > n)
3464                               return (0);/* Needs more buffer size. */
3465           }
3466 
3467           if (t == DIR_REC_NORMAL && isoent->identifier != NULL)
3468                     fi_len = isoent->id_len;
3469           else
3470                     fi_len = 1;
3471 
3472           if (p != NULL) {
3473                     struct isoent *xisoent;
3474                     struct isofile *file;
3475                     unsigned char flag;
3476 
3477                     if (t == DIR_REC_PARENT)
3478                               xisoent = isoent->parent;
3479                     else
3480                               xisoent = isoent;
3481                     file = isoent->file;
3482                     if (file->hardlink_target != NULL)
3483                               file = file->hardlink_target;
3484                     /* Make a file flag. */
3485                     if (xisoent->dir)
3486                               flag = FILE_FLAG_DIRECTORY;
3487                     else {
3488                               if (file->cur_content->next != NULL)
3489                                         flag = FILE_FLAG_MULTI_EXTENT;
3490                               else
3491                                         flag = 0;
3492                     }
3493 
3494                     bp = p -1;
3495                     /* Extended Attribute Record Length */
3496                     set_num_711(bp+2, 0);
3497                     /* Location of Extent */
3498                     if (xisoent->dir)
3499                               set_num_733(bp+3, xisoent->dir_location);
3500                     else
3501                               set_num_733(bp+3, file->cur_content->location);
3502                     /* Data Length */
3503                     if (xisoent->dir)
3504                               set_num_733(bp+11,
3505                                   xisoent->dir_block * LOGICAL_BLOCK_SIZE);
3506                     else
3507                               set_num_733(bp+11, (uint32_t)file->cur_content->size);
3508                     /* Recording Date and Time */
3509                     /* NOTE:
3510                      *  If a file type is symbolic link, you are seeing this
3511                      *  field value is different from a value mkisofs makes.
3512                      *  libarchive uses lstat to get this one, but it
3513                      *  seems mkisofs uses stat to get.
3514                      */
3515                     set_time_915(bp+19,
3516                         archive_entry_mtime(xisoent->file->entry));
3517                     /* File Flags */
3518                     bp[26] = flag;
3519                     /* File Unit Size */
3520                     set_num_711(bp+27, 0);
3521                     /* Interleave Gap Size */
3522                     set_num_711(bp+28, 0);
3523                     /* Volume Sequence Number */
3524                     set_num_723(bp+29, iso9660->volume_sequence_number);
3525                     /* Length of File Identifier */
3526                     set_num_711(bp+33, (unsigned char)fi_len);
3527                     /* File Identifier */
3528                     switch (t) {
3529                     case DIR_REC_VD:
3530                     case DIR_REC_SELF:
3531                               set_num_711(bp+34, 0);
3532                               break;
3533                     case DIR_REC_PARENT:
3534                               set_num_711(bp+34, 1);
3535                               break;
3536                     case DIR_REC_NORMAL:
3537                               if (isoent->identifier != NULL)
3538                                         memcpy(bp+34, isoent->identifier, fi_len);
3539                               else
3540                                         set_num_711(bp+34, 0);
3541                               break;
3542                     }
3543           } else
3544                     bp = NULL;
3545           dr_len = 33 + fi_len;
3546           /* Padding Field */
3547           if (dr_len & 0x01) {
3548                     dr_len ++;
3549                     if (p != NULL)
3550                               bp[dr_len] = 0;
3551           }
3552 
3553           /* Volume Descriptor does not record extension. */
3554           if (t == DIR_REC_VD) {
3555                     if (p != NULL)
3556                               /* Length of Directory Record */
3557                               set_num_711(p, (unsigned char)dr_len);
3558                     else
3559                               isoent->dr_len.vd = (int)dr_len;
3560                     return ((int)dr_len);
3561           }
3562 
3563           /* Rockridge */
3564           if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
3565                     dr_len = set_directory_record_rr(bp, (int)dr_len,
3566                         isoent, iso9660, t);
3567 
3568           if (p != NULL)
3569                     /* Length of Directory Record */
3570                     set_num_711(p, (unsigned char)dr_len);
3571           else {
3572                     /*
3573                      * Save the size which is needed to write this
3574                      * Directory Record.
3575                      */
3576                     switch (t) {
3577                     case DIR_REC_VD:
3578                               /* This case does not come, but compiler
3579                                * complains that DIR_REC_VD not handled
3580                                *  in switch ....  */
3581                               break;
3582                     case DIR_REC_SELF:
3583                               isoent->dr_len.self = (int)dr_len; break;
3584                     case DIR_REC_PARENT:
3585                               isoent->dr_len.parent = (int)dr_len; break;
3586                     case DIR_REC_NORMAL:
3587                               isoent->dr_len.normal = (int)dr_len; break;
3588                     }
3589           }
3590 
3591           return ((int)dr_len);
3592 }
3593 
3594 /*
3595  * Calculate the size of a directory record.
3596  */
3597 static inline int
get_dir_rec_size(struct iso9660 * iso9660,struct isoent * isoent,enum dir_rec_type t,enum vdd_type vdd_type)3598 get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
3599     enum dir_rec_type t, enum vdd_type vdd_type)
3600 {
3601 
3602           return (set_directory_record(NULL, SIZE_MAX,
3603               isoent, iso9660, t, vdd_type));
3604 }
3605 
3606 /*
3607  * Manage to write ISO-image data with wbuff to reduce calling
3608  * __archive_write_output() for performance.
3609  */
3610 
3611 
3612 static inline unsigned char *
wb_buffptr(struct archive_write * a)3613 wb_buffptr(struct archive_write *a)
3614 {
3615           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3616 
3617           return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
3618                     - iso9660->wbuff_remaining]));
3619 }
3620 
3621 static int
wb_write_out(struct archive_write * a)3622 wb_write_out(struct archive_write *a)
3623 {
3624           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3625           size_t wsize, nw;
3626           int r;
3627 
3628           wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
3629           nw = wsize % LOGICAL_BLOCK_SIZE;
3630           if (iso9660->wbuff_type == WB_TO_STREAM)
3631                     r = __archive_write_output(a, iso9660->wbuff, wsize - nw);
3632           else
3633                     r = write_to_temp(a, iso9660->wbuff, wsize - nw);
3634           /* Increase the offset. */
3635           iso9660->wbuff_offset += wsize - nw;
3636           if (iso9660->wbuff_offset > iso9660->wbuff_written)
3637                     iso9660->wbuff_written = iso9660->wbuff_offset;
3638           iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3639           if (nw) {
3640                     iso9660->wbuff_remaining -= nw;
3641                     memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);
3642           }
3643           return (r);
3644 }
3645 
3646 static int
wb_consume(struct archive_write * a,size_t size)3647 wb_consume(struct archive_write *a, size_t size)
3648 {
3649           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3650 
3651           if (size > iso9660->wbuff_remaining ||
3652               iso9660->wbuff_remaining == 0) {
3653                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3654                         "Internal Programming error: iso9660:wb_consume()"
3655                         " size=%jd, wbuff_remaining=%jd",
3656                         (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);
3657                     return (ARCHIVE_FATAL);
3658           }
3659           iso9660->wbuff_remaining -= size;
3660           if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)
3661                     return (wb_write_out(a));
3662           return (ARCHIVE_OK);
3663 }
3664 
3665 #ifdef HAVE_ZLIB_H
3666 
3667 static int
wb_set_offset(struct archive_write * a,int64_t off)3668 wb_set_offset(struct archive_write *a, int64_t off)
3669 {
3670           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3671           int64_t used, ext_bytes;
3672 
3673           if (iso9660->wbuff_type != WB_TO_TEMP) {
3674                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3675                         "Internal Programming error: iso9660:wb_set_offset()");
3676                     return (ARCHIVE_FATAL);
3677           }
3678 
3679           used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
3680           if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)
3681                     iso9660->wbuff_tail = iso9660->wbuff_offset + used;
3682           if (iso9660->wbuff_offset < iso9660->wbuff_written) {
3683                     if (used > 0 &&
3684                         write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
3685                               return (ARCHIVE_FATAL);
3686                     iso9660->wbuff_offset = iso9660->wbuff_written;
3687                     lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
3688                     iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3689                     used = 0;
3690           }
3691           if (off < iso9660->wbuff_offset) {
3692                     /*
3693                      * Write out waiting data.
3694                      */
3695                     if (used > 0) {
3696                               if (wb_write_out(a) != ARCHIVE_OK)
3697                                         return (ARCHIVE_FATAL);
3698                     }
3699                     lseek(iso9660->temp_fd, off, SEEK_SET);
3700                     iso9660->wbuff_offset = off;
3701                     iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3702           } else if (off <= iso9660->wbuff_tail) {
3703                     iso9660->wbuff_remaining = (size_t)
3704                         (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
3705           } else {
3706                     ext_bytes = off - iso9660->wbuff_tail;
3707                     iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
3708                        - (iso9660->wbuff_tail - iso9660->wbuff_offset));
3709                     while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
3710                               if (write_null(a, (size_t)iso9660->wbuff_remaining)
3711                                   != ARCHIVE_OK)
3712                                         return (ARCHIVE_FATAL);
3713                               ext_bytes -= iso9660->wbuff_remaining;
3714                     }
3715                     if (ext_bytes > 0) {
3716                               if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)
3717                                         return (ARCHIVE_FATAL);
3718                     }
3719           }
3720           return (ARCHIVE_OK);
3721 }
3722 
3723 #endif /* HAVE_ZLIB_H */
3724 
3725 static int
write_null(struct archive_write * a,size_t size)3726 write_null(struct archive_write *a, size_t size)
3727 {
3728           size_t remaining;
3729           unsigned char *p, *old;
3730           int r;
3731 
3732           remaining = wb_remaining(a);
3733           p = wb_buffptr(a);
3734           if (size <= remaining) {
3735                     memset(p, 0, size);
3736                     return (wb_consume(a, size));
3737           }
3738           memset(p, 0, remaining);
3739           r = wb_consume(a, remaining);
3740           if (r != ARCHIVE_OK)
3741                     return (r);
3742           size -= remaining;
3743           old = p;
3744           p = wb_buffptr(a);
3745           memset(p, 0, old - p);
3746           remaining = wb_remaining(a);
3747           while (size) {
3748                     size_t wsize = size;
3749 
3750                     if (wsize > remaining)
3751                               wsize = remaining;
3752                     r = wb_consume(a, wsize);
3753                     if (r != ARCHIVE_OK)
3754                               return (r);
3755                     size -= wsize;
3756           }
3757           return (ARCHIVE_OK);
3758 }
3759 
3760 /*
3761  * Write Volume Descriptor Set Terminator
3762  */
3763 static int
write_VD_terminator(struct archive_write * a)3764 write_VD_terminator(struct archive_write *a)
3765 {
3766           unsigned char *bp;
3767 
3768           bp = wb_buffptr(a) -1;
3769           set_VD_bp(bp, VDT_TERMINATOR, 1);
3770           set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);
3771 
3772           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
3773 }
3774 
3775 static int
set_file_identifier(unsigned char * bp,int from,int to,enum vdc vdc,struct archive_write * a,struct vdd * vdd,struct archive_string * id,const char * label,int leading_under,enum char_type char_type)3776 set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
3777     struct archive_write *a, struct vdd *vdd, struct archive_string *id,
3778     const char *label, int leading_under, enum char_type char_type)
3779 {
3780           char identifier[256];
3781           struct isoent *isoent;
3782           const char *ids;
3783           size_t len;
3784           int r;
3785 
3786           if (id->length > 0 && leading_under && id->s[0] != '_') {
3787                     if (char_type == A_CHAR)
3788                               r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);
3789                     else
3790                               r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);
3791           } else if (id->length > 0) {
3792                     ids = id->s;
3793                     if (leading_under)
3794                               ids++;
3795                     isoent = isoent_find_entry(vdd->rootent, ids);
3796                     if (isoent == NULL) {
3797                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3798                                   "Not Found %s `%s'.",
3799                                   label, ids);
3800                               return (ARCHIVE_FATAL);
3801                     }
3802                     len = isoent->ext_off + isoent->ext_len;
3803                     if (vdd->vdd_type == VDD_JOLIET) {
3804                               if (len > sizeof(identifier)-2)
3805                                         len = sizeof(identifier)-2;
3806                     } else {
3807                               if (len > sizeof(identifier)-1)
3808                                         len = sizeof(identifier)-1;
3809                     }
3810                     memcpy(identifier, isoent->identifier, len);
3811                     identifier[len] = '\0';
3812                     if (vdd->vdd_type == VDD_JOLIET) {
3813                               identifier[len+1] = 0;
3814                               vdc = VDC_UCS2_DIRECT;
3815                     }
3816                     if (char_type == A_CHAR)
3817                               r = set_str_a_characters_bp(a, bp, from, to,
3818                                   identifier, vdc);
3819                     else
3820                               r = set_str_d_characters_bp(a, bp, from, to,
3821                                   identifier, vdc);
3822           } else {
3823                     if (char_type == A_CHAR)
3824                               r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);
3825                     else
3826                               r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);
3827           }
3828           return (r);
3829 }
3830 
3831 /*
3832  * Write Primary/Supplementary Volume Descriptor
3833  */
3834 static int
write_VD(struct archive_write * a,struct vdd * vdd)3835 write_VD(struct archive_write *a, struct vdd *vdd)
3836 {
3837           struct iso9660 *iso9660;
3838           unsigned char *bp;
3839           uint16_t volume_set_size = 1;
3840           char identifier[256];
3841           enum VD_type vdt;
3842           enum vdc vdc;
3843           unsigned char vd_ver, fst_ver;
3844           int r;
3845 
3846           iso9660 = a->format_data;
3847           switch (vdd->vdd_type) {
3848           case VDD_JOLIET:
3849                     vdt = VDT_SUPPLEMENTARY;
3850                     vd_ver = fst_ver = 1;
3851                     vdc = VDC_UCS2;
3852                     break;
3853           case VDD_ENHANCED:
3854                     vdt = VDT_SUPPLEMENTARY;
3855                     vd_ver = fst_ver = 2;
3856                     vdc = VDC_LOWERCASE;
3857                     break;
3858           case VDD_PRIMARY:
3859           default:
3860                     vdt = VDT_PRIMARY;
3861                     vd_ver = fst_ver = 1;
3862 #ifdef COMPAT_MKISOFS
3863                     vdc = VDC_LOWERCASE;
3864 #else
3865                     vdc = VDC_STD;
3866 #endif
3867                     break;
3868           }
3869 
3870           bp = wb_buffptr(a) -1;
3871           /* Volume Descriptor Type */
3872           set_VD_bp(bp, vdt, vd_ver);
3873           /* Unused Field */
3874           set_unused_field_bp(bp, 8, 8);
3875           /* System Identifier */
3876           get_system_identitier(identifier, sizeof(identifier));
3877           r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);
3878           if (r != ARCHIVE_OK)
3879                     return (r);
3880           /* Volume Identifier */
3881           r = set_str_d_characters_bp(a, bp, 41, 72,
3882               iso9660->volume_identifier.s, vdc);
3883           if (r != ARCHIVE_OK)
3884                     return (r);
3885           /* Unused Field */
3886           set_unused_field_bp(bp, 73, 80);
3887           /* Volume Space Size */
3888           set_num_733(bp+81, iso9660->volume_space_size);
3889           if (vdd->vdd_type == VDD_JOLIET) {
3890                     /* Escape Sequences */
3891                     bp[89] = 0x25;/* UCS-2 Level 3 */
3892                     bp[90] = 0x2F;
3893                     bp[91] = 0x45;
3894                     memset(bp + 92, 0, 120 - 92 + 1);
3895           } else {
3896                     /* Unused Field */
3897                     set_unused_field_bp(bp, 89, 120);
3898           }
3899           /* Volume Set Size */
3900           set_num_723(bp+121, volume_set_size);
3901           /* Volume Sequence Number */
3902           set_num_723(bp+125, iso9660->volume_sequence_number);
3903           /* Logical Block Size */
3904           set_num_723(bp+129, LOGICAL_BLOCK_SIZE);
3905           /* Path Table Size */
3906           set_num_733(bp+133, vdd->path_table_size);
3907           /* Location of Occurrence of Type L Path Table */
3908           set_num_731(bp+141, vdd->location_type_L_path_table);
3909           /* Location of Optional Occurrence of Type L Path Table */
3910           set_num_731(bp+145, 0);
3911           /* Location of Occurrence of Type M Path Table */
3912           set_num_732(bp+149, vdd->location_type_M_path_table);
3913           /* Location of Optional Occurrence of Type M Path Table */
3914           set_num_732(bp+153, 0);
3915           /* Directory Record for Root Directory(BP 157 to 190) */
3916           set_directory_record(bp+157, 190-157+1, vdd->rootent,
3917               iso9660, DIR_REC_VD, vdd->vdd_type);
3918           /* Volume Set Identifier */
3919           r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);
3920           if (r != ARCHIVE_OK)
3921                     return (r);
3922           /* Publisher Identifier */
3923           r = set_file_identifier(bp, 319, 446, vdc, a, vdd,
3924               &(iso9660->publisher_identifier),
3925               "Publisher File", 1, A_CHAR);
3926           if (r != ARCHIVE_OK)
3927                     return (r);
3928           /* Data Preparer Identifier */
3929           r = set_file_identifier(bp, 447, 574, vdc, a, vdd,
3930               &(iso9660->data_preparer_identifier),
3931               "Data Preparer File", 1, A_CHAR);
3932           if (r != ARCHIVE_OK)
3933                     return (r);
3934           /* Application Identifier */
3935           r = set_file_identifier(bp, 575, 702, vdc, a, vdd,
3936               &(iso9660->application_identifier),
3937               "Application File", 1, A_CHAR);
3938           if (r != ARCHIVE_OK)
3939                     return (r);
3940           /* Copyright File Identifier */
3941           r = set_file_identifier(bp, 703, 739, vdc, a, vdd,
3942               &(iso9660->copyright_file_identifier),
3943               "Copyright File", 0, D_CHAR);
3944           if (r != ARCHIVE_OK)
3945                     return (r);
3946           /* Abstract File Identifier */
3947           r = set_file_identifier(bp, 740, 776, vdc, a, vdd,
3948               &(iso9660->abstract_file_identifier),
3949               "Abstract File", 0, D_CHAR);
3950           if (r != ARCHIVE_OK)
3951                     return (r);
3952           /* Bibliographic File Identifier */
3953           r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
3954               &(iso9660->bibliographic_file_identifier),
3955               "Bibliongraphic File", 0, D_CHAR);
3956           if (r != ARCHIVE_OK)
3957                     return (r);
3958           /* Volume Creation Date and Time */
3959           set_date_time(bp+814, iso9660->birth_time);
3960           /* Volume Modification Date and Time */
3961           set_date_time(bp+831, iso9660->birth_time);
3962           /* Volume Expiration Date and Time(obsolete) */
3963           set_date_time_null(bp+848);
3964           /* Volume Effective Date and Time */
3965           set_date_time(bp+865, iso9660->birth_time);
3966           /* File Structure Version */
3967           bp[882] = fst_ver;
3968           /* Reserved */
3969           bp[883] = 0;
3970           /* Application Use */
3971           memset(bp + 884, 0x20, 1395 - 884 + 1);
3972           /* Reserved */
3973           set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);
3974 
3975           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
3976 }
3977 
3978 /*
3979  * Write Boot Record Volume Descriptor
3980  */
3981 static int
write_VD_boot_record(struct archive_write * a)3982 write_VD_boot_record(struct archive_write *a)
3983 {
3984           struct iso9660 *iso9660;
3985           unsigned char *bp;
3986 
3987           iso9660 = a->format_data;
3988           bp = wb_buffptr(a) -1;
3989           /* Volume Descriptor Type */
3990           set_VD_bp(bp, VDT_BOOT_RECORD, 1);
3991           /* Boot System Identifier */
3992           memcpy(bp+8, "EL TORITO SPECIFICATION", 23);
3993           set_unused_field_bp(bp, 8+23, 39);
3994           /* Unused */
3995           set_unused_field_bp(bp, 40, 71);
3996           /* Absolute pointer to first sector of Boot Catalog */
3997           set_num_731(bp+72,
3998               iso9660->el_torito.catalog->file->content.location);
3999           /* Unused */
4000           set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);
4001 
4002           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4003 }
4004 
4005 enum keytype {
4006           KEY_FLG,
4007           KEY_STR,
4008           KEY_INT,
4009           KEY_HEX
4010 };
4011 static void
set_option_info(struct archive_string * info,int * opt,const char * key,enum keytype type,...)4012 set_option_info(struct archive_string *info, int *opt, const char *key,
4013     enum keytype type,  ...)
4014 {
4015           va_list ap;
4016           char prefix;
4017           const char *s;
4018           int d;
4019 
4020           prefix = (*opt==0)? ' ':',';
4021           va_start(ap, type);
4022           switch (type) {
4023           case KEY_FLG:
4024                     d = va_arg(ap, int);
4025                     archive_string_sprintf(info, "%c%s%s",
4026                         prefix, (d == 0)?"!":"", key);
4027                     break;
4028           case KEY_STR:
4029                     s = va_arg(ap, const char *);
4030                     archive_string_sprintf(info, "%c%s=%s",
4031                         prefix, key, s);
4032                     break;
4033           case KEY_INT:
4034                     d = va_arg(ap, int);
4035                     archive_string_sprintf(info, "%c%s=%d",
4036                         prefix, key, d);
4037                     break;
4038           case KEY_HEX:
4039                     d = va_arg(ap, int);
4040                     archive_string_sprintf(info, "%c%s=%x",
4041                         prefix, key, d);
4042                     break;
4043           }
4044           va_end(ap);
4045 
4046           *opt = 1;
4047 }
4048 
4049 /*
4050  * Make Non-ISO File System Information
4051  */
4052 static int
write_information_block(struct archive_write * a)4053 write_information_block(struct archive_write *a)
4054 {
4055           struct iso9660 *iso9660;
4056           char buf[128];
4057           const char *v;
4058           int opt, r;
4059           struct archive_string info;
4060           size_t info_size = LOGICAL_BLOCK_SIZE *
4061                                      NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
4062 
4063           iso9660 = (struct iso9660 *)a->format_data;
4064           if (info_size > wb_remaining(a)) {
4065                     r = wb_write_out(a);
4066                     if (r != ARCHIVE_OK)
4067                               return (r);
4068           }
4069           archive_string_init(&info);
4070           if (archive_string_ensure(&info, info_size) == NULL) {
4071                     archive_set_error(&a->archive, ENOMEM,
4072                         "Can't allocate memory");
4073                     return (ARCHIVE_FATAL);
4074           }
4075           memset(info.s, 0, info_size);
4076           opt = 0;
4077 #if defined(HAVE__CTIME64_S)
4078           {
4079                     __time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
4080                     _ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
4081           }
4082 #elif defined(HAVE_CTIME_R)
4083           ctime_r(&(iso9660->birth_time), buf);
4084 #else
4085           strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);
4086           buf[sizeof(buf)-1] = '\0';
4087 #endif
4088           archive_string_sprintf(&info,
4089               "INFO %s%s", buf, archive_version_string());
4090           if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)
4091                     set_option_info(&info, &opt, "abstract-file",
4092                         KEY_STR, iso9660->abstract_file_identifier.s);
4093           if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)
4094                     set_option_info(&info, &opt, "application-id",
4095                         KEY_STR, iso9660->application_identifier.s);
4096           if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)
4097                     set_option_info(&info, &opt, "allow-vernum",
4098                         KEY_FLG, iso9660->opt.allow_vernum);
4099           if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)
4100                     set_option_info(&info, &opt, "biblio-file",
4101                         KEY_STR, iso9660->bibliographic_file_identifier.s);
4102           if (iso9660->opt.boot != OPT_BOOT_DEFAULT)
4103                     set_option_info(&info, &opt, "boot",
4104                         KEY_STR, iso9660->el_torito.boot_filename.s);
4105           if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)
4106                     set_option_info(&info, &opt, "boot-catalog",
4107                         KEY_STR, iso9660->el_torito.catalog_filename.s);
4108           if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)
4109                     set_option_info(&info, &opt, "boot-info-table",
4110                         KEY_FLG, iso9660->opt.boot_info_table);
4111           if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)
4112                     set_option_info(&info, &opt, "boot-load-seg",
4113                         KEY_HEX, iso9660->el_torito.boot_load_seg);
4114           if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)
4115                     set_option_info(&info, &opt, "boot-load-size",
4116                         KEY_INT, iso9660->el_torito.boot_load_size);
4117           if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {
4118                     v = "no-emulation";
4119                     if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)
4120                               v = "fd";
4121                     if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)
4122                               v = "hard-disk";
4123                     set_option_info(&info, &opt, "boot-type",
4124                         KEY_STR, v);
4125           }
4126 #ifdef HAVE_ZLIB_H
4127           if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)
4128                     set_option_info(&info, &opt, "compression-level",
4129                         KEY_INT, iso9660->zisofs.compression_level);
4130 #endif
4131           if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)
4132                     set_option_info(&info, &opt, "copyright-file",
4133                         KEY_STR, iso9660->copyright_file_identifier.s);
4134           if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)
4135                     set_option_info(&info, &opt, "iso-level",
4136                         KEY_INT, iso9660->opt.iso_level);
4137           if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {
4138                     if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
4139                               set_option_info(&info, &opt, "joliet",
4140                                   KEY_STR, "long");
4141                     else
4142                               set_option_info(&info, &opt, "joliet",
4143                                   KEY_FLG, iso9660->opt.joliet);
4144           }
4145           if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)
4146                     set_option_info(&info, &opt, "limit-depth",
4147                         KEY_FLG, iso9660->opt.limit_depth);
4148           if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)
4149                     set_option_info(&info, &opt, "limit-dirs",
4150                         KEY_FLG, iso9660->opt.limit_dirs);
4151           if (iso9660->opt.pad != OPT_PAD_DEFAULT)
4152                     set_option_info(&info, &opt, "pad",
4153                         KEY_FLG, iso9660->opt.pad);
4154           if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)
4155                     set_option_info(&info, &opt, "publisher",
4156                         KEY_STR, iso9660->publisher_identifier.s);
4157           if (iso9660->opt.rr != OPT_RR_DEFAULT) {
4158                     if (iso9660->opt.rr == OPT_RR_DISABLED)
4159                               set_option_info(&info, &opt, "rockridge",
4160                                   KEY_FLG, iso9660->opt.rr);
4161                     else if (iso9660->opt.rr == OPT_RR_STRICT)
4162                               set_option_info(&info, &opt, "rockridge",
4163                                   KEY_STR, "strict");
4164                     else if (iso9660->opt.rr == OPT_RR_USEFUL)
4165                               set_option_info(&info, &opt, "rockridge",
4166                                   KEY_STR, "useful");
4167           }
4168           if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)
4169                     set_option_info(&info, &opt, "volume-id",
4170                         KEY_STR, iso9660->volume_identifier.s);
4171           if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)
4172                     set_option_info(&info, &opt, "zisofs",
4173                         KEY_FLG, iso9660->opt.zisofs);
4174 
4175           memcpy(wb_buffptr(a), info.s, info_size);
4176           archive_string_free(&info);
4177           return (wb_consume(a, info_size));
4178 }
4179 
4180 static int
write_rr_ER(struct archive_write * a)4181 write_rr_ER(struct archive_write *a)
4182 {
4183           unsigned char *p;
4184 
4185           p = wb_buffptr(a);
4186 
4187           memset(p, 0, LOGICAL_BLOCK_SIZE);
4188           p[0] = 'E';
4189           p[1] = 'R';
4190           p[3] = 0x01;
4191           p[2] = RRIP_ER_SIZE;
4192           p[4] = RRIP_ER_ID_SIZE;
4193           p[5] = RRIP_ER_DSC_SIZE;
4194           p[6] = RRIP_ER_SRC_SIZE;
4195           p[7] = 0x01;
4196           memcpy(&p[8], rrip_identifier, p[4]);
4197           memcpy(&p[8+p[4]], rrip_descriptor, p[5]);
4198           memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);
4199 
4200           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4201 }
4202 
4203 static void
calculate_path_table_size(struct vdd * vdd)4204 calculate_path_table_size(struct vdd *vdd)
4205 {
4206           int depth, size;
4207           struct path_table *pt;
4208 
4209           pt = vdd->pathtbl;
4210           size = 0;
4211           for (depth = 0; depth < vdd->max_depth; depth++) {
4212                     struct isoent **ptbl;
4213                     int i, cnt;
4214 
4215                     if ((cnt = pt[depth].cnt) == 0)
4216                               break;
4217 
4218                     ptbl = pt[depth].sorted;
4219                     for (i = 0; i < cnt; i++) {
4220                               int len;
4221 
4222                               if (ptbl[i]->identifier == NULL)
4223                                         len = 1; /* root directory */
4224                               else
4225                                         len = ptbl[i]->id_len;
4226                               if (len & 0x01)
4227                                         len++; /* Padding Field */
4228                               size += 8 + len;
4229                     }
4230           }
4231           vdd->path_table_size = size;
4232           vdd->path_table_block =
4233               ((size + PATH_TABLE_BLOCK_SIZE -1) /
4234               PATH_TABLE_BLOCK_SIZE) *
4235               (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);
4236 }
4237 
4238 static int
_write_path_table(struct archive_write * a,int type_m,int depth,struct vdd * vdd)4239 _write_path_table(struct archive_write *a, int type_m, int depth,
4240     struct vdd *vdd)
4241 {
4242           unsigned char *bp, *wb;
4243           struct isoent **ptbl;
4244           size_t wbremaining;
4245           int i, r, wsize;
4246 
4247           if (vdd->pathtbl[depth].cnt == 0)
4248                     return (0);
4249 
4250           wsize = 0;
4251           wb = wb_buffptr(a);
4252           wbremaining = wb_remaining(a);
4253           bp = wb - 1;
4254           ptbl = vdd->pathtbl[depth].sorted;
4255           for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {
4256                     struct isoent *np;
4257                     size_t len;
4258 
4259                     np = ptbl[i];
4260                     if (np->identifier == NULL)
4261                               len = 1; /* root directory */
4262                     else
4263                               len = np->id_len;
4264                     if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {
4265                               r = wb_consume(a, (bp+1) - wb);
4266                               if (r < 0)
4267                                         return (r);
4268                               wb = wb_buffptr(a);
4269                               wbremaining = wb_remaining(a);
4270                               bp = wb -1;
4271                     }
4272                     /* Length of Directory Identifier */
4273                     set_num_711(bp+1, (unsigned char)len);
4274                     /* Extended Attribute Record Length */
4275                     set_num_711(bp+2, 0);
4276                     /* Location of Extent */
4277                     if (type_m)
4278                               set_num_732(bp+3, np->dir_location);
4279                     else
4280                               set_num_731(bp+3, np->dir_location);
4281                     /* Parent Directory Number */
4282                     if (type_m)
4283                               set_num_722(bp+7, np->parent->dir_number);
4284                     else
4285                               set_num_721(bp+7, np->parent->dir_number);
4286                     /* Directory Identifier */
4287                     if (np->identifier == NULL)
4288                               bp[9] = 0;
4289                     else
4290                               memcpy(&bp[9], np->identifier, len);
4291                     if (len & 0x01) {
4292                               /* Padding Field */
4293                               bp[9+len] = 0;
4294                               len++;
4295                     }
4296                     wsize += 8 + (int)len;
4297                     bp += 8 + len;
4298           }
4299           if ((bp + 1) > wb) {
4300                     r = wb_consume(a, (bp+1)-wb);
4301                     if (r < 0)
4302                               return (r);
4303           }
4304           return (wsize);
4305 }
4306 
4307 static int
write_path_table(struct archive_write * a,int type_m,struct vdd * vdd)4308 write_path_table(struct archive_write *a, int type_m, struct vdd *vdd)
4309 {
4310           int depth, r;
4311           size_t path_table_size;
4312 
4313           r = ARCHIVE_OK;
4314           path_table_size = 0;
4315           for (depth = 0; depth < vdd->max_depth; depth++) {
4316                     r = _write_path_table(a, type_m, depth, vdd);
4317                     if (r < 0)
4318                               return (r);
4319                     path_table_size += r;
4320           }
4321 
4322           /* Write padding data. */
4323           path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;
4324           if (path_table_size > 0)
4325                     r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);
4326           return (r);
4327 }
4328 
4329 static int
calculate_directory_descriptors(struct iso9660 * iso9660,struct vdd * vdd,struct isoent * isoent,int depth)4330 calculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,
4331     struct isoent *isoent, int depth)
4332 {
4333           struct isoent **enttbl;
4334           int bs, block, i;
4335 
4336           block = 1;
4337           bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);
4338           bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);
4339 
4340           if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
4341               !iso9660->opt.rr && depth + 1 >= vdd->max_depth))
4342                     return (block);
4343 
4344           enttbl = isoent->children_sorted;
4345           for (i = 0; i < isoent->children.cnt; i++) {
4346                     struct isoent *np = enttbl[i];
4347                     struct isofile *file;
4348 
4349                     file = np->file;
4350                     if (file->hardlink_target != NULL)
4351                               file = file->hardlink_target;
4352                     file->cur_content = &(file->content);
4353                     do {
4354                               int dr_l;
4355 
4356                               dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,
4357                                   vdd->vdd_type);
4358                               if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {
4359                                         block ++;
4360                                         bs = dr_l;
4361                               } else
4362                                         bs += dr_l;
4363                               file->cur_content = file->cur_content->next;
4364                     } while (file->cur_content != NULL);
4365           }
4366           return (block);
4367 }
4368 
4369 static int
_write_directory_descriptors(struct archive_write * a,struct vdd * vdd,struct isoent * isoent,int depth)4370 _write_directory_descriptors(struct archive_write *a, struct vdd *vdd,
4371     struct isoent *isoent, int depth)
4372 {
4373           struct iso9660 *iso9660 = a->format_data;
4374           struct isoent **enttbl;
4375           unsigned char *p, *wb;
4376           int i, r;
4377           int dr_l;
4378 
4379           p = wb = wb_buffptr(a);
4380 #define WD_REMAINING          (LOGICAL_BLOCK_SIZE - (p - wb))
4381           p += set_directory_record(p, WD_REMAINING, isoent,
4382               iso9660, DIR_REC_SELF, vdd->vdd_type);
4383           p += set_directory_record(p, WD_REMAINING, isoent,
4384               iso9660, DIR_REC_PARENT, vdd->vdd_type);
4385 
4386           if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
4387               !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {
4388                     memset(p, 0, WD_REMAINING);
4389                     return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4390           }
4391 
4392           enttbl = isoent->children_sorted;
4393           for (i = 0; i < isoent->children.cnt; i++) {
4394                     struct isoent *np = enttbl[i];
4395                     struct isofile *file = np->file;
4396 
4397                     if (file->hardlink_target != NULL)
4398                               file = file->hardlink_target;
4399                     file->cur_content = &(file->content);
4400                     do {
4401                               dr_l = set_directory_record(p, WD_REMAINING,
4402                                   np, iso9660, DIR_REC_NORMAL,
4403                                   vdd->vdd_type);
4404                               if (dr_l == 0) {
4405                                         memset(p, 0, WD_REMAINING);
4406                                         r = wb_consume(a, LOGICAL_BLOCK_SIZE);
4407                                         if (r < 0)
4408                                                   return (r);
4409                                         p = wb = wb_buffptr(a);
4410                                         dr_l = set_directory_record(p,
4411                                             WD_REMAINING, np, iso9660,
4412                                             DIR_REC_NORMAL, vdd->vdd_type);
4413                               }
4414                               p += dr_l;
4415                               file->cur_content = file->cur_content->next;
4416                     } while (file->cur_content != NULL);
4417           }
4418           memset(p, 0, WD_REMAINING);
4419           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4420 }
4421 
4422 static int
write_directory_descriptors(struct archive_write * a,struct vdd * vdd)4423 write_directory_descriptors(struct archive_write *a, struct vdd *vdd)
4424 {
4425           struct isoent *np;
4426           int depth, r;
4427 
4428           depth = 0;
4429           np = vdd->rootent;
4430           do {
4431                     struct extr_rec *extr;
4432 
4433                     r = _write_directory_descriptors(a, vdd, np, depth);
4434                     if (r < 0)
4435                               return (r);
4436                     if (vdd->vdd_type != VDD_JOLIET) {
4437                               /*
4438                                * This extract record is used by SUSP,RRIP.
4439                                * Not for joliet.
4440                                */
4441                               for (extr = np->extr_rec_list.first;
4442                                   extr != NULL;
4443                                   extr = extr->next) {
4444                                         unsigned char *wb;
4445 
4446                                         wb = wb_buffptr(a);
4447                                         memcpy(wb, extr->buf, extr->offset);
4448                                         memset(wb + extr->offset, 0,
4449                                             LOGICAL_BLOCK_SIZE - extr->offset);
4450                                         r = wb_consume(a, LOGICAL_BLOCK_SIZE);
4451                                         if (r < 0)
4452                                                   return (r);
4453                               }
4454                     }
4455 
4456                     if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
4457                               /* Enter to sub directories. */
4458                               np = np->subdirs.first;
4459                               depth++;
4460                               continue;
4461                     }
4462                     while (np != np->parent) {
4463                               if (np->drnext == NULL) {
4464                                         /* Return to the parent directory. */
4465                                         np = np->parent;
4466                                         depth--;
4467                               } else {
4468                                         np = np->drnext;
4469                                         break;
4470                               }
4471                     }
4472           } while (np != np->parent);
4473 
4474           return (ARCHIVE_OK);
4475 }
4476 
4477 /*
4478  * Read file contents from the temporary file, and write it.
4479  */
4480 static int
write_file_contents(struct archive_write * a,int64_t offset,int64_t size)4481 write_file_contents(struct archive_write *a, int64_t offset, int64_t size)
4482 {
4483           struct iso9660 *iso9660 = a->format_data;
4484           int r;
4485 
4486           lseek(iso9660->temp_fd, offset, SEEK_SET);
4487 
4488           while (size) {
4489                     size_t rsize;
4490                     ssize_t rs;
4491                     unsigned char *wb;
4492 
4493                     wb = wb_buffptr(a);
4494                     rsize = wb_remaining(a);
4495                     if (rsize > (size_t)size)
4496                               rsize = (size_t)size;
4497                     rs = read(iso9660->temp_fd, wb, rsize);
4498                     if (rs <= 0) {
4499                               archive_set_error(&a->archive, errno,
4500                                   "Can't read temporary file(%jd)", (intmax_t)rs);
4501                               return (ARCHIVE_FATAL);
4502                     }
4503                     size -= rs;
4504                     r = wb_consume(a, rs);
4505                     if (r < 0)
4506                               return (r);
4507           }
4508           return (ARCHIVE_OK);
4509 }
4510 
4511 static int
write_file_descriptors(struct archive_write * a)4512 write_file_descriptors(struct archive_write *a)
4513 {
4514           struct iso9660 *iso9660 = a->format_data;
4515           struct isofile *file;
4516           int64_t blocks, offset;
4517           int r;
4518 
4519           blocks = 0;
4520           offset = 0;
4521 
4522           /* Make the boot catalog contents, and write it. */
4523           if (iso9660->el_torito.catalog != NULL) {
4524                     r = make_boot_catalog(a);
4525                     if (r < 0)
4526                               return (r);
4527           }
4528 
4529           /* Write the boot file contents. */
4530           if (iso9660->el_torito.boot != NULL) {
4531                     file = iso9660->el_torito.boot->file;
4532                     blocks = file->content.blocks;
4533                     offset = file->content.offset_of_temp;
4534                     if (offset != 0) {
4535                               r = write_file_contents(a, offset,
4536                                   blocks << LOGICAL_BLOCK_BITS);
4537                               if (r < 0)
4538                                         return (r);
4539                               blocks = 0;
4540                               offset = 0;
4541                     }
4542           }
4543 
4544           /* Write out all file contents. */
4545           for (file = iso9660->data_file_list.first;
4546               file != NULL; file = file->datanext) {
4547 
4548                     if (!file->write_content)
4549                               continue;
4550 
4551                     if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <
4552                          file->content.offset_of_temp) {
4553                               if (blocks > 0) {
4554                                         r = write_file_contents(a, offset,
4555                                             blocks << LOGICAL_BLOCK_BITS);
4556                                         if (r < 0)
4557                                                   return (r);
4558                               }
4559                               blocks = 0;
4560                               offset = file->content.offset_of_temp;
4561                     }
4562 
4563                     file->cur_content = &(file->content);
4564                     do {
4565                               blocks += file->cur_content->blocks;
4566                               /* Next fragment */
4567                               file->cur_content = file->cur_content->next;
4568                     } while (file->cur_content != NULL);
4569           }
4570 
4571           /* Flush out remaining blocks. */
4572           if (blocks > 0) {
4573                     r = write_file_contents(a, offset,
4574                         blocks << LOGICAL_BLOCK_BITS);
4575                     if (r < 0)
4576                               return (r);
4577           }
4578 
4579           return (ARCHIVE_OK);
4580 }
4581 
4582 static void
isofile_init_entry_list(struct iso9660 * iso9660)4583 isofile_init_entry_list(struct iso9660 *iso9660)
4584 {
4585           iso9660->all_file_list.first = NULL;
4586           iso9660->all_file_list.last = &(iso9660->all_file_list.first);
4587 }
4588 
4589 static void
isofile_add_entry(struct iso9660 * iso9660,struct isofile * file)4590 isofile_add_entry(struct iso9660 *iso9660, struct isofile *file)
4591 {
4592           file->allnext = NULL;
4593           *iso9660->all_file_list.last = file;
4594           iso9660->all_file_list.last = &(file->allnext);
4595 }
4596 
4597 static void
isofile_free_all_entries(struct iso9660 * iso9660)4598 isofile_free_all_entries(struct iso9660 *iso9660)
4599 {
4600           struct isofile *file, *file_next;
4601 
4602           file = iso9660->all_file_list.first;
4603           while (file != NULL) {
4604                     file_next = file->allnext;
4605                     isofile_free(file);
4606                     file = file_next;
4607           }
4608 }
4609 
4610 static void
isofile_init_entry_data_file_list(struct iso9660 * iso9660)4611 isofile_init_entry_data_file_list(struct iso9660 *iso9660)
4612 {
4613           iso9660->data_file_list.first = NULL;
4614           iso9660->data_file_list.last = &(iso9660->data_file_list.first);
4615 }
4616 
4617 static void
isofile_add_data_file(struct iso9660 * iso9660,struct isofile * file)4618 isofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)
4619 {
4620           file->datanext = NULL;
4621           *iso9660->data_file_list.last = file;
4622           iso9660->data_file_list.last = &(file->datanext);
4623 }
4624 
4625 
4626 static struct isofile *
isofile_new(struct archive_write * a,struct archive_entry * entry)4627 isofile_new(struct archive_write *a, struct archive_entry *entry)
4628 {
4629           struct isofile *file;
4630 
4631           file = calloc(1, sizeof(*file));
4632           if (file == NULL)
4633                     return (NULL);
4634 
4635           if (entry != NULL)
4636                     file->entry = archive_entry_clone(entry);
4637           else
4638                     file->entry = archive_entry_new2(&a->archive);
4639           if (file->entry == NULL) {
4640                     free(file);
4641                     return (NULL);
4642           }
4643           archive_string_init(&(file->parentdir));
4644           archive_string_init(&(file->basename));
4645           archive_string_init(&(file->basename_utf16));
4646           archive_string_init(&(file->symlink));
4647           file->cur_content = &(file->content);
4648 
4649           return (file);
4650 }
4651 
4652 static void
isofile_free(struct isofile * file)4653 isofile_free(struct isofile *file)
4654 {
4655           struct content *con, *tmp;
4656 
4657           con = file->content.next;
4658           while (con != NULL) {
4659                     tmp = con;
4660                     con = con->next;
4661                     free(tmp);
4662           }
4663           archive_entry_free(file->entry);
4664           archive_string_free(&(file->parentdir));
4665           archive_string_free(&(file->basename));
4666           archive_string_free(&(file->basename_utf16));
4667           archive_string_free(&(file->symlink));
4668           free(file);
4669 }
4670 
4671 #if defined(_WIN32) || defined(__CYGWIN__)
4672 static int
cleanup_backslash_1(char * p)4673 cleanup_backslash_1(char *p)
4674 {
4675           int mb, dos;
4676 
4677           mb = dos = 0;
4678           while (*p) {
4679                     if (*(unsigned char *)p > 127)
4680                               mb = 1;
4681                     if (*p == '\\') {
4682                               /* If we have not met any multi-byte characters,
4683                                * we can replace '\' with '/'. */
4684                               if (!mb)
4685                                         *p = '/';
4686                               dos = 1;
4687                     }
4688                     p++;
4689           }
4690           if (!mb || !dos)
4691                     return (0);
4692           return (-1);
4693 }
4694 
4695 static void
cleanup_backslash_2(wchar_t * p)4696 cleanup_backslash_2(wchar_t *p)
4697 {
4698 
4699           /* Convert a path-separator from '\' to  '/' */
4700           while (*p != L'\0') {
4701                     if (*p == L'\\')
4702                               *p = L'/';
4703                     p++;
4704           }
4705 }
4706 #endif
4707 
4708 /*
4709  * Generate a parent directory name and a base name from a pathname.
4710  */
4711 static int
isofile_gen_utility_names(struct archive_write * a,struct isofile * file)4712 isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
4713 {
4714           struct iso9660 *iso9660;
4715           const char *pathname;
4716           char *p, *dirname, *slash;
4717           size_t len;
4718           int ret = ARCHIVE_OK;
4719 
4720           iso9660 = a->format_data;
4721 
4722           archive_string_empty(&(file->parentdir));
4723           archive_string_empty(&(file->basename));
4724           archive_string_empty(&(file->basename_utf16));
4725           archive_string_empty(&(file->symlink));
4726 
4727           pathname =  archive_entry_pathname(file->entry);
4728           if (pathname == NULL || pathname[0] == '\0') {/* virtual root */
4729                     file->dircnt = 0;
4730                     return (ret);
4731           }
4732 
4733           /*
4734            * Make a UTF-16BE basename if Joliet extension enabled.
4735            */
4736           if (iso9660->opt.joliet) {
4737                     const char *u16, *ulast;
4738                     size_t u16len, ulen_last;
4739 
4740                     if (iso9660->sconv_to_utf16be == NULL) {
4741                               iso9660->sconv_to_utf16be =
4742                                   archive_string_conversion_to_charset(
4743                                         &(a->archive), "UTF-16BE", 1);
4744                               if (iso9660->sconv_to_utf16be == NULL)
4745                                         /* Couldn't allocate memory */
4746                                         return (ARCHIVE_FATAL);
4747                               iso9660->sconv_from_utf16be =
4748                                   archive_string_conversion_from_charset(
4749                                         &(a->archive), "UTF-16BE", 1);
4750                               if (iso9660->sconv_from_utf16be == NULL)
4751                                         /* Couldn't allocate memory */
4752                                         return (ARCHIVE_FATAL);
4753                     }
4754 
4755                     /*
4756                      * Convert a filename to UTF-16BE.
4757                      */
4758                     if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
4759                         iso9660->sconv_to_utf16be)) {
4760                               if (errno == ENOMEM) {
4761                                         archive_set_error(&a->archive, ENOMEM,
4762                                             "Can't allocate memory for UTF-16BE");
4763                                         return (ARCHIVE_FATAL);
4764                               }
4765                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4766                                   "A filename cannot be converted to UTF-16BE;"
4767                                   "You should disable making Joliet extension");
4768                               ret = ARCHIVE_WARN;
4769                     }
4770 
4771                     /*
4772                      * Make sure a path separator is not in the last;
4773                      * Remove trailing '/'.
4774                      */
4775                     while (u16len >= 2) {
4776 #if defined(_WIN32) || defined(__CYGWIN__)
4777                               if (u16[u16len-2] == 0 &&
4778                                   (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))
4779 #else
4780                               if (u16[u16len-2] == 0 && u16[u16len-1] == '/')
4781 #endif
4782                               {
4783                                         u16len -= 2;
4784                               } else
4785                                         break;
4786                     }
4787 
4788                     /*
4789                      * Find a basename in UTF-16BE.
4790                      */
4791                     ulast = u16;
4792                     u16len >>= 1;
4793                     ulen_last = u16len;
4794                     while (u16len > 0) {
4795 #if defined(_WIN32) || defined(__CYGWIN__)
4796                               if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))
4797 #else
4798                               if (u16[0] == 0 && u16[1] == '/')
4799 #endif
4800                               {
4801                                         ulast = u16 + 2;
4802                                         ulen_last = u16len -1;
4803                               }
4804                               u16 += 2;
4805                               u16len --;
4806                     }
4807                     ulen_last <<= 1;
4808                     if (archive_string_ensure(&(file->basename_utf16),
4809                         ulen_last) == NULL) {
4810                               archive_set_error(&a->archive, ENOMEM,
4811                                   "Can't allocate memory for UTF-16BE");
4812                               return (ARCHIVE_FATAL);
4813                     }
4814 
4815                     /*
4816                      * Set UTF-16BE basename.
4817                      */
4818                     memcpy(file->basename_utf16.s, ulast, ulen_last);
4819                     file->basename_utf16.length = ulen_last;
4820           }
4821 
4822           archive_strcpy(&(file->parentdir), pathname);
4823 #if defined(_WIN32) || defined(__CYGWIN__)
4824           /*
4825            * Convert a path-separator from '\' to  '/'
4826            */
4827           if (cleanup_backslash_1(file->parentdir.s) != 0) {
4828                     const wchar_t *wp = archive_entry_pathname_w(file->entry);
4829                     struct archive_wstring ws;
4830 
4831                     if (wp != NULL) {
4832                               int r;
4833                               archive_string_init(&ws);
4834                               archive_wstrcpy(&ws, wp);
4835                               cleanup_backslash_2(ws.s);
4836                               archive_string_empty(&(file->parentdir));
4837                               r = archive_string_append_from_wcs(&(file->parentdir),
4838                                   ws.s, ws.length);
4839                               archive_wstring_free(&ws);
4840                               if (r < 0 && errno == ENOMEM) {
4841                                         archive_set_error(&a->archive, ENOMEM,
4842                                             "Can't allocate memory");
4843                                         return (ARCHIVE_FATAL);
4844                               }
4845                     }
4846           }
4847 #endif
4848 
4849           len = file->parentdir.length;
4850           p = dirname = file->parentdir.s;
4851 
4852           /*
4853            * Remove leading '/', '../' and './' elements
4854            */
4855           while (*p) {
4856                     if (p[0] == '/') {
4857                               p++;
4858                               len--;
4859                     } else if (p[0] != '.')
4860                               break;
4861                     else if (p[1] == '.' && p[2] == '/') {
4862                               p += 3;
4863                               len -= 3;
4864                     } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
4865                               p += 2;
4866                               len -= 2;
4867                     } else if (p[1] == '\0') {
4868                               p++;
4869                               len--;
4870                     } else
4871                               break;
4872           }
4873           if (p != dirname) {
4874                     memmove(dirname, p, len+1);
4875                     p = dirname;
4876           }
4877           /*
4878            * Remove "/","/." and "/.." elements from tail.
4879            */
4880           while (len > 0) {
4881                     size_t ll = len;
4882 
4883                     if (len > 0 && p[len-1] == '/') {
4884                               p[len-1] = '\0';
4885                               len--;
4886                     }
4887                     if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
4888                               p[len-2] = '\0';
4889                               len -= 2;
4890                     }
4891                     if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
4892                         p[len-1] == '.') {
4893                               p[len-3] = '\0';
4894                               len -= 3;
4895                     }
4896                     if (ll == len)
4897                               break;
4898           }
4899           while (*p) {
4900                     if (p[0] == '/') {
4901                               if (p[1] == '/')
4902                                         /* Convert '//' --> '/' */
4903                                         memmove(p, p+1, strlen(p+1) + 1);
4904                               else if (p[1] == '.' && p[2] == '/')
4905                                         /* Convert '/./' --> '/' */
4906                                         memmove(p, p+2, strlen(p+2) + 1);
4907                               else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
4908                                         /* Convert 'dir/dir1/../dir2/'
4909                                          *     --> 'dir/dir2/'
4910                                          */
4911                                         char *rp = p -1;
4912                                         while (rp >= dirname) {
4913                                                   if (*rp == '/')
4914                                                             break;
4915                                                   --rp;
4916                                         }
4917                                         if (rp > dirname) {
4918                                                   strcpy(rp, p+3);
4919                                                   p = rp;
4920                                         } else {
4921                                                   strcpy(dirname, p+4);
4922                                                   p = dirname;
4923                                         }
4924                               } else
4925                                         p++;
4926                     } else
4927                               p++;
4928           }
4929           p = dirname;
4930           len = strlen(p);
4931 
4932           if (archive_entry_filetype(file->entry) == AE_IFLNK) {
4933                     /* Convert symlink name too. */
4934                     pathname = archive_entry_symlink(file->entry);
4935                     archive_strcpy(&(file->symlink),  pathname);
4936 #if defined(_WIN32) || defined(__CYGWIN__)
4937                     /*
4938                      * Convert a path-separator from '\' to  '/'
4939                      */
4940                     if (archive_strlen(&(file->symlink)) > 0 &&
4941                         cleanup_backslash_1(file->symlink.s) != 0) {
4942                               const wchar_t *wp =
4943                                   archive_entry_symlink_w(file->entry);
4944                               struct archive_wstring ws;
4945 
4946                               if (wp != NULL) {
4947                                         int r;
4948                                         archive_string_init(&ws);
4949                                         archive_wstrcpy(&ws, wp);
4950                                         cleanup_backslash_2(ws.s);
4951                                         archive_string_empty(&(file->symlink));
4952                                         r = archive_string_append_from_wcs(
4953                                             &(file->symlink),
4954                                             ws.s, ws.length);
4955                                         archive_wstring_free(&ws);
4956                                         if (r < 0 && errno == ENOMEM) {
4957                                                   archive_set_error(&a->archive, ENOMEM,
4958                                                       "Can't allocate memory");
4959                                                   return (ARCHIVE_FATAL);
4960                                         }
4961                               }
4962                     }
4963 #endif
4964           }
4965           /*
4966            * - Count up directory elements.
4967            * - Find out the position which points the last position of
4968            *   path separator('/').
4969            */
4970           slash = NULL;
4971           file->dircnt = 0;
4972           for (; *p != '\0'; p++)
4973                     if (*p == '/') {
4974                               slash = p;
4975                               file->dircnt++;
4976                     }
4977           if (slash == NULL) {
4978                     /* The pathname doesn't have a parent directory. */
4979                     file->parentdir.length = len;
4980                     archive_string_copy(&(file->basename), &(file->parentdir));
4981                     archive_string_empty(&(file->parentdir));
4982                     *file->parentdir.s = '\0';
4983                     return (ret);
4984           }
4985 
4986           /* Make a basename from dirname and slash */
4987           *slash  = '\0';
4988           file->parentdir.length = slash - dirname;
4989           archive_strcpy(&(file->basename),  slash + 1);
4990           if (archive_entry_filetype(file->entry) == AE_IFDIR)
4991                     file->dircnt ++;
4992           return (ret);
4993 }
4994 
4995 /*
4996  * Register a entry to get a hardlink target.
4997  */
4998 static int
isofile_register_hardlink(struct archive_write * a,struct isofile * file)4999 isofile_register_hardlink(struct archive_write *a, struct isofile *file)
5000 {
5001           struct iso9660 *iso9660 = a->format_data;
5002           struct hardlink *hl;
5003           const char *pathname;
5004 
5005           archive_entry_set_nlink(file->entry, 1);
5006           pathname = archive_entry_hardlink(file->entry);
5007           if (pathname == NULL) {
5008                     /* This `file` is a hardlink target. */
5009                     hl = malloc(sizeof(*hl));
5010                     if (hl == NULL) {
5011                               archive_set_error(&a->archive, ENOMEM,
5012                                   "Can't allocate memory");
5013                               return (ARCHIVE_FATAL);
5014                     }
5015                     hl->nlink = 1;
5016                     /* A hardlink target must be the first position. */
5017                     file->hlnext = NULL;
5018                     hl->file_list.first = file;
5019                     hl->file_list.last = &(file->hlnext);
5020                     __archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),
5021                         (struct archive_rb_node *)hl);
5022           } else {
5023                     hl = (struct hardlink *)__archive_rb_tree_find_node(
5024                         &(iso9660->hardlink_rbtree), pathname);
5025                     if (hl != NULL) {
5026                               /* Insert `file` entry into the tail. */
5027                               file->hlnext = NULL;
5028                               *hl->file_list.last = file;
5029                               hl->file_list.last = &(file->hlnext);
5030                               hl->nlink++;
5031                     }
5032                     archive_entry_unset_size(file->entry);
5033           }
5034 
5035           return (ARCHIVE_OK);
5036 }
5037 
5038 /*
5039  * Hardlinked files have to have the same location of extent.
5040  * We have to find out hardlink target entries for the entries
5041  * which have a hardlink target name.
5042  */
5043 static void
isofile_connect_hardlink_files(struct iso9660 * iso9660)5044 isofile_connect_hardlink_files(struct iso9660 *iso9660)
5045 {
5046           struct archive_rb_node *n;
5047           struct hardlink *hl;
5048           struct isofile *target, *nf;
5049 
5050           ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {
5051                     hl = (struct hardlink *)n;
5052 
5053                     /* The first entry must be a hardlink target. */
5054                     target = hl->file_list.first;
5055                     archive_entry_set_nlink(target->entry, hl->nlink);
5056                     /* Set a hardlink target to reference entries. */
5057                     for (nf = target->hlnext;
5058                         nf != NULL; nf = nf->hlnext) {
5059                               nf->hardlink_target = target;
5060                               archive_entry_set_nlink(nf->entry, hl->nlink);
5061                     }
5062           }
5063 }
5064 
5065 static int
isofile_hd_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)5066 isofile_hd_cmp_node(const struct archive_rb_node *n1,
5067     const struct archive_rb_node *n2)
5068 {
5069           const struct hardlink *h1 = (const struct hardlink *)n1;
5070           const struct hardlink *h2 = (const struct hardlink *)n2;
5071 
5072           return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
5073                            archive_entry_pathname(h2->file_list.first->entry)));
5074 }
5075 
5076 static int
isofile_hd_cmp_key(const struct archive_rb_node * n,const void * key)5077 isofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
5078 {
5079           const struct hardlink *h = (const struct hardlink *)n;
5080 
5081           return (strcmp(archive_entry_pathname(h->file_list.first->entry),
5082                            (const char *)key));
5083 }
5084 
5085 static void
isofile_init_hardlinks(struct iso9660 * iso9660)5086 isofile_init_hardlinks(struct iso9660 *iso9660)
5087 {
5088           static const struct archive_rb_tree_ops rb_ops = {
5089                     isofile_hd_cmp_node, isofile_hd_cmp_key,
5090           };
5091 
5092           __archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);
5093 }
5094 
5095 static void
isofile_free_hardlinks(struct iso9660 * iso9660)5096 isofile_free_hardlinks(struct iso9660 *iso9660)
5097 {
5098           struct archive_rb_node *n, *tmp;
5099 
5100           ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(iso9660->hardlink_rbtree), tmp) {
5101                     __archive_rb_tree_remove_node(&(iso9660->hardlink_rbtree), n);
5102                     free(n);
5103           }
5104 }
5105 
5106 static struct isoent *
isoent_new(struct isofile * file)5107 isoent_new(struct isofile *file)
5108 {
5109           struct isoent *isoent;
5110           static const struct archive_rb_tree_ops rb_ops = {
5111                     isoent_cmp_node, isoent_cmp_key,
5112           };
5113 
5114           isoent = calloc(1, sizeof(*isoent));
5115           if (isoent == NULL)
5116                     return (NULL);
5117           isoent->file = file;
5118           isoent->children.first = NULL;
5119           isoent->children.last = &(isoent->children.first);
5120           __archive_rb_tree_init(&(isoent->rbtree), &rb_ops);
5121           isoent->subdirs.first = NULL;
5122           isoent->subdirs.last = &(isoent->subdirs.first);
5123           isoent->extr_rec_list.first = NULL;
5124           isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);
5125           isoent->extr_rec_list.current = NULL;
5126           if (archive_entry_filetype(file->entry) == AE_IFDIR)
5127                     isoent->dir = 1;
5128 
5129           return (isoent);
5130 }
5131 
5132 static inline struct isoent *
isoent_clone(struct isoent * src)5133 isoent_clone(struct isoent *src)
5134 {
5135           return (isoent_new(src->file));
5136 }
5137 
5138 static void
_isoent_free(struct isoent * isoent)5139 _isoent_free(struct isoent *isoent)
5140 {
5141           struct extr_rec *er, *er_next;
5142 
5143           free(isoent->children_sorted);
5144           free(isoent->identifier);
5145           er = isoent->extr_rec_list.first;
5146           while (er != NULL) {
5147                     er_next = er->next;
5148                     free(er);
5149                     er = er_next;
5150           }
5151           free(isoent);
5152 }
5153 
5154 static void
isoent_free_all(struct isoent * isoent)5155 isoent_free_all(struct isoent *isoent)
5156 {
5157           struct isoent *np, *np_temp;
5158 
5159           if (isoent == NULL)
5160                     return;
5161           np = isoent;
5162           for (;;) {
5163                     if (np->dir) {
5164                               if (np->children.first != NULL) {
5165                                         /* Enter to sub directories. */
5166                                         np = np->children.first;
5167                                         continue;
5168                               }
5169                     }
5170                     for (;;) {
5171                               np_temp = np;
5172                               if (np->chnext == NULL) {
5173                                         /* Return to the parent directory. */
5174                                         np = np->parent;
5175                                         _isoent_free(np_temp);
5176                                         if (np == np_temp)
5177                                                   return;
5178                               } else {
5179                                         np = np->chnext;
5180                                         _isoent_free(np_temp);
5181                                         break;
5182                               }
5183                     }
5184           }
5185 }
5186 
5187 static struct isoent *
isoent_create_virtual_dir(struct archive_write * a,struct iso9660 * iso9660,const char * pathname)5188 isoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)
5189 {
5190           struct isofile *file;
5191           struct isoent *isoent;
5192 
5193           file = isofile_new(a, NULL);
5194           if (file == NULL)
5195                     return (NULL);
5196           archive_entry_set_pathname(file->entry, pathname);
5197           archive_entry_unset_mtime(file->entry);
5198           archive_entry_unset_atime(file->entry);
5199           archive_entry_unset_ctime(file->entry);
5200           archive_entry_set_uid(file->entry, getuid());
5201           archive_entry_set_gid(file->entry, getgid());
5202           archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
5203           archive_entry_set_nlink(file->entry, 2);
5204           if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
5205                     isofile_free(file);
5206                     return (NULL);
5207           }
5208           isofile_add_entry(iso9660, file);
5209 
5210           isoent = isoent_new(file);
5211           if (isoent == NULL)
5212                     return (NULL);
5213           isoent->dir = 1;
5214           isoent->virtual = 1;
5215 
5216           return (isoent);
5217 }
5218 
5219 static int
isoent_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)5220 isoent_cmp_node(const struct archive_rb_node *n1,
5221     const struct archive_rb_node *n2)
5222 {
5223           const struct isoent *e1 = (const struct isoent *)n1;
5224           const struct isoent *e2 = (const struct isoent *)n2;
5225 
5226           return (strcmp(e1->file->basename.s, e2->file->basename.s));
5227 }
5228 
5229 static int
isoent_cmp_key(const struct archive_rb_node * n,const void * key)5230 isoent_cmp_key(const struct archive_rb_node *n, const void *key)
5231 {
5232           const struct isoent *e = (const struct isoent *)n;
5233 
5234           return (strcmp(e->file->basename.s, (const char *)key));
5235 }
5236 
5237 static int
isoent_add_child_head(struct isoent * parent,struct isoent * child)5238 isoent_add_child_head(struct isoent *parent, struct isoent *child)
5239 {
5240 
5241           if (!__archive_rb_tree_insert_node(
5242               &(parent->rbtree), (struct archive_rb_node *)child))
5243                     return (0);
5244           if ((child->chnext = parent->children.first) == NULL)
5245                     parent->children.last = &(child->chnext);
5246           parent->children.first = child;
5247           parent->children.cnt++;
5248           child->parent = parent;
5249 
5250           /* Add a child to a sub-directory chain */
5251           if (child->dir) {
5252                     if ((child->drnext = parent->subdirs.first) == NULL)
5253                               parent->subdirs.last = &(child->drnext);
5254                     parent->subdirs.first = child;
5255                     parent->subdirs.cnt++;
5256                     child->parent = parent;
5257           } else
5258                     child->drnext = NULL;
5259           return (1);
5260 }
5261 
5262 static int
isoent_add_child_tail(struct isoent * parent,struct isoent * child)5263 isoent_add_child_tail(struct isoent *parent, struct isoent *child)
5264 {
5265 
5266           if (!__archive_rb_tree_insert_node(
5267               &(parent->rbtree), (struct archive_rb_node *)child))
5268                     return (0);
5269           child->chnext = NULL;
5270           *parent->children.last = child;
5271           parent->children.last = &(child->chnext);
5272           parent->children.cnt++;
5273           child->parent = parent;
5274 
5275           /* Add a child to a sub-directory chain */
5276           child->drnext = NULL;
5277           if (child->dir) {
5278                     *parent->subdirs.last = child;
5279                     parent->subdirs.last = &(child->drnext);
5280                     parent->subdirs.cnt++;
5281                     child->parent = parent;
5282           }
5283           return (1);
5284 }
5285 
5286 static void
isoent_remove_child(struct isoent * parent,struct isoent * child)5287 isoent_remove_child(struct isoent *parent, struct isoent *child)
5288 {
5289           struct isoent *ent;
5290 
5291           /* Remove a child entry from children chain. */
5292           ent = parent->children.first;
5293           while (ent->chnext != child)
5294                     ent = ent->chnext;
5295           if ((ent->chnext = ent->chnext->chnext) == NULL)
5296                     parent->children.last = &(ent->chnext);
5297           parent->children.cnt--;
5298 
5299           if (child->dir) {
5300                     /* Remove a child entry from sub-directory chain. */
5301                     ent = parent->subdirs.first;
5302                     while (ent->drnext != child)
5303                               ent = ent->drnext;
5304                     if ((ent->drnext = ent->drnext->drnext) == NULL)
5305                               parent->subdirs.last = &(ent->drnext);
5306                     parent->subdirs.cnt--;
5307           }
5308 
5309           __archive_rb_tree_remove_node(&(parent->rbtree),
5310               (struct archive_rb_node *)child);
5311 }
5312 
5313 static int
isoent_clone_tree(struct archive_write * a,struct isoent ** nroot,struct isoent * root)5314 isoent_clone_tree(struct archive_write *a, struct isoent **nroot,
5315     struct isoent *root)
5316 {
5317           struct isoent *np, *xroot, *newent;
5318 
5319           np = root;
5320           xroot = NULL;
5321           do {
5322                     newent = isoent_clone(np);
5323                     if (newent == NULL) {
5324                               archive_set_error(&a->archive, ENOMEM,
5325                                   "Can't allocate memory");
5326                               return (ARCHIVE_FATAL);
5327                     }
5328                     if (xroot == NULL) {
5329                               *nroot = xroot = newent;
5330                               newent->parent = xroot;
5331                     } else
5332                               isoent_add_child_tail(xroot, newent);
5333                     if (np->dir && np->children.first != NULL) {
5334                               /* Enter to sub directories. */
5335                               np = np->children.first;
5336                               xroot = newent;
5337                               continue;
5338                     }
5339                     while (np != np->parent) {
5340                               if (np->chnext == NULL) {
5341                                         /* Return to the parent directory. */
5342                                         np = np->parent;
5343                                         xroot = xroot->parent;
5344                               } else {
5345                                         np = np->chnext;
5346                                         break;
5347                               }
5348                     }
5349           } while (np != np->parent);
5350 
5351           return (ARCHIVE_OK);
5352 }
5353 
5354 /*
5355  * Setup directory locations.
5356  */
5357 static void
isoent_setup_directory_location(struct iso9660 * iso9660,int location,struct vdd * vdd)5358 isoent_setup_directory_location(struct iso9660 *iso9660, int location,
5359     struct vdd *vdd)
5360 {
5361           struct isoent *np;
5362           int depth;
5363 
5364           vdd->total_dir_block = 0;
5365           depth = 0;
5366           np = vdd->rootent;
5367           do {
5368                     int block;
5369 
5370                     np->dir_block = calculate_directory_descriptors(
5371                         iso9660, vdd, np, depth);
5372                     vdd->total_dir_block += np->dir_block;
5373                     np->dir_location = location;
5374                     location += np->dir_block;
5375                     block = extra_setup_location(np, location);
5376                     vdd->total_dir_block += block;
5377                     location += block;
5378 
5379                     if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
5380                               /* Enter to sub directories. */
5381                               np = np->subdirs.first;
5382                               depth++;
5383                               continue;
5384                     }
5385                     while (np != np->parent) {
5386                               if (np->drnext == NULL) {
5387                                         /* Return to the parent directory. */
5388                                         np = np->parent;
5389                                         depth--;
5390                               } else {
5391                                         np = np->drnext;
5392                                         break;
5393                               }
5394                     }
5395           } while (np != np->parent);
5396 }
5397 
5398 static void
_isoent_file_location(struct iso9660 * iso9660,struct isoent * isoent,int * symlocation)5399 _isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,
5400     int *symlocation)
5401 {
5402           struct isoent **children;
5403           int n;
5404 
5405           if (isoent->children.cnt == 0)
5406                     return;
5407 
5408           children = isoent->children_sorted;
5409           for (n = 0; n < isoent->children.cnt; n++) {
5410                     struct isoent *np;
5411                     struct isofile *file;
5412 
5413                     np = children[n];
5414                     if (np->dir)
5415                               continue;
5416                     if (np == iso9660->el_torito.boot)
5417                               continue;
5418                     file = np->file;
5419                     if (file->boot || file->hardlink_target != NULL)
5420                               continue;
5421                     if (archive_entry_filetype(file->entry) == AE_IFLNK ||
5422                         file->content.size == 0) {
5423                               /*
5424                                * Do not point a valid location.
5425                                * Make sure entry is not hardlink file.
5426                                */
5427                               file->content.location = (*symlocation)--;
5428                               continue;
5429                     }
5430 
5431                     file->write_content = 1;
5432           }
5433 }
5434 
5435 /*
5436  * Setup file locations.
5437  */
5438 static void
isoent_setup_file_location(struct iso9660 * iso9660,int location)5439 isoent_setup_file_location(struct iso9660 *iso9660, int location)
5440 {
5441           struct isoent *isoent;
5442           struct isoent *np;
5443           struct isofile *file;
5444           size_t size;
5445           int block;
5446           int depth;
5447           int joliet;
5448           int symlocation;
5449           int total_block;
5450 
5451           iso9660->total_file_block = 0;
5452           if ((isoent = iso9660->el_torito.catalog) != NULL) {
5453                     isoent->file->content.location = location;
5454                     block = (int)((archive_entry_size(isoent->file->entry) +
5455                         LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
5456                     location += block;
5457                     iso9660->total_file_block += block;
5458           }
5459           if ((isoent = iso9660->el_torito.boot) != NULL) {
5460                     isoent->file->content.location = location;
5461                     size = fd_boot_image_size(iso9660->el_torito.media_type);
5462                     if (size == 0)
5463                               size = (size_t)archive_entry_size(isoent->file->entry);
5464                     block = ((int)size + LOGICAL_BLOCK_SIZE -1)
5465                         >> LOGICAL_BLOCK_BITS;
5466                     location += block;
5467                     iso9660->total_file_block += block;
5468                     isoent->file->content.blocks = block;
5469           }
5470 
5471           depth = 0;
5472           symlocation = -16;
5473           if (!iso9660->opt.rr && iso9660->opt.joliet) {
5474                     joliet = 1;
5475                     np = iso9660->joliet.rootent;
5476           } else {
5477                     joliet = 0;
5478                     np = iso9660->primary.rootent;
5479           }
5480           do {
5481                     _isoent_file_location(iso9660, np, &symlocation);
5482 
5483                     if (np->subdirs.first != NULL &&
5484                         (joliet ||
5485                         ((iso9660->opt.rr == OPT_RR_DISABLED &&
5486                           depth + 2 < iso9660->primary.max_depth) ||
5487                          (iso9660->opt.rr &&
5488                           depth + 1 < iso9660->primary.max_depth)))) {
5489                               /* Enter to sub directories. */
5490                               np = np->subdirs.first;
5491                               depth++;
5492                               continue;
5493                     }
5494                     while (np != np->parent) {
5495                               if (np->drnext == NULL) {
5496                                         /* Return to the parent directory. */
5497                                         np = np->parent;
5498                                         depth--;
5499                               } else {
5500                                         np = np->drnext;
5501                                         break;
5502                               }
5503                     }
5504           } while (np != np->parent);
5505 
5506           total_block = 0;
5507           for (file = iso9660->data_file_list.first;
5508               file != NULL; file = file->datanext) {
5509 
5510                     if (!file->write_content)
5511                               continue;
5512 
5513                     file->cur_content = &(file->content);
5514                     do {
5515                               file->cur_content->location = location;
5516                               location += file->cur_content->blocks;
5517                               total_block += file->cur_content->blocks;
5518                               /* Next fragment */
5519                               file->cur_content = file->cur_content->next;
5520                     } while (file->cur_content != NULL);
5521           }
5522           iso9660->total_file_block += total_block;
5523 }
5524 
5525 static int
get_path_component(char * name,size_t n,const char * fn)5526 get_path_component(char *name, size_t n, const char *fn)
5527 {
5528           char *p;
5529           size_t l;
5530 
5531           p = strchr(fn, '/');
5532           if (p == NULL) {
5533                     if ((l = strlen(fn)) == 0)
5534                               return (0);
5535           } else
5536                     l = p - fn;
5537           if (l > n -1)
5538                     return (-1);
5539           memcpy(name, fn, l);
5540           name[l] = '\0';
5541 
5542           return ((int)l);
5543 }
5544 
5545 /*
5546  * Add a new entry into the tree.
5547  */
5548 static int
isoent_tree(struct archive_write * a,struct isoent ** isoentpp)5549 isoent_tree(struct archive_write *a, struct isoent **isoentpp)
5550 {
5551 #if defined(_WIN32) && !defined(__CYGWIN__)
5552           char name[_MAX_FNAME];/* Included null terminator size. */
5553 #elif defined(NAME_MAX) && NAME_MAX >= 255
5554           char name[NAME_MAX+1];
5555 #else
5556           char name[256];
5557 #endif
5558           struct iso9660 *iso9660 = a->format_data;
5559           struct isoent *dent, *isoent, *np;
5560           struct isofile *f1, *f2;
5561           const char *fn, *p;
5562           int l;
5563 
5564           isoent = *isoentpp;
5565           dent = iso9660->primary.rootent;
5566           if (isoent->file->parentdir.length > 0)
5567                     fn = p = isoent->file->parentdir.s;
5568           else
5569                     fn = p = "";
5570 
5571           /*
5572            * If the path of the parent directory of `isoent' entry is
5573            * the same as the path of `cur_dirent', add isoent to
5574            * `cur_dirent'.
5575            */
5576           if (archive_strlen(&(iso9660->cur_dirstr))
5577                 == archive_strlen(&(isoent->file->parentdir)) &&
5578               strcmp(iso9660->cur_dirstr.s, fn) == 0) {
5579                     if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {
5580                               np = (struct isoent *)__archive_rb_tree_find_node(
5581                                   &(iso9660->cur_dirent->rbtree),
5582                                   isoent->file->basename.s);
5583                               goto same_entry;
5584                     }
5585                     return (ARCHIVE_OK);
5586           }
5587 
5588           for (;;) {
5589                     l = get_path_component(name, sizeof(name), fn);
5590                     if (l == 0) {
5591                               np = NULL;
5592                               break;
5593                     }
5594                     if (l < 0) {
5595                               archive_set_error(&a->archive,
5596                                   ARCHIVE_ERRNO_MISC,
5597                                   "A name buffer is too small");
5598                               _isoent_free(isoent);
5599                               return (ARCHIVE_FATAL);
5600                     }
5601 
5602                     np = isoent_find_child(dent, name);
5603                     if (np == NULL || fn[0] == '\0')
5604                               break;
5605 
5606                     /* Find next subdirectory. */
5607                     if (!np->dir) {
5608                               /* NOT Directory! */
5609                               archive_set_error(&a->archive,
5610                                   ARCHIVE_ERRNO_MISC,
5611                                   "`%s' is not directory, we cannot insert `%s' ",
5612                                   archive_entry_pathname(np->file->entry),
5613                                   archive_entry_pathname(isoent->file->entry));
5614                               _isoent_free(isoent);
5615                               *isoentpp = NULL;
5616                               return (ARCHIVE_FAILED);
5617                     }
5618                     fn += l;
5619                     if (fn[0] == '/')
5620                               fn++;
5621                     dent = np;
5622           }
5623           if (np == NULL) {
5624                     /*
5625                      * Create virtual parent directories.
5626                      */
5627                     while (fn[0] != '\0') {
5628                               struct isoent *vp;
5629                               struct archive_string as;
5630 
5631                               archive_string_init(&as);
5632                               archive_strncat(&as, p, fn - p + l);
5633                               if (as.s[as.length-1] == '/') {
5634                                         as.s[as.length-1] = '\0';
5635                                         as.length--;
5636                               }
5637                               vp = isoent_create_virtual_dir(a, iso9660, as.s);
5638                               if (vp == NULL) {
5639                                         archive_string_free(&as);
5640                                         archive_set_error(&a->archive, ENOMEM,
5641                                             "Can't allocate memory");
5642                                         _isoent_free(isoent);
5643                                         *isoentpp = NULL;
5644                                         return (ARCHIVE_FATAL);
5645                               }
5646                               archive_string_free(&as);
5647 
5648                               if (vp->file->dircnt > iso9660->dircnt_max)
5649                                         iso9660->dircnt_max = vp->file->dircnt;
5650                               isoent_add_child_tail(dent, vp);
5651                               np = vp;
5652 
5653                               fn += l;
5654                               if (fn[0] == '/')
5655                                         fn++;
5656                               l = get_path_component(name, sizeof(name), fn);
5657                               if (l < 0) {
5658                                         archive_string_free(&as);
5659                                         archive_set_error(&a->archive,
5660                                             ARCHIVE_ERRNO_MISC,
5661                                             "A name buffer is too small");
5662                                         _isoent_free(isoent);
5663                                         *isoentpp = NULL;
5664                                         return (ARCHIVE_FATAL);
5665                               }
5666                               dent = np;
5667                     }
5668 
5669                     /* Found out the parent directory where isoent can be
5670                      * inserted. */
5671                     iso9660->cur_dirent = dent;
5672                     archive_string_empty(&(iso9660->cur_dirstr));
5673                     archive_string_ensure(&(iso9660->cur_dirstr),
5674                         archive_strlen(&(dent->file->parentdir)) +
5675                         archive_strlen(&(dent->file->basename)) + 2);
5676                     if (archive_strlen(&(dent->file->parentdir)) +
5677                         archive_strlen(&(dent->file->basename)) == 0)
5678                               iso9660->cur_dirstr.s[0] = 0;
5679                     else {
5680                               if (archive_strlen(&(dent->file->parentdir)) > 0) {
5681                                         archive_string_copy(&(iso9660->cur_dirstr),
5682                                             &(dent->file->parentdir));
5683                                         archive_strappend_char(&(iso9660->cur_dirstr), '/');
5684                               }
5685                               archive_string_concat(&(iso9660->cur_dirstr),
5686                                   &(dent->file->basename));
5687                     }
5688 
5689                     if (!isoent_add_child_tail(dent, isoent)) {
5690                               np = (struct isoent *)__archive_rb_tree_find_node(
5691                                   &(dent->rbtree), isoent->file->basename.s);
5692                               goto same_entry;
5693                     }
5694                     return (ARCHIVE_OK);
5695           }
5696 
5697 same_entry:
5698           /*
5699            * We have already has the entry the filename of which is
5700            * the same.
5701            */
5702           f1 = np->file;
5703           f2 = isoent->file;
5704 
5705           /* If the file type of entries is different,
5706            * we cannot handle it. */
5707           if (archive_entry_filetype(f1->entry) !=
5708               archive_entry_filetype(f2->entry)) {
5709                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
5710                         "Found duplicate entries `%s' and its file type is "
5711                         "different",
5712                         archive_entry_pathname(f1->entry));
5713                     _isoent_free(isoent);
5714                     *isoentpp = NULL;
5715                     return (ARCHIVE_FAILED);
5716           }
5717 
5718           /* Swap file entries. */
5719           np->file = f2;
5720           isoent->file = f1;
5721           np->virtual = 0;
5722 
5723           _isoent_free(isoent);
5724           *isoentpp = np;
5725           return (ARCHIVE_OK);
5726 }
5727 
5728 /*
5729  * Find a entry from `isoent'
5730  */
5731 static struct isoent *
isoent_find_child(struct isoent * isoent,const char * child_name)5732 isoent_find_child(struct isoent *isoent, const char *child_name)
5733 {
5734           struct isoent *np;
5735 
5736           np = (struct isoent *)__archive_rb_tree_find_node(
5737               &(isoent->rbtree), child_name);
5738           return (np);
5739 }
5740 
5741 /*
5742  * Find a entry full-path of which is specified by `fn' parameter,
5743  * in the tree.
5744  */
5745 static struct isoent *
isoent_find_entry(struct isoent * rootent,const char * fn)5746 isoent_find_entry(struct isoent *rootent, const char *fn)
5747 {
5748 #if defined(_WIN32) && !defined(__CYGWIN__)
5749           char name[_MAX_FNAME];/* Included null terminator size. */
5750 #elif defined(NAME_MAX) && NAME_MAX >= 255
5751           char name[NAME_MAX+1];
5752 #else
5753           char name[256];
5754 #endif
5755           struct isoent *isoent, *np;
5756           int l;
5757 
5758           isoent = rootent;
5759           np = NULL;
5760           for (;;) {
5761                     l = get_path_component(name, sizeof(name), fn);
5762                     if (l == 0)
5763                               break;
5764                     fn += l;
5765                     if (fn[0] == '/')
5766                               fn++;
5767 
5768                     np = isoent_find_child(isoent, name);
5769                     if (np == NULL)
5770                               break;
5771                     if (fn[0] == '\0')
5772                               break;/* We found out the entry */
5773 
5774                     /* Try sub directory. */
5775                     isoent = np;
5776                     np = NULL;
5777                     if (!isoent->dir)
5778                               break;/* Not directory */
5779           }
5780 
5781           return (np);
5782 }
5783 
5784 /*
5785  * Following idr_* functions are used for resolving duplicated filenames
5786  * and unreceivable filenames to generate ISO9660/Joliet Identifiers.
5787  */
5788 
5789 static void
idr_relaxed_filenames(char * map)5790 idr_relaxed_filenames(char *map)
5791 {
5792           int i;
5793 
5794           for (i = 0x21; i <= 0x2F; i++)
5795                     map[i] = 1;
5796           for (i = 0x3A; i <= 0x41; i++)
5797                     map[i] = 1;
5798           for (i = 0x5B; i <= 0x5E; i++)
5799                     map[i] = 1;
5800           map[0x60] = 1;
5801           for (i = 0x7B; i <= 0x7E; i++)
5802                     map[i] = 1;
5803 }
5804 
5805 static void
idr_init(struct iso9660 * iso9660,struct vdd * vdd,struct idr * idr)5806 idr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)
5807 {
5808 
5809           idr->idrent_pool = NULL;
5810           idr->pool_size = 0;
5811           if (vdd->vdd_type != VDD_JOLIET) {
5812                     if (iso9660->opt.iso_level <= 3) {
5813                               memcpy(idr->char_map, d_characters_map,
5814                                   sizeof(idr->char_map));
5815                     } else {
5816                               memcpy(idr->char_map, d1_characters_map,
5817                                   sizeof(idr->char_map));
5818                               idr_relaxed_filenames(idr->char_map);
5819                     }
5820           }
5821 }
5822 
5823 static void
idr_cleanup(struct idr * idr)5824 idr_cleanup(struct idr *idr)
5825 {
5826           free(idr->idrent_pool);
5827 }
5828 
5829 static int
idr_ensure_poolsize(struct archive_write * a,struct idr * idr,int cnt)5830 idr_ensure_poolsize(struct archive_write *a, struct idr *idr,
5831     int cnt)
5832 {
5833 
5834           if (idr->pool_size < cnt) {
5835                     void *p;
5836                     const int bk = (1 << 7) - 1;
5837                     int psize;
5838 
5839                     psize = (cnt + bk) & ~bk;
5840                     p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
5841                     if (p == NULL) {
5842                               archive_set_error(&a->archive, ENOMEM,
5843                                   "Can't allocate memory");
5844                               return (ARCHIVE_FATAL);
5845                     }
5846                     idr->idrent_pool = (struct idrent *)p;
5847                     idr->pool_size = psize;
5848           }
5849           return (ARCHIVE_OK);
5850 }
5851 
5852 static int
idr_start(struct archive_write * a,struct idr * idr,int cnt,int ffmax,int num_size,int null_size,const struct archive_rb_tree_ops * rbt_ops)5853 idr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,
5854     int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)
5855 {
5856           int r;
5857 
5858           (void)ffmax; /* UNUSED */
5859 
5860           r = idr_ensure_poolsize(a, idr, cnt);
5861           if (r != ARCHIVE_OK)
5862                     return (r);
5863           __archive_rb_tree_init(&(idr->rbtree), rbt_ops);
5864           idr->wait_list.first = NULL;
5865           idr->wait_list.last = &(idr->wait_list.first);
5866           idr->pool_idx = 0;
5867           idr->num_size = num_size;
5868           idr->null_size = null_size;
5869           return (ARCHIVE_OK);
5870 }
5871 
5872 static void
idr_register(struct idr * idr,struct isoent * isoent,int weight,int noff)5873 idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
5874 {
5875           struct idrent *idrent, *n;
5876 
5877           idrent = &(idr->idrent_pool[idr->pool_idx++]);
5878           idrent->wnext = idrent->avail = NULL;
5879           idrent->isoent = isoent;
5880           idrent->weight = weight;
5881           idrent->noff = noff;
5882           idrent->rename_num = 0;
5883 
5884           if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {
5885                     n = (struct idrent *)__archive_rb_tree_find_node(
5886                         &(idr->rbtree), idrent->isoent);
5887                     if (n != NULL) {
5888                               /* this `idrent' needs to rename. */
5889                               idrent->avail = n;
5890                               *idr->wait_list.last = idrent;
5891                               idr->wait_list.last = &(idrent->wnext);
5892                     }
5893           }
5894 }
5895 
5896 static void
idr_extend_identifier(struct idrent * wnp,int numsize,int nullsize)5897 idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
5898 {
5899           unsigned char *p;
5900           int wnp_ext_off;
5901 
5902           wnp_ext_off = wnp->isoent->ext_off;
5903           if (wnp->noff + numsize != wnp_ext_off) {
5904                     p = (unsigned char *)wnp->isoent->identifier;
5905                     /* Extend the filename; foo.c --> foo___.c */
5906                     memmove(p + wnp->noff + numsize, p + wnp_ext_off,
5907                         wnp->isoent->ext_len + nullsize);
5908                     wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
5909                     wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
5910           }
5911 }
5912 
5913 static void
idr_resolve(struct idr * idr,void (* fsetnum)(unsigned char * p,int num))5914 idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
5915 {
5916           struct idrent *n;
5917           unsigned char *p;
5918 
5919           for (n = idr->wait_list.first; n != NULL; n = n->wnext) {
5920                     idr_extend_identifier(n, idr->num_size, idr->null_size);
5921                     p = (unsigned char *)n->isoent->identifier + n->noff;
5922                     do {
5923                               fsetnum(p, n->avail->rename_num++);
5924                     } while (!__archive_rb_tree_insert_node(
5925                         &(idr->rbtree), &(n->rbnode)));
5926           }
5927 }
5928 
5929 static void
idr_set_num(unsigned char * p,int num)5930 idr_set_num(unsigned char *p, int num)
5931 {
5932           static const char xdig[] = {
5933                     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5934                     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
5935                     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
5936                     'U', 'V', 'W', 'X', 'Y', 'Z'
5937           };
5938 
5939           num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);
5940           p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];
5941           num %= sizeof(xdig) * sizeof(xdig);
5942           p[1] = xdig[ (num / sizeof(xdig))];
5943           num %= sizeof(xdig);
5944           p[2] = xdig[num];
5945 }
5946 
5947 static void
idr_set_num_beutf16(unsigned char * p,int num)5948 idr_set_num_beutf16(unsigned char *p, int num)
5949 {
5950           static const uint16_t xdig[] = {
5951                     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
5952                     0x0036, 0x0037, 0x0038, 0x0039,
5953                     0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
5954                     0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,
5955                     0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
5956                     0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
5957                     0x0059, 0x005A
5958           };
5959 #define XDIG_CNT    (sizeof(xdig)/sizeof(xdig[0]))
5960 
5961           num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;
5962           archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);
5963           num %= XDIG_CNT * XDIG_CNT;
5964           archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);
5965           num %= XDIG_CNT;
5966           archive_be16enc(p+4, xdig[num]);
5967 }
5968 
5969 /*
5970  * Generate ISO9660 Identifier.
5971  */
5972 static int
isoent_gen_iso9660_identifier(struct archive_write * a,struct isoent * isoent,struct idr * idr)5973 isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
5974     struct idr *idr)
5975 {
5976           struct iso9660 *iso9660;
5977           struct isoent *np;
5978           char *p;
5979           int l, r;
5980           const char *char_map;
5981           char allow_ldots, allow_multidot, allow_period, allow_vernum;
5982           int fnmax, ffmax, dnmax;
5983           static const struct archive_rb_tree_ops rb_ops = {
5984                     isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
5985           };
5986 
5987           if (isoent->children.cnt == 0)
5988                     return (0);
5989 
5990           iso9660 = a->format_data;
5991           char_map = idr->char_map;
5992           if (iso9660->opt.iso_level <= 3) {
5993                     allow_ldots = 0;
5994                     allow_multidot = 0;
5995                     allow_period = 1;
5996                     allow_vernum = iso9660->opt.allow_vernum;
5997                     if (iso9660->opt.iso_level == 1) {
5998                               fnmax = 8;
5999                               ffmax = 12;/* fnmax + '.' + 3 */
6000                               dnmax = 8;
6001                     } else {
6002                               fnmax = 30;
6003                               ffmax = 31;
6004                               dnmax = 31;
6005                     }
6006           } else {
6007                     allow_ldots = allow_multidot = 1;
6008                     allow_period = allow_vernum = 0;
6009                     if (iso9660->opt.rr)
6010                               /*
6011                                * MDR : The maximum size of Directory Record(254).
6012                                * DRL : A Directory Record Length(33).
6013                                * CE  : A size of SUSP CE System Use Entry(28).
6014                                * MDR - DRL - CE = 254 - 33 - 28 = 193.
6015                                */
6016                               fnmax = ffmax = dnmax = 193;
6017                     else
6018                               /*
6019                                * XA  : CD-ROM XA System Use Extension
6020                                *       Information(14).
6021                                * MDR - DRL - XA = 254 - 33 -14 = 207.
6022                                */
6023                               fnmax = ffmax = dnmax = 207;
6024           }
6025 
6026           r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
6027           if (r < 0)
6028                     return (r);
6029 
6030           for (np = isoent->children.first; np != NULL; np = np->chnext) {
6031                     char *dot, *xdot;
6032                     int ext_off, noff, weight;
6033 
6034                     l = (int)np->file->basename.length;
6035                     p = malloc(l+31+2+1);
6036                     if (p == NULL) {
6037                               archive_set_error(&a->archive, ENOMEM,
6038                                   "Can't allocate memory");
6039                               return (ARCHIVE_FATAL);
6040                     }
6041                     memcpy(p, np->file->basename.s, l);
6042                     p[l] = '\0';
6043                     np->identifier = p;
6044 
6045                     dot = xdot = NULL;
6046                     if (!allow_ldots) {
6047                               /*
6048                                * If there is a '.' character at the first byte,
6049                                * it has to be replaced by '_' character.
6050                                */
6051                               if (*p == '.')
6052                                         *p++ = '_';
6053                     }
6054                     for (;*p; p++) {
6055                               if (*p & 0x80) {
6056                                         *p = '_';
6057                                         continue;
6058                               }
6059                               if (char_map[(unsigned char)*p]) {
6060                                         /* if iso-level is '4', a character '.' is
6061                                          * allowed by char_map. */
6062                                         if (*p == '.') {
6063                                                   xdot = dot;
6064                                                   dot = p;
6065                                         }
6066                                         continue;
6067                               }
6068                               if (*p >= 'a' && *p <= 'z') {
6069                                         *p -= 'a' - 'A';
6070                                         continue;
6071                               }
6072                               if (*p == '.') {
6073                                         xdot = dot;
6074                                         dot = p;
6075                                         if (allow_multidot)
6076                                                   continue;
6077                               }
6078                               *p = '_';
6079                     }
6080                     p = np->identifier;
6081                     weight = -1;
6082                     if (dot == NULL) {
6083                               int nammax;
6084 
6085                               if (np->dir)
6086                                         nammax = dnmax;
6087                               else
6088                                         nammax = fnmax;
6089 
6090                               if (l > nammax) {
6091                                         p[nammax] = '\0';
6092                                         weight = nammax;
6093                                         ext_off = nammax;
6094                               } else
6095                                         ext_off = l;
6096                     } else {
6097                               *dot = '.';
6098                               ext_off = (int)(dot - p);
6099 
6100                               if (iso9660->opt.iso_level == 1) {
6101                                         if (dot - p <= 8) {
6102                                                   if (strlen(dot) > 4) {
6103                                                             /* A length of a file extension
6104                                                              * must be less than 4 */
6105                                                             dot[4] = '\0';
6106                                                             weight = 0;
6107                                                   }
6108                                         } else {
6109                                                   p[8] = dot[0];
6110                                                   p[9] = dot[1];
6111                                                   p[10] = dot[2];
6112                                                   p[11] = dot[3];
6113                                                   p[12] = '\0';
6114                                                   weight = 8;
6115                                                   ext_off = 8;
6116                                         }
6117                               } else if (np->dir) {
6118                                         if (l > dnmax) {
6119                                                   p[dnmax] = '\0';
6120                                                   weight = dnmax;
6121                                                   if (ext_off > dnmax)
6122                                                             ext_off = dnmax;
6123                                         }
6124                               } else if (l > ffmax) {
6125                                         int extlen = (int)strlen(dot);
6126                                         int xdoff;
6127 
6128                                         if (xdot != NULL)
6129                                                   xdoff = (int)(xdot - p);
6130                                         else
6131                                                   xdoff = 0;
6132 
6133                                         if (extlen > 1 && xdoff < fnmax-1) {
6134                                                   int off;
6135 
6136                                                   if (extlen > ffmax)
6137                                                             extlen = ffmax;
6138                                                   off = ffmax - extlen;
6139                                                   if (off == 0) {
6140                                                             /* A dot('.')  character
6141                                                              * doesn't place to the first
6142                                                              * byte of identifier. */
6143                                                             off ++;
6144                                                             extlen --;
6145                                                   }
6146                                                   memmove(p+off, dot, extlen);
6147                                                   p[ffmax] = '\0';
6148                                                   ext_off = off;
6149                                                   weight = off;
6150 #ifdef COMPAT_MKISOFS
6151                                         } else if (xdoff >= fnmax-1) {
6152                                                   /* Simulate a bug(?) of mkisofs. */
6153                                                   p[fnmax-1] = '\0';
6154                                                   ext_off = fnmax-1;
6155                                                   weight = fnmax-1;
6156 #endif
6157                                         } else {
6158                                                   p[fnmax] = '\0';
6159                                                   ext_off = fnmax;
6160                                                   weight = fnmax;
6161                                         }
6162                               }
6163                     }
6164                     /* Save an offset of a file name extension to sort files. */
6165                     np->ext_off = ext_off;
6166                     np->ext_len = (int)strlen(&p[ext_off]);
6167                     np->id_len = l = ext_off + np->ext_len;
6168 
6169                     /* Make an offset of the number which is used to be set
6170                      * hexadecimal number to avoid duplicate identifier. */
6171                     if (iso9660->opt.iso_level == 1) {
6172                               if (ext_off >= 5)
6173                                         noff = 5;
6174                               else
6175                                         noff = ext_off;
6176                     } else {
6177                               if (l == ffmax)
6178                                         noff = ext_off - 3;
6179                               else if (l == ffmax-1)
6180                                         noff = ext_off - 2;
6181                               else if (l == ffmax-2)
6182                                         noff = ext_off - 1;
6183                               else
6184                                         noff = ext_off;
6185                     }
6186                     /* Register entry to the identifier resolver. */
6187                     idr_register(idr, np, weight, noff);
6188           }
6189 
6190           /* Resolve duplicate identifier. */
6191           idr_resolve(idr, idr_set_num);
6192 
6193           /* Add a period and a version number to identifiers. */
6194           for (np = isoent->children.first; np != NULL; np = np->chnext) {
6195                     if (!np->dir && np->rr_child == NULL) {
6196                               p = np->identifier + np->ext_off + np->ext_len;
6197                               if (np->ext_len == 0 && allow_period) {
6198                                         *p++ = '.';
6199                                         np->ext_len = 1;
6200                               }
6201                               if (np->ext_len == 1 && !allow_period) {
6202                                         *--p = '\0';
6203                                         np->ext_len = 0;
6204                               }
6205                               np->id_len = np->ext_off + np->ext_len;
6206                               if (allow_vernum) {
6207                                         *p++ = ';';
6208                                         *p++ = '1';
6209                                         np->id_len += 2;
6210                               }
6211                               *p = '\0';
6212                     } else
6213                               np->id_len = np->ext_off + np->ext_len;
6214                     np->mb_len = np->id_len;
6215           }
6216           return (ARCHIVE_OK);
6217 }
6218 
6219 /*
6220  * Generate Joliet Identifier.
6221  */
6222 static int
isoent_gen_joliet_identifier(struct archive_write * a,struct isoent * isoent,struct idr * idr)6223 isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
6224     struct idr *idr)
6225 {
6226           struct iso9660 *iso9660;
6227           struct isoent *np;
6228           unsigned char *p;
6229           size_t l;
6230           int r;
6231           size_t ffmax, parent_len;
6232           static const struct archive_rb_tree_ops rb_ops = {
6233                     isoent_cmp_node_joliet, isoent_cmp_key_joliet
6234           };
6235 
6236           if (isoent->children.cnt == 0)
6237                     return (0);
6238 
6239           iso9660 = a->format_data;
6240           if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
6241                     ffmax = 206;
6242           else
6243                     ffmax = 128;
6244 
6245           r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
6246           if (r < 0)
6247                     return (r);
6248 
6249           parent_len = 1;
6250           for (np = isoent; np->parent != np; np = np->parent)
6251                     parent_len += np->mb_len + 1;
6252 
6253           for (np = isoent->children.first; np != NULL; np = np->chnext) {
6254                     unsigned char *dot;
6255                     int ext_off, noff, weight;
6256                     size_t lt;
6257 
6258                     if ((l = np->file->basename_utf16.length) > ffmax)
6259                               l = ffmax;
6260 
6261                     p = malloc((l+1)*2);
6262                     if (p == NULL) {
6263                               archive_set_error(&a->archive, ENOMEM,
6264                                   "Can't allocate memory");
6265                               return (ARCHIVE_FATAL);
6266                     }
6267                     memcpy(p, np->file->basename_utf16.s, l);
6268                     p[l] = 0;
6269                     p[l+1] = 0;
6270 
6271                     np->identifier = (char *)p;
6272                     lt = l;
6273                     dot = p + l;
6274                     weight = 0;
6275                     while (lt > 0) {
6276                               if (!joliet_allowed_char(p[0], p[1]))
6277                                         archive_be16enc(p, 0x005F); /* '_' */
6278                               else if (p[0] == 0 && p[1] == 0x2E) /* '.' */
6279                                         dot = p;
6280                               p += 2;
6281                               lt -= 2;
6282                     }
6283                     ext_off = (int)(dot - (unsigned char *)np->identifier);
6284                     np->ext_off = ext_off;
6285                     np->ext_len = (int)l - ext_off;
6286                     np->id_len = (int)l;
6287 
6288                     /*
6289                      * Get a length of MBS of a full-pathname.
6290                      */
6291                     if (np->file->basename_utf16.length > ffmax) {
6292                               if (archive_strncpy_l(&iso9660->mbs,
6293                                   (const char *)np->identifier, l,
6294                                         iso9660->sconv_from_utf16be) != 0 &&
6295                                   errno == ENOMEM) {
6296                                         archive_set_error(&a->archive, errno,
6297                                             "No memory");
6298                                         return (ARCHIVE_FATAL);
6299                               }
6300                               np->mb_len = (int)iso9660->mbs.length;
6301                               if (np->mb_len != (int)np->file->basename.length)
6302                                         weight = np->mb_len;
6303                     } else
6304                               np->mb_len = (int)np->file->basename.length;
6305 
6306                     /* If a length of full-pathname is longer than 240 bytes,
6307                      * it violates Joliet extensions regulation. */
6308                     if (parent_len > 240
6309                         || np->mb_len > 240
6310                         || parent_len + np->mb_len > 240) {
6311                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
6312                                   "The regulation of Joliet extensions;"
6313                                   " A length of a full-pathname of `%s' is "
6314                                   "longer than 240 bytes, (p=%d, b=%d)",
6315                                   archive_entry_pathname(np->file->entry),
6316                                   (int)parent_len, (int)np->mb_len);
6317                               return (ARCHIVE_FATAL);
6318                     }
6319 
6320                     /* Make an offset of the number which is used to be set
6321                      * hexadecimal number to avoid duplicate identifier. */
6322                     if (l == ffmax)
6323                               noff = ext_off - 6;
6324                     else if (l == ffmax-2)
6325                               noff = ext_off - 4;
6326                     else if (l == ffmax-4)
6327                               noff = ext_off - 2;
6328                     else
6329                               noff = ext_off;
6330                     /* Register entry to the identifier resolver. */
6331                     idr_register(idr, np, weight, noff);
6332           }
6333 
6334           /* Resolve duplicate identifier with Joliet Volume. */
6335           idr_resolve(idr, idr_set_num_beutf16);
6336 
6337           return (ARCHIVE_OK);
6338 }
6339 
6340 /*
6341  * This comparing rule is according to ISO9660 Standard 9.3
6342  */
6343 static int
isoent_cmp_iso9660_identifier(const struct isoent * p1,const struct isoent * p2)6344 isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
6345 {
6346           const char *s1, *s2;
6347           int cmp;
6348           int l;
6349 
6350           s1 = p1->identifier;
6351           s2 = p2->identifier;
6352 
6353           /* Compare File Name */
6354           l = p1->ext_off;
6355           if (l > p2->ext_off)
6356                     l = p2->ext_off;
6357           cmp = memcmp(s1, s2, l);
6358           if (cmp != 0)
6359                     return (cmp);
6360           if (p1->ext_off < p2->ext_off) {
6361                     s2 += l;
6362                     l = p2->ext_off - p1->ext_off;
6363                     while (l--)
6364                               if (0x20 != *s2++)
6365                                         return (0x20
6366                                             - *(const unsigned char *)(s2 - 1));
6367           } else if (p1->ext_off > p2->ext_off) {
6368                     s1 += l;
6369                     l = p1->ext_off - p2->ext_off;
6370                     while (l--)
6371                               if (0x20 != *s1++)
6372                                         return (*(const unsigned char *)(s1 - 1)
6373                                             - 0x20);
6374           }
6375           /* Compare File Name Extension */
6376           if (p1->ext_len == 0 && p2->ext_len == 0)
6377                     return (0);
6378           if (p1->ext_len == 1 && p2->ext_len == 1)
6379                     return (0);
6380           if (p1->ext_len <= 1)
6381                     return (-1);
6382           if (p2->ext_len <= 1)
6383                     return (1);
6384           l = p1->ext_len;
6385           if (l > p2->ext_len)
6386                     l = p2->ext_len;
6387           s1 = p1->identifier + p1->ext_off;
6388           s2 = p2->identifier + p2->ext_off;
6389           if (l > 1) {
6390                     cmp = memcmp(s1, s2, l);
6391                     if (cmp != 0)
6392                               return (cmp);
6393           }
6394           if (p1->ext_len < p2->ext_len) {
6395                     s2 += l;
6396                     l = p2->ext_len - p1->ext_len;
6397                     while (l--)
6398                               if (0x20 != *s2++)
6399                                         return (0x20
6400                                             - *(const unsigned char *)(s2 - 1));
6401           } else if (p1->ext_len > p2->ext_len) {
6402                     s1 += l;
6403                     l = p1->ext_len - p2->ext_len;
6404                     while (l--)
6405                               if (0x20 != *s1++)
6406                                         return (*(const unsigned char *)(s1 - 1)
6407                                             - 0x20);
6408           }
6409           /* Compare File Version Number */
6410           /* No operation. The File Version Number is always one. */
6411 
6412           return (cmp);
6413 }
6414 
6415 static int
isoent_cmp_node_iso9660(const struct archive_rb_node * n1,const struct archive_rb_node * n2)6416 isoent_cmp_node_iso9660(const struct archive_rb_node *n1,
6417     const struct archive_rb_node *n2)
6418 {
6419           const struct idrent *e1 = (const struct idrent *)n1;
6420           const struct idrent *e2 = (const struct idrent *)n2;
6421 
6422           return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));
6423 }
6424 
6425 static int
isoent_cmp_key_iso9660(const struct archive_rb_node * node,const void * key)6426 isoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)
6427 {
6428           const struct isoent *isoent = (const struct isoent *)key;
6429           const struct idrent *idrent = (const struct idrent *)node;
6430 
6431           return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));
6432 }
6433 
6434 static int
isoent_cmp_joliet_identifier(const struct isoent * p1,const struct isoent * p2)6435 isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
6436 {
6437           const unsigned char *s1, *s2;
6438           int cmp;
6439           int l;
6440 
6441           s1 = (const unsigned char *)p1->identifier;
6442           s2 = (const unsigned char *)p2->identifier;
6443 
6444           /* Compare File Name */
6445           l = p1->ext_off;
6446           if (l > p2->ext_off)
6447                     l = p2->ext_off;
6448           cmp = memcmp(s1, s2, l);
6449           if (cmp != 0)
6450                     return (cmp);
6451           if (p1->ext_off < p2->ext_off) {
6452                     s2 += l;
6453                     l = p2->ext_off - p1->ext_off;
6454                     while (l--)
6455                               if (0 != *s2++)
6456                                         return (- *(const unsigned char *)(s2 - 1));
6457           } else if (p1->ext_off > p2->ext_off) {
6458                     s1 += l;
6459                     l = p1->ext_off - p2->ext_off;
6460                     while (l--)
6461                               if (0 != *s1++)
6462                                         return (*(const unsigned char *)(s1 - 1));
6463           }
6464           /* Compare File Name Extension */
6465           if (p1->ext_len == 0 && p2->ext_len == 0)
6466                     return (0);
6467           if (p1->ext_len == 2 && p2->ext_len == 2)
6468                     return (0);
6469           if (p1->ext_len <= 2)
6470                     return (-1);
6471           if (p2->ext_len <= 2)
6472                     return (1);
6473           l = p1->ext_len;
6474           if (l > p2->ext_len)
6475                     l = p2->ext_len;
6476           s1 = (unsigned char *)(p1->identifier + p1->ext_off);
6477           s2 = (unsigned char *)(p2->identifier + p2->ext_off);
6478           if (l > 1) {
6479                     cmp = memcmp(s1, s2, l);
6480                     if (cmp != 0)
6481                               return (cmp);
6482           }
6483           if (p1->ext_len < p2->ext_len) {
6484                     s2 += l;
6485                     l = p2->ext_len - p1->ext_len;
6486                     while (l--)
6487                               if (0 != *s2++)
6488                                         return (- *(const unsigned char *)(s2 - 1));
6489           } else if (p1->ext_len > p2->ext_len) {
6490                     s1 += l;
6491                     l = p1->ext_len - p2->ext_len;
6492                     while (l--)
6493                               if (0 != *s1++)
6494                                         return (*(const unsigned char *)(s1 - 1));
6495           }
6496           /* Compare File Version Number */
6497           /* No operation. The File Version Number is always one. */
6498 
6499           return (cmp);
6500 }
6501 
6502 static int
isoent_cmp_node_joliet(const struct archive_rb_node * n1,const struct archive_rb_node * n2)6503 isoent_cmp_node_joliet(const struct archive_rb_node *n1,
6504     const struct archive_rb_node *n2)
6505 {
6506           const struct idrent *e1 = (const struct idrent *)n1;
6507           const struct idrent *e2 = (const struct idrent *)n2;
6508 
6509           return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));
6510 }
6511 
6512 static int
isoent_cmp_key_joliet(const struct archive_rb_node * node,const void * key)6513 isoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)
6514 {
6515           const struct isoent *isoent = (const struct isoent *)key;
6516           const struct idrent *idrent = (const struct idrent *)node;
6517 
6518           return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));
6519 }
6520 
6521 static int
isoent_make_sorted_files(struct archive_write * a,struct isoent * isoent,struct idr * idr)6522 isoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,
6523     struct idr *idr)
6524 {
6525           struct archive_rb_node *rn;
6526           struct isoent **children;
6527 
6528           children = malloc(isoent->children.cnt * sizeof(struct isoent *));
6529           if (children == NULL) {
6530                     archive_set_error(&a->archive, ENOMEM,
6531                         "Can't allocate memory");
6532                     return (ARCHIVE_FATAL);
6533           }
6534           isoent->children_sorted = children;
6535 
6536           ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {
6537                     struct idrent *idrent = (struct idrent *)rn;
6538                     *children ++ = idrent->isoent;
6539           }
6540           return (ARCHIVE_OK);
6541 }
6542 
6543 /*
6544  * - Generate ISO9660 and Joliet identifiers from basenames.
6545  * - Sort files by each directory.
6546  */
6547 static int
isoent_traverse_tree(struct archive_write * a,struct vdd * vdd)6548 isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
6549 {
6550           struct iso9660 *iso9660 = a->format_data;
6551           struct isoent *np;
6552           struct idr idr;
6553           int depth;
6554           int r;
6555           int (*genid)(struct archive_write *, struct isoent *, struct idr *);
6556 
6557           idr_init(iso9660, vdd, &idr);
6558           np = vdd->rootent;
6559           depth = 0;
6560           if (vdd->vdd_type == VDD_JOLIET)
6561                     genid = isoent_gen_joliet_identifier;
6562           else
6563                     genid = isoent_gen_iso9660_identifier;
6564           do {
6565                     if (np->virtual &&
6566                         !archive_entry_mtime_is_set(np->file->entry)) {
6567                               /* Set properly times to virtual directory */
6568                               archive_entry_set_mtime(np->file->entry,
6569                                   iso9660->birth_time, 0);
6570                               archive_entry_set_atime(np->file->entry,
6571                                   iso9660->birth_time, 0);
6572                               archive_entry_set_ctime(np->file->entry,
6573                                   iso9660->birth_time, 0);
6574                     }
6575                     if (np->children.first != NULL) {
6576                               if (vdd->vdd_type != VDD_JOLIET &&
6577                                   !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {
6578                                         if (np->children.cnt > 0)
6579                                                   iso9660->directories_too_deep = np;
6580                               } else {
6581                                         /* Generate Identifier */
6582                                         r = genid(a, np, &idr);
6583                                         if (r < 0)
6584                                                   goto exit_traverse_tree;
6585                                         r = isoent_make_sorted_files(a, np, &idr);
6586                                         if (r < 0)
6587                                                   goto exit_traverse_tree;
6588 
6589                                         if (np->subdirs.first != NULL &&
6590                                             depth + 1 < vdd->max_depth) {
6591                                                   /* Enter to sub directories. */
6592                                                   np = np->subdirs.first;
6593                                                   depth++;
6594                                                   continue;
6595                                         }
6596                               }
6597                     }
6598                     while (np != np->parent) {
6599                               if (np->drnext == NULL) {
6600                                         /* Return to the parent directory. */
6601                                         np = np->parent;
6602                                         depth--;
6603                               } else {
6604                                         np = np->drnext;
6605                                         break;
6606                               }
6607                     }
6608           } while (np != np->parent);
6609 
6610           r = ARCHIVE_OK;
6611 exit_traverse_tree:
6612           idr_cleanup(&idr);
6613 
6614           return (r);
6615 }
6616 
6617 /*
6618  * Collect directory entries into path_table by a directory depth.
6619  */
6620 static int
isoent_collect_dirs(struct vdd * vdd,struct isoent * rootent,int depth)6621 isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
6622 {
6623           struct isoent *np;
6624 
6625           if (rootent == NULL)
6626                     rootent = vdd->rootent;
6627           np = rootent;
6628           do {
6629                     /* Register current directory to pathtable. */
6630                     path_table_add_entry(&(vdd->pathtbl[depth]), np);
6631 
6632                     if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
6633                               /* Enter to sub directories. */
6634                               np = np->subdirs.first;
6635                               depth++;
6636                               continue;
6637                     }
6638                     while (np != rootent) {
6639                               if (np->drnext == NULL) {
6640                                         /* Return to the parent directory. */
6641                                         np = np->parent;
6642                                         depth--;
6643                               } else {
6644                                         np = np->drnext;
6645                                         break;
6646                               }
6647                     }
6648           } while (np != rootent);
6649 
6650           return (ARCHIVE_OK);
6651 }
6652 
6653 /*
6654  * The entry whose number of levels in a directory hierarchy is
6655  * large than eight relocate to rr_move directory.
6656  */
6657 static int
isoent_rr_move_dir(struct archive_write * a,struct isoent ** rr_moved,struct isoent * curent,struct isoent ** newent)6658 isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
6659     struct isoent *curent, struct isoent **newent)
6660 {
6661           struct iso9660 *iso9660 = a->format_data;
6662           struct isoent *rrmoved, *mvent, *np;
6663 
6664           if ((rrmoved = *rr_moved) == NULL) {
6665                     struct isoent *rootent = iso9660->primary.rootent;
6666                     /* There isn't rr_move entry.
6667                      * Create rr_move entry and insert it into the root entry.
6668                      */
6669                     rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");
6670                     if (rrmoved == NULL) {
6671                               archive_set_error(&a->archive, ENOMEM,
6672                                   "Can't allocate memory");
6673                               return (ARCHIVE_FATAL);
6674                     }
6675                     /* Add "rr_moved" entry to the root entry. */
6676                     isoent_add_child_head(rootent, rrmoved);
6677                     archive_entry_set_nlink(rootent->file->entry,
6678                         archive_entry_nlink(rootent->file->entry) + 1);
6679                     /* Register "rr_moved" entry to second level pathtable. */
6680                     path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);
6681                     /* Save rr_moved. */
6682                     *rr_moved = rrmoved;
6683           }
6684           /*
6685            * Make a clone of curent which is going to be relocated
6686            * to rr_moved.
6687            */
6688           mvent = isoent_clone(curent);
6689           if (mvent == NULL) {
6690                     archive_set_error(&a->archive, ENOMEM,
6691                         "Can't allocate memory");
6692                     return (ARCHIVE_FATAL);
6693           }
6694           /* linking..  and use for creating "CL", "PL" and "RE" */
6695           mvent->rr_parent = curent->parent;
6696           curent->rr_child = mvent;
6697           /*
6698            * Move subdirectories from the curent to mvent
6699            */
6700           if (curent->children.first != NULL) {
6701                     *mvent->children.last = curent->children.first;
6702                     mvent->children.last = curent->children.last;
6703           }
6704           for (np = mvent->children.first; np != NULL; np = np->chnext)
6705                     np->parent = mvent;
6706           mvent->children.cnt = curent->children.cnt;
6707           curent->children.cnt = 0;
6708           curent->children.first = NULL;
6709           curent->children.last = &curent->children.first;
6710 
6711           if (curent->subdirs.first != NULL) {
6712                     *mvent->subdirs.last = curent->subdirs.first;
6713                     mvent->subdirs.last = curent->subdirs.last;
6714           }
6715           mvent->subdirs.cnt = curent->subdirs.cnt;
6716           curent->subdirs.cnt = 0;
6717           curent->subdirs.first = NULL;
6718           curent->subdirs.last = &curent->subdirs.first;
6719 
6720           /*
6721            * The mvent becomes a child of the rr_moved entry.
6722            */
6723           isoent_add_child_tail(rrmoved, mvent);
6724           archive_entry_set_nlink(rrmoved->file->entry,
6725               archive_entry_nlink(rrmoved->file->entry) + 1);
6726           /*
6727            * This entry which relocated to the rr_moved directory
6728            * has to set the flag as a file.
6729            * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
6730            */
6731           curent->dir = 0;
6732 
6733           *newent = mvent;
6734 
6735           return (ARCHIVE_OK);
6736 }
6737 
6738 static int
isoent_rr_move(struct archive_write * a)6739 isoent_rr_move(struct archive_write *a)
6740 {
6741           struct iso9660 *iso9660 = a->format_data;
6742           struct path_table *pt;
6743           struct isoent *rootent, *rr_moved;
6744           struct isoent *np, *last;
6745           int r;
6746 
6747           pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
6748           /* There aren't level 8 directories reaching a deeper level. */
6749           if (pt->cnt == 0)
6750                     return (ARCHIVE_OK);
6751 
6752           rootent = iso9660->primary.rootent;
6753           /* If "rr_moved" directory is already existing,
6754            * we have to use it. */
6755           rr_moved = isoent_find_child(rootent, "rr_moved");
6756           if (rr_moved != NULL &&
6757               rr_moved != rootent->children.first) {
6758                     /*
6759                      * It's necessary that rr_move is the first entry
6760                      * of the root.
6761                      */
6762                     /* Remove "rr_moved" entry from children chain. */
6763                     isoent_remove_child(rootent, rr_moved);
6764 
6765                     /* Add "rr_moved" entry into the head of children chain. */
6766                     isoent_add_child_head(rootent, rr_moved);
6767           }
6768 
6769           /*
6770            * Check level 8 path_table.
6771            * If find out sub directory entries, that entries move to rr_move.
6772            */
6773           np = pt->first;
6774           while (np != NULL) {
6775                     last = path_table_last_entry(pt);
6776                     for (; np != NULL; np = np->ptnext) {
6777                               struct isoent *mvent;
6778                               struct isoent *newent;
6779 
6780                               if (!np->dir)
6781                                         continue;
6782                               for (mvent = np->subdirs.first;
6783                                   mvent != NULL; mvent = mvent->drnext) {
6784                                         r = isoent_rr_move_dir(a, &rr_moved,
6785                                             mvent, &newent);
6786                                         if (r < 0)
6787                                                   return (r);
6788                                         isoent_collect_dirs(&(iso9660->primary),
6789                                             newent, 2);
6790                               }
6791                     }
6792                     /* If new entries are added to level 8 path_talbe,
6793                      * its sub directory entries move to rr_move too.
6794                      */
6795                     np = last->ptnext;
6796           }
6797 
6798           return (ARCHIVE_OK);
6799 }
6800 
6801 /*
6802  * This comparing rule is according to ISO9660 Standard 6.9.1
6803  */
6804 static int
6805 __LA_LIBC_CC
_compare_path_table(const void * v1,const void * v2)6806 _compare_path_table(const void *v1, const void *v2)
6807 {
6808           const struct isoent *p1, *p2;
6809           const char *s1, *s2;
6810           int cmp, l;
6811 
6812           p1 = *((const struct isoent **)(uintptr_t)v1);
6813           p2 = *((const struct isoent **)(uintptr_t)v2);
6814 
6815           /* Compare parent directory number */
6816           cmp = p1->parent->dir_number - p2->parent->dir_number;
6817           if (cmp != 0)
6818                     return (cmp);
6819 
6820           /* Compare identifier */
6821           s1 = p1->identifier;
6822           s2 = p2->identifier;
6823           l = p1->ext_off;
6824           if (l > p2->ext_off)
6825                     l = p2->ext_off;
6826           cmp = strncmp(s1, s2, l);
6827           if (cmp != 0)
6828                     return (cmp);
6829           if (p1->ext_off < p2->ext_off) {
6830                     s2 += l;
6831                     l = p2->ext_off - p1->ext_off;
6832                     while (l--)
6833                               if (0x20 != *s2++)
6834                                         return (0x20
6835                                             - *(const unsigned char *)(s2 - 1));
6836           } else if (p1->ext_off > p2->ext_off) {
6837                     s1 += l;
6838                     l = p1->ext_off - p2->ext_off;
6839                     while (l--)
6840                               if (0x20 != *s1++)
6841                                         return (*(const unsigned char *)(s1 - 1)
6842                                             - 0x20);
6843           }
6844           return (0);
6845 }
6846 
6847 static int
6848 __LA_LIBC_CC
_compare_path_table_joliet(const void * v1,const void * v2)6849 _compare_path_table_joliet(const void *v1, const void *v2)
6850 {
6851           const struct isoent *p1, *p2;
6852           const unsigned char *s1, *s2;
6853           int cmp, l;
6854 
6855           p1 = *((const struct isoent **)(uintptr_t)v1);
6856           p2 = *((const struct isoent **)(uintptr_t)v2);
6857 
6858           /* Compare parent directory number */
6859           cmp = p1->parent->dir_number - p2->parent->dir_number;
6860           if (cmp != 0)
6861                     return (cmp);
6862 
6863           /* Compare identifier */
6864           s1 = (const unsigned char *)p1->identifier;
6865           s2 = (const unsigned char *)p2->identifier;
6866           l = p1->ext_off;
6867           if (l > p2->ext_off)
6868                     l = p2->ext_off;
6869           cmp = memcmp(s1, s2, l);
6870           if (cmp != 0)
6871                     return (cmp);
6872           if (p1->ext_off < p2->ext_off) {
6873                     s2 += l;
6874                     l = p2->ext_off - p1->ext_off;
6875                     while (l--)
6876                               if (0 != *s2++)
6877                                         return (- *(const unsigned char *)(s2 - 1));
6878           } else if (p1->ext_off > p2->ext_off) {
6879                     s1 += l;
6880                     l = p1->ext_off - p2->ext_off;
6881                     while (l--)
6882                               if (0 != *s1++)
6883                                         return (*(const unsigned char *)(s1 - 1));
6884           }
6885           return (0);
6886 }
6887 
6888 static inline void
path_table_add_entry(struct path_table * pathtbl,struct isoent * ent)6889 path_table_add_entry(struct path_table *pathtbl, struct isoent *ent)
6890 {
6891           ent->ptnext = NULL;
6892           *pathtbl->last = ent;
6893           pathtbl->last = &(ent->ptnext);
6894           pathtbl->cnt ++;
6895 }
6896 
6897 static inline struct isoent *
path_table_last_entry(struct path_table * pathtbl)6898 path_table_last_entry(struct path_table *pathtbl)
6899 {
6900           if (pathtbl->first == NULL)
6901                     return (NULL);
6902           return (((struct isoent *)(void *)
6903                     ((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));
6904 }
6905 
6906 /*
6907  * Sort directory entries in path_table
6908  * and assign directory number to each entries.
6909  */
6910 static int
isoent_make_path_table_2(struct archive_write * a,struct vdd * vdd,int depth,int * dir_number)6911 isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
6912     int depth, int *dir_number)
6913 {
6914           struct isoent *np;
6915           struct isoent **enttbl;
6916           struct path_table *pt;
6917           int i;
6918 
6919           pt = &vdd->pathtbl[depth];
6920           if (pt->cnt == 0) {
6921                     pt->sorted = NULL;
6922                     return (ARCHIVE_OK);
6923           }
6924           enttbl = malloc(pt->cnt * sizeof(struct isoent *));
6925           if (enttbl == NULL) {
6926                     archive_set_error(&a->archive, ENOMEM,
6927                         "Can't allocate memory");
6928                     return (ARCHIVE_FATAL);
6929           }
6930           pt->sorted = enttbl;
6931           for (np = pt->first; np != NULL; np = np->ptnext)
6932                     *enttbl ++ = np;
6933           enttbl = pt->sorted;
6934 
6935           switch (vdd->vdd_type) {
6936           case VDD_PRIMARY:
6937           case VDD_ENHANCED:
6938 #ifdef __COMPAR_FN_T
6939                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6940                         (__compar_fn_t)_compare_path_table);
6941 #else
6942                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6943                         _compare_path_table);
6944 #endif
6945                     break;
6946           case VDD_JOLIET:
6947 #ifdef __COMPAR_FN_T
6948                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6949                         (__compar_fn_t)_compare_path_table_joliet);
6950 #else
6951                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6952                         _compare_path_table_joliet);
6953 #endif
6954                     break;
6955           }
6956           for (i = 0; i < pt->cnt; i++)
6957                     enttbl[i]->dir_number = (*dir_number)++;
6958 
6959           return (ARCHIVE_OK);
6960 }
6961 
6962 static int
isoent_alloc_path_table(struct archive_write * a,struct vdd * vdd,int max_depth)6963 isoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,
6964     int max_depth)
6965 {
6966           int i;
6967 
6968           vdd->max_depth = max_depth;
6969           vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);
6970           if (vdd->pathtbl == NULL) {
6971                     archive_set_error(&a->archive, ENOMEM,
6972                         "Can't allocate memory");
6973                     return (ARCHIVE_FATAL);
6974           }
6975           for (i = 0; i < vdd->max_depth; i++) {
6976                     vdd->pathtbl[i].first = NULL;
6977                     vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);
6978                     vdd->pathtbl[i].sorted = NULL;
6979                     vdd->pathtbl[i].cnt = 0;
6980           }
6981           return (ARCHIVE_OK);
6982 }
6983 
6984 /*
6985  * Make Path Tables
6986  */
6987 static int
isoent_make_path_table(struct archive_write * a)6988 isoent_make_path_table(struct archive_write *a)
6989 {
6990           struct iso9660 *iso9660 = a->format_data;
6991           int depth, r;
6992           int dir_number;
6993 
6994           /*
6995            * Init Path Table.
6996            */
6997           if (iso9660->dircnt_max >= MAX_DEPTH &&
6998               (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))
6999                     r = isoent_alloc_path_table(a, &(iso9660->primary),
7000                         iso9660->dircnt_max + 1);
7001           else
7002                     /* The number of levels in the hierarchy cannot exceed
7003                      * eight. */
7004                     r = isoent_alloc_path_table(a, &(iso9660->primary),
7005                         MAX_DEPTH);
7006           if (r < 0)
7007                     return (r);
7008           if (iso9660->opt.joliet) {
7009                     r = isoent_alloc_path_table(a, &(iso9660->joliet),
7010                         iso9660->dircnt_max + 1);
7011                     if (r < 0)
7012                               return (r);
7013           }
7014 
7015           /* Step 0.
7016            * - Collect directories for primary and joliet.
7017            */
7018           isoent_collect_dirs(&(iso9660->primary), NULL, 0);
7019           if (iso9660->opt.joliet)
7020                     isoent_collect_dirs(&(iso9660->joliet), NULL, 0);
7021           /*
7022            * Rockridge; move deeper depth directories to rr_moved.
7023            */
7024           if (iso9660->opt.rr) {
7025                     r = isoent_rr_move(a);
7026                     if (r < 0)
7027                               return (r);
7028           }
7029 
7030           /* Update nlink. */
7031           isofile_connect_hardlink_files(iso9660);
7032 
7033           /* Step 1.
7034            * - Renew a value of the depth of that directories.
7035            * - Resolve hardlinks.
7036            * - Convert pathnames to ISO9660 name or UCS2(joliet).
7037            * - Sort files by each directory.
7038            */
7039           r = isoent_traverse_tree(a, &(iso9660->primary));
7040           if (r < 0)
7041                     return (r);
7042           if (iso9660->opt.joliet) {
7043                     r = isoent_traverse_tree(a, &(iso9660->joliet));
7044                     if (r < 0)
7045                               return (r);
7046           }
7047 
7048           /* Step 2.
7049            * - Sort directories.
7050            * - Assign all directory number.
7051            */
7052           dir_number = 1;
7053           for (depth = 0; depth < iso9660->primary.max_depth; depth++) {
7054                     r = isoent_make_path_table_2(a, &(iso9660->primary),
7055                         depth, &dir_number);
7056                     if (r < 0)
7057                               return (r);
7058           }
7059           if (iso9660->opt.joliet) {
7060                     dir_number = 1;
7061                     for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {
7062                               r = isoent_make_path_table_2(a, &(iso9660->joliet),
7063                                   depth, &dir_number);
7064                               if (r < 0)
7065                                         return (r);
7066                     }
7067           }
7068           if (iso9660->opt.limit_dirs && dir_number > 0xffff) {
7069                     /*
7070                      * Maximum number of directories is 65535(0xffff)
7071                      * doe to size(16bit) of Parent Directory Number of
7072                      * the Path Table.
7073                      * See also ISO9660 Standard 9.4.
7074                      */
7075                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7076                         "Too many directories(%d) over 65535.", dir_number);
7077                     return (ARCHIVE_FATAL);
7078           }
7079 
7080           /* Get the size of the Path Table. */
7081           calculate_path_table_size(&(iso9660->primary));
7082           if (iso9660->opt.joliet)
7083                     calculate_path_table_size(&(iso9660->joliet));
7084 
7085           return (ARCHIVE_OK);
7086 }
7087 
7088 static int
isoent_find_out_boot_file(struct archive_write * a,struct isoent * rootent)7089 isoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)
7090 {
7091           struct iso9660 *iso9660 = a->format_data;
7092 
7093           /* Find a isoent of the boot file. */
7094           iso9660->el_torito.boot = isoent_find_entry(rootent,
7095               iso9660->el_torito.boot_filename.s);
7096           if (iso9660->el_torito.boot == NULL) {
7097                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7098                         "Can't find the boot image file ``%s''",
7099                         iso9660->el_torito.boot_filename.s);
7100                     return (ARCHIVE_FATAL);
7101           }
7102           iso9660->el_torito.boot->file->boot = BOOT_IMAGE;
7103           return (ARCHIVE_OK);
7104 }
7105 
7106 static int
isoent_create_boot_catalog(struct archive_write * a,struct isoent * rootent)7107 isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
7108 {
7109           struct iso9660 *iso9660 = a->format_data;
7110           struct isofile *file;
7111           struct isoent *isoent;
7112           struct archive_entry *entry;
7113 
7114           (void)rootent; /* UNUSED */
7115           /*
7116            * Create the entry which is the "boot.catalog" file.
7117            */
7118           file = isofile_new(a, NULL);
7119           if (file == NULL) {
7120                     archive_set_error(&a->archive, ENOMEM,
7121                         "Can't allocate memory");
7122                     return (ARCHIVE_FATAL);
7123           }
7124           archive_entry_set_pathname(file->entry,
7125               iso9660->el_torito.catalog_filename.s);
7126           archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);
7127           archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);
7128           archive_entry_set_atime(file->entry, iso9660->birth_time, 0);
7129           archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);
7130           archive_entry_set_uid(file->entry, getuid());
7131           archive_entry_set_gid(file->entry, getgid());
7132           archive_entry_set_mode(file->entry, AE_IFREG | 0444);
7133           archive_entry_set_nlink(file->entry, 1);
7134 
7135           if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
7136                     isofile_free(file);
7137                     return (ARCHIVE_FATAL);
7138           }
7139           file->boot = BOOT_CATALOG;
7140           file->content.size = LOGICAL_BLOCK_SIZE;
7141           isofile_add_entry(iso9660, file);
7142 
7143           isoent = isoent_new(file);
7144           if (isoent == NULL) {
7145                     archive_set_error(&a->archive, ENOMEM,
7146                         "Can't allocate memory");
7147                     return (ARCHIVE_FATAL);
7148           }
7149           isoent->virtual = 1;
7150 
7151           /* Add the "boot.catalog" entry into tree */
7152           if (isoent_tree(a, &isoent) != ARCHIVE_OK)
7153                     return (ARCHIVE_FATAL);
7154 
7155           iso9660->el_torito.catalog = isoent;
7156           /*
7157            * Get a boot media type.
7158            */
7159           switch (iso9660->opt.boot_type) {
7160           default:
7161           case OPT_BOOT_TYPE_AUTO:
7162                     /* Try detecting a media type of the boot image. */
7163                     entry = iso9660->el_torito.boot->file->entry;
7164                     if (archive_entry_size(entry) == FD_1_2M_SIZE)
7165                               iso9660->el_torito.media_type =
7166                                   BOOT_MEDIA_1_2M_DISKETTE;
7167                     else if (archive_entry_size(entry) == FD_1_44M_SIZE)
7168                               iso9660->el_torito.media_type =
7169                                   BOOT_MEDIA_1_44M_DISKETTE;
7170                     else if (archive_entry_size(entry) == FD_2_88M_SIZE)
7171                               iso9660->el_torito.media_type =
7172                                   BOOT_MEDIA_2_88M_DISKETTE;
7173                     else
7174                               /* We cannot decide whether the boot image is
7175                                * hard-disk. */
7176                               iso9660->el_torito.media_type =
7177                                   BOOT_MEDIA_NO_EMULATION;
7178                     break;
7179           case OPT_BOOT_TYPE_NO_EMU:
7180                     iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;
7181                     break;
7182           case OPT_BOOT_TYPE_HARD_DISK:
7183                     iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;
7184                     break;
7185           case OPT_BOOT_TYPE_FD:
7186                     entry = iso9660->el_torito.boot->file->entry;
7187                     if (archive_entry_size(entry) <= FD_1_2M_SIZE)
7188                               iso9660->el_torito.media_type =
7189                                   BOOT_MEDIA_1_2M_DISKETTE;
7190                     else if (archive_entry_size(entry) <= FD_1_44M_SIZE)
7191                               iso9660->el_torito.media_type =
7192                                   BOOT_MEDIA_1_44M_DISKETTE;
7193                     else if (archive_entry_size(entry) <= FD_2_88M_SIZE)
7194                               iso9660->el_torito.media_type =
7195                                   BOOT_MEDIA_2_88M_DISKETTE;
7196                     else {
7197                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7198                                   "Boot image file(``%s'') size is too big "
7199                                   "for fd type.",
7200                                   iso9660->el_torito.boot_filename.s);
7201                               return (ARCHIVE_FATAL);
7202                     }
7203                     break;
7204           }
7205 
7206           /*
7207            * Get a system type.
7208            * TODO: `El Torito' specification says "A copy of byte 5 from the
7209            *       Partition Table found in the boot image".
7210            */
7211           iso9660->el_torito.system_type = 0;
7212 
7213           /*
7214            * Get an ID.
7215            */
7216           if (iso9660->opt.publisher)
7217                     archive_string_copy(&(iso9660->el_torito.id),
7218                         &(iso9660->publisher_identifier));
7219 
7220 
7221           return (ARCHIVE_OK);
7222 }
7223 
7224 /*
7225  * If a media type is floppy, return its image size.
7226  * otherwise return 0.
7227  */
7228 static size_t
fd_boot_image_size(int media_type)7229 fd_boot_image_size(int media_type)
7230 {
7231           switch (media_type) {
7232           case BOOT_MEDIA_1_2M_DISKETTE:
7233                     return (FD_1_2M_SIZE);
7234           case BOOT_MEDIA_1_44M_DISKETTE:
7235                     return (FD_1_44M_SIZE);
7236           case BOOT_MEDIA_2_88M_DISKETTE:
7237                     return (FD_2_88M_SIZE);
7238           default:
7239                     return (0);
7240           }
7241 }
7242 
7243 /*
7244  * Make a boot catalog image data.
7245  */
7246 static int
make_boot_catalog(struct archive_write * a)7247 make_boot_catalog(struct archive_write *a)
7248 {
7249           struct iso9660 *iso9660 = a->format_data;
7250           unsigned char *block;
7251           unsigned char *p;
7252           uint16_t sum, *wp;
7253 
7254           block = wb_buffptr(a);
7255           memset(block, 0, LOGICAL_BLOCK_SIZE);
7256           p = block;
7257           /*
7258            * Validation Entry
7259            */
7260           /* Header ID */
7261           p[0] = 1;
7262           /* Platform ID */
7263           p[1] = iso9660->el_torito.platform_id;
7264           /* Reserved */
7265           p[2] = p[3] = 0;
7266           /* ID */
7267           if (archive_strlen(&(iso9660->el_torito.id)) > 0)
7268                     strncpy((char *)p+4, iso9660->el_torito.id.s, 23);
7269           p[27] = 0;
7270           /* Checksum */
7271           p[28] = p[29] = 0;
7272           /* Key */
7273           p[30] = 0x55;
7274           p[31] = 0xAA;
7275 
7276           sum = 0;
7277           wp = (uint16_t *)block;
7278           while (wp < (uint16_t *)&block[32])
7279                     sum += archive_le16dec(wp++);
7280           set_num_721(&block[28], (~sum) + 1);
7281 
7282           /*
7283            * Initial/Default Entry
7284            */
7285           p = &block[32];
7286           /* Boot Indicator */
7287           p[0] = 0x88;
7288           /* Boot media type */
7289           p[1] = iso9660->el_torito.media_type;
7290           /* Load Segment */
7291           if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
7292                     set_num_721(&p[2], iso9660->el_torito.boot_load_seg);
7293           else
7294                     set_num_721(&p[2], 0);
7295           /* System Type */
7296           p[4] = iso9660->el_torito.system_type;
7297           /* Unused */
7298           p[5] = 0;
7299           /* Sector Count */
7300           if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
7301                     set_num_721(&p[6], iso9660->el_torito.boot_load_size);
7302           else
7303                     set_num_721(&p[6], 1);
7304           /* Load RBA */
7305           set_num_731(&p[8],
7306               iso9660->el_torito.boot->file->content.location);
7307           /* Unused */
7308           memset(&p[12], 0, 20);
7309 
7310           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
7311 }
7312 
7313 static int
setup_boot_information(struct archive_write * a)7314 setup_boot_information(struct archive_write *a)
7315 {
7316           struct iso9660 *iso9660 = a->format_data;
7317           struct isoent *np;
7318           int64_t size;
7319           uint32_t sum;
7320           unsigned char buff[4096];
7321 
7322           np = iso9660->el_torito.boot;
7323           lseek(iso9660->temp_fd,
7324               np->file->content.offset_of_temp + 64, SEEK_SET);
7325           size = archive_entry_size(np->file->entry) - 64;
7326           if (size <= 0) {
7327                     archive_set_error(&a->archive, errno,
7328                         "Boot file(%jd) is too small", (intmax_t)size + 64);
7329                     return (ARCHIVE_FATAL);
7330           }
7331           sum = 0;
7332           while (size > 0) {
7333                     size_t rsize;
7334                     ssize_t i, rs;
7335 
7336                     if (size > (int64_t)sizeof(buff))
7337                               rsize = sizeof(buff);
7338                     else
7339                               rsize = (size_t)size;
7340 
7341                     rs = read(iso9660->temp_fd, buff, rsize);
7342                     if (rs <= 0) {
7343                               archive_set_error(&a->archive, errno,
7344                                   "Can't read temporary file(%jd)",
7345                                   (intmax_t)rs);
7346                               return (ARCHIVE_FATAL);
7347                     }
7348                     for (i = 0; i < rs; i += 4)
7349                               sum += archive_le32dec(buff + i);
7350                     size -= rs;
7351           }
7352           /* Set the location of Primary Volume Descriptor. */
7353           set_num_731(buff, SYSTEM_AREA_BLOCK);
7354           /* Set the location of the boot file. */
7355           set_num_731(buff+4, np->file->content.location);
7356           /* Set the size of the boot file. */
7357           size = fd_boot_image_size(iso9660->el_torito.media_type);
7358           if (size == 0)
7359                     size = archive_entry_size(np->file->entry);
7360           set_num_731(buff+8, (uint32_t)size);
7361           /* Set the sum of the boot file. */
7362           set_num_731(buff+12, sum);
7363           /* Clear reserved bytes. */
7364           memset(buff+16, 0, 40);
7365 
7366           /* Overwrite the boot file. */
7367           lseek(iso9660->temp_fd,
7368               np->file->content.offset_of_temp + 8, SEEK_SET);
7369           return (write_to_temp(a, buff, 56));
7370 }
7371 
7372 #ifdef HAVE_ZLIB_H
7373 
7374 static int
zisofs_init_zstream(struct archive_write * a)7375 zisofs_init_zstream(struct archive_write *a)
7376 {
7377           struct iso9660 *iso9660 = a->format_data;
7378           int r;
7379 
7380           iso9660->zisofs.stream.next_in = NULL;
7381           iso9660->zisofs.stream.avail_in = 0;
7382           iso9660->zisofs.stream.total_in = 0;
7383           iso9660->zisofs.stream.total_out = 0;
7384           if (iso9660->zisofs.stream_valid)
7385                     r = deflateReset(&(iso9660->zisofs.stream));
7386           else {
7387                     r = deflateInit(&(iso9660->zisofs.stream),
7388                         iso9660->zisofs.compression_level);
7389                     iso9660->zisofs.stream_valid = 1;
7390           }
7391           switch (r) {
7392           case Z_OK:
7393                     break;
7394           default:
7395           case Z_STREAM_ERROR:
7396                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7397                         "Internal error initializing "
7398                         "compression library: invalid setup parameter");
7399                     return (ARCHIVE_FATAL);
7400           case Z_MEM_ERROR:
7401                     archive_set_error(&a->archive, ENOMEM,
7402                         "Internal error initializing "
7403                         "compression library");
7404                     return (ARCHIVE_FATAL);
7405           case Z_VERSION_ERROR:
7406                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7407                         "Internal error initializing "
7408                         "compression library: invalid library version");
7409                     return (ARCHIVE_FATAL);
7410           }
7411           return (ARCHIVE_OK);
7412 }
7413 
7414 #endif /* HAVE_ZLIB_H */
7415 
7416 static int
zisofs_init(struct archive_write * a,struct isofile * file)7417 zisofs_init(struct archive_write *a,  struct isofile *file)
7418 {
7419           struct iso9660 *iso9660 = a->format_data;
7420 #ifdef HAVE_ZLIB_H
7421           uint64_t tsize;
7422           size_t _ceil, bpsize;
7423           int r;
7424 #endif
7425 
7426           iso9660->zisofs.detect_magic = 0;
7427           iso9660->zisofs.making = 0;
7428 
7429           if (!iso9660->opt.rr || !iso9660->opt.zisofs)
7430                     return (ARCHIVE_OK);
7431 
7432           if (archive_entry_size(file->entry) >= 24 &&
7433               archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {
7434                     /* Acceptable file size for zisofs. */
7435                     iso9660->zisofs.detect_magic = 1;
7436                     iso9660->zisofs.magic_cnt = 0;
7437           }
7438           if (!iso9660->zisofs.detect_magic)
7439                     return (ARCHIVE_OK);
7440 
7441 #ifdef HAVE_ZLIB_H
7442           /* The number of Logical Blocks which uncompressed data
7443            * will use in iso-image file is the same as the number of
7444            * Logical Blocks which zisofs(compressed) data will use
7445            * in ISO-image file. It won't reduce iso-image file size. */
7446           if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)
7447                     return (ARCHIVE_OK);
7448 
7449           /* Initialize compression library */
7450           r = zisofs_init_zstream(a);
7451           if (r != ARCHIVE_OK)
7452                     return (ARCHIVE_FATAL);
7453 
7454           /* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
7455           file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
7456           file->zisofs.log2_bs = ZF_LOG2_BS;
7457           file->zisofs.uncompressed_size =
7458                     (uint32_t)archive_entry_size(file->entry);
7459 
7460           /* Calculate a size of Block Pointers of zisofs. */
7461           _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
7462                     >> file->zisofs.log2_bs;
7463           iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
7464           iso9660->zisofs.block_pointers_idx = 0;
7465 
7466           /* Ensure a buffer size used for Block Pointers */
7467           bpsize = iso9660->zisofs.block_pointers_cnt *
7468               sizeof(iso9660->zisofs.block_pointers[0]);
7469           if (iso9660->zisofs.block_pointers_allocated < bpsize) {
7470                     free(iso9660->zisofs.block_pointers);
7471                     iso9660->zisofs.block_pointers = malloc(bpsize);
7472                     if (iso9660->zisofs.block_pointers == NULL) {
7473                               archive_set_error(&a->archive, ENOMEM,
7474                                   "Can't allocate data");
7475                               return (ARCHIVE_FATAL);
7476                     }
7477                     iso9660->zisofs.block_pointers_allocated = bpsize;
7478           }
7479 
7480           /*
7481            * Skip zisofs header and Block Pointers, which we will write
7482            * after all compressed data of a file written to the temporary
7483            * file.
7484            */
7485           tsize = ZF_HEADER_SIZE + bpsize;
7486           if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
7487                     return (ARCHIVE_FATAL);
7488 
7489           /*
7490            * Initialize some variables to make zisofs.
7491            */
7492           archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
7493                     (uint32_t)tsize);
7494           iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
7495           iso9660->zisofs.making = 1;
7496           iso9660->zisofs.allzero = 1;
7497           iso9660->zisofs.block_offset = tsize;
7498           iso9660->zisofs.total_size = tsize;
7499           iso9660->cur_file->cur_content->size = tsize;
7500 #endif
7501 
7502           return (ARCHIVE_OK);
7503 }
7504 
7505 static void
zisofs_detect_magic(struct archive_write * a,const void * buff,size_t s)7506 zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
7507 {
7508           struct iso9660 *iso9660 = a->format_data;
7509           struct isofile *file = iso9660->cur_file;
7510           const unsigned char *p, *endp;
7511           const unsigned char *magic_buff;
7512           uint32_t uncompressed_size;
7513           unsigned char header_size;
7514           unsigned char log2_bs;
7515           size_t _ceil, doff;
7516           uint32_t bst, bed;
7517           int magic_max;
7518           int64_t entry_size;
7519 
7520           entry_size = archive_entry_size(file->entry);
7521           if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
7522                     magic_max = (int)entry_size;
7523           else
7524                     magic_max = sizeof(iso9660->zisofs.magic_buffer);
7525 
7526           if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)
7527                     /* It's unnecessary we copy buffer. */
7528                     magic_buff = buff;
7529           else {
7530                     if (iso9660->zisofs.magic_cnt < magic_max) {
7531                               size_t l;
7532 
7533                               l = sizeof(iso9660->zisofs.magic_buffer)
7534                                   - iso9660->zisofs.magic_cnt;
7535                               if (l > s)
7536                                         l = s;
7537                               memcpy(iso9660->zisofs.magic_buffer
7538                                   + iso9660->zisofs.magic_cnt, buff, l);
7539                               iso9660->zisofs.magic_cnt += (int)l;
7540                               if (iso9660->zisofs.magic_cnt < magic_max)
7541                                         return;
7542                     }
7543                     magic_buff = iso9660->zisofs.magic_buffer;
7544           }
7545           iso9660->zisofs.detect_magic = 0;
7546           p = magic_buff;
7547 
7548           /* Check the magic code of zisofs. */
7549           if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
7550                     /* This is not zisofs file which made by mkzftree. */
7551                     return;
7552           p += sizeof(zisofs_magic);
7553 
7554           /* Read a zisofs header. */
7555           uncompressed_size = archive_le32dec(p);
7556           header_size = p[4];
7557           log2_bs = p[5];
7558           if (uncompressed_size < 24 || header_size != 4 ||
7559               log2_bs > 30 || log2_bs < 7)
7560                     return;/* Invalid or not supported header. */
7561 
7562           /* Calculate a size of Block Pointers of zisofs. */
7563           _ceil = (uncompressed_size +
7564                   (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
7565           doff = (_ceil + 1) * 4 + 16;
7566           if (entry_size < (int64_t)doff)
7567                     return;/* Invalid data. */
7568 
7569           /* Check every Block Pointer has valid value. */
7570           p = magic_buff + 16;
7571           endp = magic_buff + magic_max;
7572           while (_ceil && p + 8 <= endp) {
7573                     bst = archive_le32dec(p);
7574                     if (bst != doff)
7575                               return;/* Invalid data. */
7576                     p += 4;
7577                     bed = archive_le32dec(p);
7578                     if (bed < bst || bed > entry_size)
7579                               return;/* Invalid data. */
7580                     doff += bed - bst;
7581                     _ceil--;
7582           }
7583 
7584           file->zisofs.uncompressed_size = uncompressed_size;
7585           file->zisofs.header_size = header_size;
7586           file->zisofs.log2_bs = log2_bs;
7587 
7588           /* Disable making a zisofs image. */
7589           iso9660->zisofs.making = 0;
7590 }
7591 
7592 #ifdef HAVE_ZLIB_H
7593 
7594 /*
7595  * Compress data and write it to a temporary file.
7596  */
7597 static int
zisofs_write_to_temp(struct archive_write * a,const void * buff,size_t s)7598 zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
7599 {
7600           struct iso9660 *iso9660 = a->format_data;
7601           struct isofile *file = iso9660->cur_file;
7602           const unsigned char *b;
7603           z_stream *zstrm;
7604           size_t avail, csize;
7605           int flush, r;
7606 
7607           zstrm = &(iso9660->zisofs.stream);
7608           zstrm->next_out = wb_buffptr(a);
7609           zstrm->avail_out = (uInt)wb_remaining(a);
7610           b = (const unsigned char *)buff;
7611           do {
7612                     avail = ZF_BLOCK_SIZE - zstrm->total_in;
7613                     if (s < avail) {
7614                               avail = s;
7615                               flush = Z_NO_FLUSH;
7616                     } else
7617                               flush = Z_FINISH;
7618                     iso9660->zisofs.remaining -= avail;
7619                     if (iso9660->zisofs.remaining <= 0)
7620                               flush = Z_FINISH;
7621 
7622                     zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
7623                     zstrm->avail_in = (uInt)avail;
7624 
7625                     /*
7626                      * Check if current data block are all zero.
7627                      */
7628                     if (iso9660->zisofs.allzero) {
7629                               const unsigned char *nonzero = b;
7630                               const unsigned char *nonzeroend = b + avail;
7631 
7632                               while (nonzero < nonzeroend)
7633                                         if (*nonzero++) {
7634                                                   iso9660->zisofs.allzero = 0;
7635                                                   break;
7636                                         }
7637                     }
7638                     b += avail;
7639                     s -= avail;
7640 
7641                     /*
7642                      * If current data block are all zero, we do not use
7643                      * compressed data.
7644                      */
7645                     if (flush == Z_FINISH && iso9660->zisofs.allzero &&
7646                         avail + zstrm->total_in == ZF_BLOCK_SIZE) {
7647                               if (iso9660->zisofs.block_offset !=
7648                                   file->cur_content->size) {
7649                                         int64_t diff;
7650 
7651                                         r = wb_set_offset(a,
7652                                             file->cur_content->offset_of_temp +
7653                                                 iso9660->zisofs.block_offset);
7654                                         if (r != ARCHIVE_OK)
7655                                                   return (r);
7656                                         diff = file->cur_content->size -
7657                                             iso9660->zisofs.block_offset;
7658                                         file->cur_content->size -= diff;
7659                                         iso9660->zisofs.total_size -= diff;
7660                               }
7661                               zstrm->avail_in = 0;
7662                     }
7663 
7664                     /*
7665                      * Compress file data.
7666                      */
7667                     while (zstrm->avail_in > 0) {
7668                               csize = zstrm->total_out;
7669                               r = deflate(zstrm, flush);
7670                               switch (r) {
7671                               case Z_OK:
7672                               case Z_STREAM_END:
7673                                         csize = zstrm->total_out - csize;
7674                                         if (wb_consume(a, csize) != ARCHIVE_OK)
7675                                                   return (ARCHIVE_FATAL);
7676                                         iso9660->zisofs.total_size += csize;
7677                                         iso9660->cur_file->cur_content->size += csize;
7678                                         zstrm->next_out = wb_buffptr(a);
7679                                         zstrm->avail_out = (uInt)wb_remaining(a);
7680                                         break;
7681                               default:
7682                                         archive_set_error(&a->archive,
7683                                             ARCHIVE_ERRNO_MISC,
7684                                             "Compression failed:"
7685                                             " deflate() call returned status %d",
7686                                             r);
7687                                         return (ARCHIVE_FATAL);
7688                               }
7689                     }
7690 
7691                     if (flush == Z_FINISH) {
7692                               /*
7693                                * Save the information of one zisofs block.
7694                                */
7695                               iso9660->zisofs.block_pointers_idx ++;
7696                               archive_le32enc(&(iso9660->zisofs.block_pointers[
7697                                   iso9660->zisofs.block_pointers_idx]),
7698                                         (uint32_t)iso9660->zisofs.total_size);
7699                               r = zisofs_init_zstream(a);
7700                               if (r != ARCHIVE_OK)
7701                                         return (ARCHIVE_FATAL);
7702                               iso9660->zisofs.allzero = 1;
7703                               iso9660->zisofs.block_offset = file->cur_content->size;
7704                     }
7705           } while (s);
7706 
7707           return (ARCHIVE_OK);
7708 }
7709 
7710 static int
zisofs_finish_entry(struct archive_write * a)7711 zisofs_finish_entry(struct archive_write *a)
7712 {
7713           struct iso9660 *iso9660 = a->format_data;
7714           struct isofile *file = iso9660->cur_file;
7715           unsigned char buff[16];
7716           size_t s;
7717           int64_t tail;
7718 
7719           /* Direct temp file stream to zisofs temp file stream. */
7720           archive_entry_set_size(file->entry, iso9660->zisofs.total_size);
7721 
7722           /*
7723            * Save a file pointer which points the end of current zisofs data.
7724            */
7725           tail = wb_offset(a);
7726 
7727           /*
7728            * Make a header.
7729            *
7730            * +-----------------+----------------+-----------------+
7731            * | Header 16 bytes | Block Pointers | Compressed data |
7732            * +-----------------+----------------+-----------------+
7733            * 0                16               +X
7734            * Block Pointers :
7735            *   4 * (((Uncompressed file size + block_size -1) / block_size) + 1)
7736            *
7737            * Write zisofs header.
7738            *    Magic number
7739            * +----+----+----+----+----+----+----+----+
7740            * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |
7741            * +----+----+----+----+----+----+----+----+
7742            * 0    1    2    3    4    5    6    7    8
7743            *
7744            * +------------------------+------------------+
7745            * | Uncompressed file size | header_size >> 2 |
7746            * +------------------------+------------------+
7747            * 8                       12                 13
7748            *
7749            * +-----------------+----------------+
7750            * | log2 block_size | Reserved(0000) |
7751            * +-----------------+----------------+
7752            * 13               14               16
7753            */
7754           memcpy(buff, zisofs_magic, 8);
7755           set_num_731(buff+8, file->zisofs.uncompressed_size);
7756           buff[12] = file->zisofs.header_size;
7757           buff[13] = file->zisofs.log2_bs;
7758           buff[14] = buff[15] = 0;/* Reserved */
7759 
7760           /* Move to the right position to write the header. */
7761           wb_set_offset(a, file->content.offset_of_temp);
7762 
7763           /* Write the header. */
7764           if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)
7765                     return (ARCHIVE_FATAL);
7766 
7767           /*
7768            * Write zisofs Block Pointers.
7769            */
7770           s = iso9660->zisofs.block_pointers_cnt *
7771               sizeof(iso9660->zisofs.block_pointers[0]);
7772           if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)
7773               != ARCHIVE_OK)
7774                     return (ARCHIVE_FATAL);
7775 
7776           /* Set a file pointer back to the end of the temporary file. */
7777           wb_set_offset(a, tail);
7778 
7779           return (ARCHIVE_OK);
7780 }
7781 
7782 static int
zisofs_free(struct archive_write * a)7783 zisofs_free(struct archive_write *a)
7784 {
7785           struct iso9660 *iso9660 = a->format_data;
7786           int ret = ARCHIVE_OK;
7787 
7788           free(iso9660->zisofs.block_pointers);
7789           if (iso9660->zisofs.stream_valid &&
7790               deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {
7791                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7792                         "Failed to clean up compressor");
7793                     ret = ARCHIVE_FATAL;
7794           }
7795           iso9660->zisofs.block_pointers = NULL;
7796           iso9660->zisofs.stream_valid = 0;
7797           return (ret);
7798 }
7799 
7800 struct zisofs_extract {
7801           int                  pz_log2_bs; /* Log2 of block size */
7802           uint64_t   pz_uncompressed_size;
7803           size_t               uncompressed_buffer_size;
7804 
7805           signed int           initialized:1;
7806           signed int           header_passed:1;
7807 
7808           uint32_t   pz_offset;
7809           unsigned char       *block_pointers;
7810           size_t               block_pointers_size;
7811           size_t               block_pointers_avail;
7812           size_t               block_off;
7813           uint32_t   block_avail;
7814 
7815           z_stream   stream;
7816           int                  stream_valid;
7817 };
7818 
7819 static ssize_t
zisofs_extract_init(struct archive_write * a,struct zisofs_extract * zisofs,const unsigned char * p,size_t bytes)7820 zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
7821     const unsigned char *p, size_t bytes)
7822 {
7823           size_t avail = bytes;
7824           size_t _ceil, xsize;
7825 
7826           /* Allocate block pointers buffer. */
7827           _ceil = (size_t)((zisofs->pz_uncompressed_size +
7828                     (((int64_t)1) << zisofs->pz_log2_bs) - 1)
7829                     >> zisofs->pz_log2_bs);
7830           xsize = (_ceil + 1) * 4;
7831           if (zisofs->block_pointers == NULL) {
7832                     size_t alloc = ((xsize >> 10) + 1) << 10;
7833                     zisofs->block_pointers = malloc(alloc);
7834                     if (zisofs->block_pointers == NULL) {
7835                               archive_set_error(&a->archive, ENOMEM,
7836                                   "No memory for zisofs decompression");
7837                               return (ARCHIVE_FATAL);
7838                     }
7839           }
7840           zisofs->block_pointers_size = xsize;
7841 
7842           /* Allocate uncompressed data buffer. */
7843           zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
7844 
7845           /*
7846            * Read the file header, and check the magic code of zisofs.
7847            */
7848           if (!zisofs->header_passed) {
7849                     int err = 0;
7850                     if (avail < 16) {
7851                               archive_set_error(&a->archive,
7852                                   ARCHIVE_ERRNO_FILE_FORMAT,
7853                                   "Illegal zisofs file body");
7854                               return (ARCHIVE_FATAL);
7855                     }
7856 
7857                     if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
7858                               err = 1;
7859                     else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)
7860                               err = 1;
7861                     else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)
7862                               err = 1;
7863                     if (err) {
7864                               archive_set_error(&a->archive,
7865                                   ARCHIVE_ERRNO_FILE_FORMAT,
7866                                   "Illegal zisofs file body");
7867                               return (ARCHIVE_FATAL);
7868                     }
7869                     avail -= 16;
7870                     p += 16;
7871                     zisofs->header_passed = 1;
7872           }
7873 
7874           /*
7875            * Read block pointers.
7876            */
7877           if (zisofs->header_passed &&
7878               zisofs->block_pointers_avail < zisofs->block_pointers_size) {
7879                     xsize = zisofs->block_pointers_size
7880                         - zisofs->block_pointers_avail;
7881                     if (avail < xsize)
7882                               xsize = avail;
7883                     memcpy(zisofs->block_pointers
7884                         + zisofs->block_pointers_avail, p, xsize);
7885                     zisofs->block_pointers_avail += xsize;
7886                     avail -= xsize;
7887                     if (zisofs->block_pointers_avail
7888                         == zisofs->block_pointers_size) {
7889                               /* We've got all block pointers and initialize
7890                                * related variables.         */
7891                               zisofs->block_off = 0;
7892                               zisofs->block_avail = 0;
7893                               /* Complete a initialization */
7894                               zisofs->initialized = 1;
7895                     }
7896           }
7897           return ((ssize_t)avail);
7898 }
7899 
7900 static ssize_t
zisofs_extract(struct archive_write * a,struct zisofs_extract * zisofs,const unsigned char * p,size_t bytes)7901 zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
7902     const unsigned char *p, size_t bytes)
7903 {
7904           size_t avail;
7905           int r;
7906 
7907           if (!zisofs->initialized) {
7908                     ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);
7909                     if (rs < 0)
7910                               return (rs);
7911                     if (!zisofs->initialized) {
7912                               /* We need more data. */
7913                               zisofs->pz_offset += (uint32_t)bytes;
7914                               return (bytes);
7915                     }
7916                     avail = rs;
7917                     p += bytes - avail;
7918           } else
7919                     avail = bytes;
7920 
7921           /*
7922            * Get block offsets from block pointers.
7923            */
7924           if (zisofs->block_avail == 0) {
7925                     uint32_t bst, bed;
7926 
7927                     if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
7928                               /* There isn't a pair of offsets. */
7929                               archive_set_error(&a->archive,
7930                                   ARCHIVE_ERRNO_FILE_FORMAT,
7931                                   "Illegal zisofs block pointers");
7932                               return (ARCHIVE_FATAL);
7933                     }
7934                     bst = archive_le32dec(
7935                         zisofs->block_pointers + zisofs->block_off);
7936                     if (bst != zisofs->pz_offset + (bytes - avail)) {
7937                               archive_set_error(&a->archive,
7938                                   ARCHIVE_ERRNO_FILE_FORMAT,
7939                                   "Illegal zisofs block pointers(cannot seek)");
7940                               return (ARCHIVE_FATAL);
7941                     }
7942                     bed = archive_le32dec(
7943                         zisofs->block_pointers + zisofs->block_off + 4);
7944                     if (bed < bst) {
7945                               archive_set_error(&a->archive,
7946                                   ARCHIVE_ERRNO_FILE_FORMAT,
7947                                   "Illegal zisofs block pointers");
7948                               return (ARCHIVE_FATAL);
7949                     }
7950                     zisofs->block_avail = bed - bst;
7951                     zisofs->block_off += 4;
7952 
7953                     /* Initialize compression library for new block. */
7954                     if (zisofs->stream_valid)
7955                               r = inflateReset(&zisofs->stream);
7956                     else
7957                               r = inflateInit(&zisofs->stream);
7958                     if (r != Z_OK) {
7959                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7960                                   "Can't initialize zisofs decompression.");
7961                               return (ARCHIVE_FATAL);
7962                     }
7963                     zisofs->stream_valid = 1;
7964                     zisofs->stream.total_in = 0;
7965                     zisofs->stream.total_out = 0;
7966           }
7967 
7968           /*
7969            * Make uncompressed data.
7970            */
7971           if (zisofs->block_avail == 0) {
7972                     /*
7973                      * It's basically 32K bytes NUL data.
7974                      */
7975                     unsigned char *wb;
7976                     size_t size, wsize;
7977 
7978                     size = zisofs->uncompressed_buffer_size;
7979                     while (size) {
7980                               wb = wb_buffptr(a);
7981                               if (size > wb_remaining(a))
7982                                         wsize = wb_remaining(a);
7983                               else
7984                                         wsize = size;
7985                               memset(wb, 0, wsize);
7986                               r = wb_consume(a, wsize);
7987                               if (r < 0)
7988                                         return (r);
7989                               size -= wsize;
7990                     }
7991           } else {
7992                     zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
7993                     if (avail > zisofs->block_avail)
7994                               zisofs->stream.avail_in = zisofs->block_avail;
7995                     else
7996                               zisofs->stream.avail_in = (uInt)avail;
7997                     zisofs->stream.next_out = wb_buffptr(a);
7998                     zisofs->stream.avail_out = (uInt)wb_remaining(a);
7999 
8000                     r = inflate(&zisofs->stream, 0);
8001                     switch (r) {
8002                     case Z_OK: /* Decompressor made some progress.*/
8003                     case Z_STREAM_END: /* Found end of stream. */
8004                               break;
8005                     default:
8006                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8007                                   "zisofs decompression failed (%d)", r);
8008                               return (ARCHIVE_FATAL);
8009                     }
8010                     avail -= zisofs->stream.next_in - p;
8011                     zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
8012                     r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
8013                     if (r < 0)
8014                               return (r);
8015           }
8016           zisofs->pz_offset += (uint32_t)bytes;
8017           return (bytes - avail);
8018 }
8019 
8020 static int
zisofs_rewind_boot_file(struct archive_write * a)8021 zisofs_rewind_boot_file(struct archive_write *a)
8022 {
8023           struct iso9660 *iso9660 = a->format_data;
8024           struct isofile *file;
8025           unsigned char *rbuff;
8026           ssize_t r;
8027           size_t remaining, rbuff_size;
8028           struct zisofs_extract zext;
8029           int64_t read_offset, write_offset, new_offset;
8030           int fd, ret = ARCHIVE_OK;
8031 
8032           file = iso9660->el_torito.boot->file;
8033           /*
8034            * There is nothing to do if this boot file does not have
8035            * zisofs header.
8036            */
8037           if (file->zisofs.header_size == 0)
8038                     return (ARCHIVE_OK);
8039 
8040           /*
8041            * Uncompress the zisofs'ed file contents.
8042            */
8043           memset(&zext, 0, sizeof(zext));
8044           zext.pz_uncompressed_size = file->zisofs.uncompressed_size;
8045           zext.pz_log2_bs = file->zisofs.log2_bs;
8046 
8047           fd = iso9660->temp_fd;
8048           new_offset = wb_offset(a);
8049           read_offset = file->content.offset_of_temp;
8050           remaining = (size_t)file->content.size;
8051           if (remaining > 1024 * 32)
8052                     rbuff_size = 1024 * 32;
8053           else
8054                     rbuff_size = remaining;
8055 
8056           rbuff = malloc(rbuff_size);
8057           if (rbuff == NULL) {
8058                     archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
8059                     return (ARCHIVE_FATAL);
8060           }
8061           while (remaining) {
8062                     size_t rsize;
8063                     ssize_t rs;
8064 
8065                     /* Get the current file pointer. */
8066                     write_offset = lseek(fd, 0, SEEK_CUR);
8067 
8068                     /* Change the file pointer to read. */
8069                     lseek(fd, read_offset, SEEK_SET);
8070 
8071                     rsize = rbuff_size;
8072                     if (rsize > remaining)
8073                               rsize = remaining;
8074                     rs = read(iso9660->temp_fd, rbuff, rsize);
8075                     if (rs <= 0) {
8076                               archive_set_error(&a->archive, errno,
8077                                   "Can't read temporary file(%jd)", (intmax_t)rs);
8078                               ret = ARCHIVE_FATAL;
8079                               break;
8080                     }
8081                     remaining -= rs;
8082                     read_offset += rs;
8083 
8084                     /* Put the file pointer back to write. */
8085                     lseek(fd, write_offset, SEEK_SET);
8086 
8087                     r = zisofs_extract(a, &zext, rbuff, rs);
8088                     if (r < 0) {
8089                               ret = (int)r;
8090                               break;
8091                     }
8092           }
8093 
8094           if (ret == ARCHIVE_OK) {
8095                     /*
8096                      * Change the boot file content from zisofs'ed data
8097                      * to plain data.
8098                      */
8099                     file->content.offset_of_temp = new_offset;
8100                     file->content.size = file->zisofs.uncompressed_size;
8101                     archive_entry_set_size(file->entry, file->content.size);
8102                     /* Set to be no zisofs. */
8103                     file->zisofs.header_size = 0;
8104                     file->zisofs.log2_bs = 0;
8105                     file->zisofs.uncompressed_size = 0;
8106                     r = wb_write_padding_to_temp(a, file->content.size);
8107                     if (r < 0)
8108                               ret = ARCHIVE_FATAL;
8109           }
8110 
8111           /*
8112            * Free the resource we used in this function only.
8113            */
8114           free(rbuff);
8115           free(zext.block_pointers);
8116           if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {
8117           archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8118                         "Failed to clean up compressor");
8119                     ret = ARCHIVE_FATAL;
8120           }
8121 
8122           return (ret);
8123 }
8124 
8125 #else
8126 
8127 static int
zisofs_write_to_temp(struct archive_write * a,const void * buff,size_t s)8128 zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
8129 {
8130           (void)buff; /* UNUSED */
8131           (void)s; /* UNUSED */
8132           archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programming error");
8133           return (ARCHIVE_FATAL);
8134 }
8135 
8136 static int
zisofs_rewind_boot_file(struct archive_write * a)8137 zisofs_rewind_boot_file(struct archive_write *a)
8138 {
8139           struct iso9660 *iso9660 = a->format_data;
8140 
8141           if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {
8142                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8143                         "We cannot extract the zisofs imaged boot file;"
8144                         " this may not boot in being zisofs imaged");
8145                     return (ARCHIVE_FAILED);
8146           }
8147           return (ARCHIVE_OK);
8148 }
8149 
8150 static int
zisofs_finish_entry(struct archive_write * a)8151 zisofs_finish_entry(struct archive_write *a)
8152 {
8153           (void)a; /* UNUSED */
8154           return (ARCHIVE_OK);
8155 }
8156 
8157 static int
zisofs_free(struct archive_write * a)8158 zisofs_free(struct archive_write *a)
8159 {
8160           (void)a; /* UNUSED */
8161           return (ARCHIVE_OK);
8162 }
8163 
8164 #endif /* HAVE_ZLIB_H */
8165 
8166