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           unsigned 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           unsigned 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                     unsigned int         detect_magic:1;
759                     unsigned int         making:1;
760                     unsigned 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 = "\0\0";
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_S
2525           localtime_s(tm, t);
2526 #elif HAVE_LOCALTIME_R
2527           tzset();
2528           localtime_r(t, tm);
2529 #else
2530           memcpy(tm, localtime(t), sizeof(*tm));
2531 #endif
2532 }
2533 
2534 /*
2535  * Date and Time Format.
2536  * ISO9660 Standard 8.4.26.1
2537  */
2538 static void
set_date_time(unsigned char * p,time_t t)2539 set_date_time(unsigned char *p, time_t t)
2540 {
2541           struct tm tm;
2542 
2543           get_tmfromtime(&tm, &t);
2544           set_digit(p, 4, tm.tm_year + 1900);
2545           set_digit(p+4, 2, tm.tm_mon + 1);
2546           set_digit(p+6, 2, tm.tm_mday);
2547           set_digit(p+8, 2, tm.tm_hour);
2548           set_digit(p+10, 2, tm.tm_min);
2549           set_digit(p+12, 2, tm.tm_sec);
2550           set_digit(p+14, 2, 0);
2551           set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
2552 }
2553 
2554 static void
set_date_time_null(unsigned char * p)2555 set_date_time_null(unsigned char *p)
2556 {
2557           memset(p, (int)'0', 16);
2558           p[16] = 0;
2559 }
2560 
2561 static void
set_time_915(unsigned char * p,time_t t)2562 set_time_915(unsigned char *p, time_t t)
2563 {
2564           struct tm tm;
2565 
2566           get_tmfromtime(&tm, &t);
2567           set_num_711(p+0, tm.tm_year);
2568           set_num_711(p+1, tm.tm_mon+1);
2569           set_num_711(p+2, tm.tm_mday);
2570           set_num_711(p+3, tm.tm_hour);
2571           set_num_711(p+4, tm.tm_min);
2572           set_num_711(p+5, tm.tm_sec);
2573           set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
2574 }
2575 
2576 
2577 /*
2578  * Write SUSP "CE" System Use Entry.
2579  */
2580 static int
set_SUSP_CE(unsigned char * p,int location,int offset,int size)2581 set_SUSP_CE(unsigned char *p, int location, int offset, int size)
2582 {
2583           unsigned char *bp = p -1;
2584           /*  Extend the System Use Area
2585            *   "CE" Format:
2586            *               len  ver
2587            *    +----+----+----+----+-----------+-----------+
2588            *    | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |
2589            *    +----+----+----+----+-----------+-----------+
2590            *    0    1    2    3    4          12          20
2591            *    +-----------+
2592            *    | LOCATION3 |
2593            *    +-----------+
2594            *   20          28
2595            *   LOCATION1 : Location of Continuation of System Use Area.
2596            *   LOCATION2 : Offset to Start of Continuation.
2597            *   LOCATION3 : Length of the Continuation.
2598            */
2599 
2600           bp[1] = 'C';
2601           bp[2] = 'E';
2602           bp[3] = RR_CE_SIZE; /* length */
2603           bp[4] = 1;                    /* version          */
2604           set_num_733(bp+5, location);
2605           set_num_733(bp+13, offset);
2606           set_num_733(bp+21, size);
2607           return (RR_CE_SIZE);
2608 }
2609 
2610 /*
2611  * The functions, which names are beginning with extra_, are used to
2612  * control extra records.
2613  * The maximum size of a Directory Record is 254. When a filename is
2614  * very long, all of RRIP data of a file won't stored to the Directory
2615  * Record and so remaining RRIP data store to an extra record instead.
2616  */
2617 static unsigned char *
extra_open_record(unsigned char * bp,int dr_len,struct isoent * isoent,struct ctl_extr_rec * ctl)2618 extra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,
2619     struct ctl_extr_rec *ctl)
2620 {
2621           ctl->bp = bp;
2622           if (bp != NULL)
2623                     bp += dr_len;
2624           ctl->use_extr = 0;
2625           ctl->isoent = isoent;
2626           ctl->ce_ptr = NULL;
2627           ctl->cur_len = ctl->dr_len = dr_len;
2628           ctl->limit = DR_LIMIT;
2629 
2630           return (bp);
2631 }
2632 
2633 static void
extra_close_record(struct ctl_extr_rec * ctl,int ce_size)2634 extra_close_record(struct ctl_extr_rec *ctl, int ce_size)
2635 {
2636           int padding = 0;
2637 
2638           if (ce_size > 0)
2639                     extra_tell_used_size(ctl, ce_size);
2640           /* Padding. */
2641           if (ctl->cur_len & 0x01) {
2642                     ctl->cur_len++;
2643                     if (ctl->bp != NULL)
2644                               ctl->bp[ctl->cur_len] = 0;
2645                     padding = 1;
2646           }
2647           if (ctl->use_extr) {
2648                     if (ctl->ce_ptr != NULL)
2649                               set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,
2650                                   ctl->extr_off, ctl->cur_len - padding);
2651           } else
2652                     ctl->dr_len = ctl->cur_len;
2653 }
2654 
2655 #define extra_space(ctl)      ((ctl)->limit - (ctl)->cur_len)
2656 
2657 static unsigned char *
extra_next_record(struct ctl_extr_rec * ctl,int length)2658 extra_next_record(struct ctl_extr_rec *ctl, int length)
2659 {
2660           int cur_len = ctl->cur_len;/* save cur_len */
2661 
2662           /* Close the current extra record or Directory Record. */
2663           extra_close_record(ctl, RR_CE_SIZE);
2664 
2665           /* Get a next extra record. */
2666           ctl->use_extr = 1;
2667           if (ctl->bp != NULL) {
2668                     /* Storing data into an extra record. */
2669                     unsigned char *p;
2670 
2671                     /* Save the pointer where a CE extension will be
2672                      * stored to. */
2673                     ctl->ce_ptr = &ctl->bp[cur_len+1];
2674                     p = extra_get_record(ctl->isoent,
2675                         &ctl->limit, &ctl->extr_off, &ctl->extr_loc);
2676                     ctl->bp = p - 1;/* the base of bp offset is 1. */
2677           } else
2678                     /* Calculating the size of an extra record. */
2679                     (void)extra_get_record(ctl->isoent,
2680                         &ctl->limit, NULL, NULL);
2681           ctl->cur_len = 0;
2682           /* Check if an extra record is almost full.
2683            * If so, get a next one. */
2684           if (extra_space(ctl) < length)
2685                     (void)extra_next_record(ctl, length);
2686 
2687           return (ctl->bp);
2688 }
2689 
2690 static inline struct extr_rec *
extra_last_record(struct isoent * isoent)2691 extra_last_record(struct isoent *isoent)
2692 {
2693           if (isoent->extr_rec_list.first == NULL)
2694                     return (NULL);
2695           return ((struct extr_rec *)(void *)
2696                     ((char *)(isoent->extr_rec_list.last)
2697                         - offsetof(struct extr_rec, next)));
2698 }
2699 
2700 static unsigned char *
extra_get_record(struct isoent * isoent,int * space,int * off,int * loc)2701 extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
2702 {
2703           struct extr_rec *rec;
2704 
2705           isoent = isoent->parent;
2706           if (off != NULL) {
2707                     /* Storing data into an extra record. */
2708                     rec = isoent->extr_rec_list.current;
2709                     if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)
2710                               rec = rec->next;
2711           } else {
2712                     /* Calculating the size of an extra record. */
2713                     rec = extra_last_record(isoent);
2714                     if (rec == NULL ||
2715                         DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {
2716                               rec = malloc(sizeof(*rec));
2717                               if (rec == NULL)
2718                                         return (NULL);
2719                               rec->location = 0;
2720                               rec->offset = 0;
2721                               /* Insert `rec` into the tail of isoent->extr_rec_list */
2722                               rec->next = NULL;
2723                               /*
2724                                * Note: testing isoent->extr_rec_list.last == NULL
2725                                * here is really unneeded since it has been already
2726                                * initialized at isoent_new function but Clang Static
2727                                * Analyzer claims that it is dereference of null
2728                                * pointer.
2729                                */
2730                               if (isoent->extr_rec_list.last == NULL)
2731                                         isoent->extr_rec_list.last =
2732                                                   &(isoent->extr_rec_list.first);
2733                               *isoent->extr_rec_list.last = rec;
2734                               isoent->extr_rec_list.last = &(rec->next);
2735                     }
2736           }
2737           *space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;
2738           if (*space & 0x01)
2739                     *space -= 1;/* Keep padding space. */
2740           if (off != NULL)
2741                     *off = rec->offset;
2742           if (loc != NULL)
2743                     *loc = rec->location;
2744           isoent->extr_rec_list.current = rec;
2745 
2746           return (&rec->buf[rec->offset]);
2747 }
2748 
2749 static void
extra_tell_used_size(struct ctl_extr_rec * ctl,int size)2750 extra_tell_used_size(struct ctl_extr_rec *ctl, int size)
2751 {
2752           struct isoent *isoent;
2753           struct extr_rec *rec;
2754 
2755           if (ctl->use_extr) {
2756                     isoent = ctl->isoent->parent;
2757                     rec = isoent->extr_rec_list.current;
2758                     if (rec != NULL)
2759                               rec->offset += size;
2760           }
2761           ctl->cur_len += size;
2762 }
2763 
2764 static int
extra_setup_location(struct isoent * isoent,int location)2765 extra_setup_location(struct isoent *isoent, int location)
2766 {
2767           struct extr_rec *rec;
2768           int cnt;
2769 
2770           cnt = 0;
2771           rec = isoent->extr_rec_list.first;
2772           isoent->extr_rec_list.current = rec;
2773           while (rec) {
2774                     cnt++;
2775                     rec->location = location++;
2776                     rec->offset = 0;
2777                     rec = rec->next;
2778           }
2779           return (cnt);
2780 }
2781 
2782 /*
2783  * Create the RRIP entries.
2784  */
2785 static int
set_directory_record_rr(unsigned char * bp,int dr_len,struct isoent * isoent,struct iso9660 * iso9660,enum dir_rec_type t)2786 set_directory_record_rr(unsigned char *bp, int dr_len,
2787     struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)
2788 {
2789           /* Flags(BP 5) of the Rockridge "RR" System Use Field */
2790           unsigned char rr_flag;
2791 #define RR_USE_PX   0x01
2792 #define RR_USE_PN   0x02
2793 #define RR_USE_SL   0x04
2794 #define RR_USE_NM   0x08
2795 #define RR_USE_CL   0x10
2796 #define RR_USE_PL   0x20
2797 #define RR_USE_RE   0x40
2798 #define RR_USE_TF   0x80
2799           int length;
2800           struct ctl_extr_rec ctl;
2801           struct isoent *rr_parent, *pxent;
2802           struct isofile *file;
2803 
2804           bp = extra_open_record(bp, dr_len, isoent, &ctl);
2805 
2806           if (t == DIR_REC_PARENT) {
2807                     rr_parent = isoent->rr_parent;
2808                     pxent = isoent->parent;
2809                     if (rr_parent != NULL)
2810                               isoent = rr_parent;
2811                     else
2812                               isoent = isoent->parent;
2813           } else {
2814                     rr_parent = NULL;
2815                     pxent = isoent;
2816           }
2817           file = isoent->file;
2818 
2819           if (t != DIR_REC_NORMAL) {
2820                     rr_flag = RR_USE_PX | RR_USE_TF;
2821                     if (rr_parent != NULL)
2822                               rr_flag |= RR_USE_PL;
2823           } else {
2824                     rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;
2825                     if (archive_entry_filetype(file->entry) == AE_IFLNK)
2826                               rr_flag |= RR_USE_SL;
2827                     if (isoent->rr_parent != NULL)
2828                               rr_flag |= RR_USE_RE;
2829                     if (isoent->rr_child != NULL)
2830                               rr_flag |= RR_USE_CL;
2831                     if (archive_entry_filetype(file->entry) == AE_IFCHR ||
2832                         archive_entry_filetype(file->entry) == AE_IFBLK)
2833                               rr_flag |= RR_USE_PN;
2834 #ifdef COMPAT_MKISOFS
2835                     /*
2836                      * mkisofs 2.01.01a63 records "RE" extension to
2837                      * the entry of "rr_moved" directory.
2838                      * I don't understand this behavior.
2839                      */
2840                     if (isoent->virtual &&
2841                         isoent->parent == iso9660->primary.rootent &&
2842                         strcmp(isoent->file->basename.s, "rr_moved") == 0)
2843                               rr_flag |= RR_USE_RE;
2844 #endif
2845           }
2846 
2847           /* Write "SP" System Use Entry. */
2848           if (t == DIR_REC_SELF && isoent == isoent->parent) {
2849                     length = 7;
2850                     if (bp != NULL) {
2851                               bp[1] = 'S';
2852                               bp[2] = 'P';
2853                               bp[3] = length;
2854                               bp[4] = 1;          /* version          */
2855                               bp[5] = 0xBE;  /* Check Byte  */
2856                               bp[6] = 0xEF;  /* Check Byte  */
2857                               bp[7] = 0;
2858                               bp += length;
2859                     }
2860                     extra_tell_used_size(&ctl, length);
2861           }
2862 
2863           /* Write "RR" System Use Entry. */
2864           length = 5;
2865           if (extra_space(&ctl) < length)
2866                     bp = extra_next_record(&ctl, length);
2867           if (bp != NULL) {
2868                     bp[1] = 'R';
2869                     bp[2] = 'R';
2870                     bp[3] = length;
2871                     bp[4] = 1;          /* version */
2872                     bp[5] = rr_flag;
2873                     bp += length;
2874           }
2875           extra_tell_used_size(&ctl, length);
2876 
2877           /* Write "NM" System Use Entry. */
2878           if (rr_flag & RR_USE_NM) {
2879                     /*
2880                      *   "NM" Format:
2881                      *     e.g. a basename is 'foo'
2882                      *               len  ver  flg
2883                      *    +----+----+----+----+----+----+----+----+
2884                      *    | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|
2885                      *    +----+----+----+----+----+----+----+----+
2886                      *    <----------------- len ----------------->
2887                      */
2888                     size_t nmlen = file->basename.length;
2889                     const char *nm = file->basename.s;
2890                     size_t nmmax;
2891 
2892                     if (extra_space(&ctl) < 6)
2893                               bp = extra_next_record(&ctl, 6);
2894                     if (bp != NULL) {
2895                               bp[1] = 'N';
2896                               bp[2] = 'M';
2897                               bp[4] = 1;              /* version      */
2898                     }
2899                     nmmax = extra_space(&ctl);
2900                     if (nmmax > 0xff)
2901                               nmmax = 0xff;
2902                     while (nmlen + 5 > nmmax) {
2903                               length = (int)nmmax;
2904                               if (bp != NULL) {
2905                                         bp[3] = length;
2906                                         bp[5] = 0x01;/* Alternate Name continues
2907                                                          * in next "NM" field */
2908                                         memcpy(bp+6, nm, length - 5);
2909                                         bp += length;
2910                               }
2911                               nmlen -= length - 5;
2912                               nm += length - 5;
2913                               extra_tell_used_size(&ctl, length);
2914                               if (extra_space(&ctl) < 6) {
2915                                         bp = extra_next_record(&ctl, 6);
2916                                         nmmax = extra_space(&ctl);
2917                                         if (nmmax > 0xff)
2918                                                   nmmax = 0xff;
2919                               }
2920                               if (bp != NULL) {
2921                                         bp[1] = 'N';
2922                                         bp[2] = 'M';
2923                                         bp[4] = 1;    /* version */
2924                               }
2925                     }
2926                     length = 5 + (int)nmlen;
2927                     if (bp != NULL) {
2928                               bp[3] = length;
2929                               bp[5] = 0;
2930                               memcpy(bp+6, nm, nmlen);
2931                               bp += length;
2932                     }
2933                     extra_tell_used_size(&ctl, length);
2934           }
2935 
2936           /* Write "PX" System Use Entry. */
2937           if (rr_flag & RR_USE_PX) {
2938                     /*
2939                      *   "PX" Format:
2940                      *               len  ver
2941                      *    +----+----+----+----+-----------+-----------+
2942                      *    | 'P'| 'X'| 2C | 01 | FILE MODE |   LINKS   |
2943                      *    +----+----+----+----+-----------+-----------+
2944                      *    0    1    2    3    4          12          20
2945                      *    +-----------+-----------+------------------+
2946                      *    |  USER ID  | GROUP ID  |FILE SERIAL NUMBER|
2947                      *    +-----------+-----------+------------------+
2948                      *   20          28          36                 44
2949                      */
2950                     length = 44;
2951                     if (extra_space(&ctl) < length)
2952                               bp = extra_next_record(&ctl, length);
2953                     if (bp != NULL) {
2954                               mode_t mode;
2955                               int64_t uid;
2956                               int64_t gid;
2957 
2958                               mode = archive_entry_mode(file->entry);
2959                               uid = archive_entry_uid(file->entry);
2960                               gid = archive_entry_gid(file->entry);
2961                               if (iso9660->opt.rr == OPT_RR_USEFUL) {
2962                                         /*
2963                                          * This action is similar to mkisofs -r option
2964                                          * but our rockridge=useful option does not
2965                                          * set a zero to uid and gid.
2966                                          */
2967                                         /* set all read bit ON */
2968                                         mode |= 0444;
2969 #if !defined(_WIN32) && !defined(__CYGWIN__)
2970                                         if (mode & 0111)
2971 #endif
2972                                                   /* set all exec bit ON */
2973                                                   mode |= 0111;
2974                                         /* clear all write bits. */
2975                                         mode &= ~0222;
2976                                         /* clear setuid,setgid,sticky bits. */
2977                                         mode &= ~07000;
2978                               }
2979 
2980                               bp[1] = 'P';
2981                               bp[2] = 'X';
2982                               bp[3] = length;
2983                               bp[4] = 1;          /* version          */
2984                               /* file mode */
2985                               set_num_733(bp+5, mode);
2986                               /* file links (stat.st_nlink) */
2987                               set_num_733(bp+13,
2988                                   archive_entry_nlink(file->entry));
2989                               set_num_733(bp+21, (uint32_t)uid);
2990                               set_num_733(bp+29, (uint32_t)gid);
2991                               /* File Serial Number */
2992                               if (pxent->dir)
2993                                         set_num_733(bp+37, pxent->dir_location);
2994                               else if (file->hardlink_target != NULL)
2995                                         set_num_733(bp+37,
2996                                             file->hardlink_target->cur_content->location);
2997                               else
2998                                         set_num_733(bp+37,
2999                                             file->cur_content->location);
3000                               bp += length;
3001                     }
3002                     extra_tell_used_size(&ctl, length);
3003           }
3004 
3005           /* Write "SL" System Use Entry. */
3006           if (rr_flag & RR_USE_SL) {
3007                     /*
3008                      *   "SL" Format:
3009                      *     e.g. a symbolic name is 'foo/bar'
3010                      *               len  ver  flg
3011                      *    +----+----+----+----+----+------------+
3012                      *    | 'S'| 'L'| 0F | 01 | 00 | components |
3013                      *    +----+----+----+----+----+-----+------+
3014                      *    0    1    2    3    4    5  ...|...  15
3015                      *    <----------------- len --------+------>
3016                      *    components :                   |
3017                      *     cflg clen                     |
3018                      *    +----+----+----+----+----+     |
3019                      *    | 00 | 03 | 'f'| 'o'| 'o'| <---+
3020                      *    +----+----+----+----+----+     |
3021                      *    5    6    7    8    9   10     |
3022                      *     cflg clen                     |
3023                      *    +----+----+----+----+----+     |
3024                      *    | 00 | 03 | 'b'| 'a'| 'r'| <---+
3025                      *    +----+----+----+----+----+
3026                      *   10   11   12   13   14   15
3027                      *
3028                      *    - cflg : flag of component
3029                      *    - clen : length of component
3030                      */
3031                     const char *sl;
3032                     char sl_last;
3033 
3034                     if (extra_space(&ctl) < 7)
3035                               bp = extra_next_record(&ctl, 7);
3036                     sl = file->symlink.s;
3037                     sl_last = '\0';
3038                     if (bp != NULL) {
3039                               bp[1] = 'S';
3040                               bp[2] = 'L';
3041                               bp[4] = 1;          /* version          */
3042                     }
3043                     for (;;) {
3044                               unsigned char *nc, *cf,  *cl, cldmy = 0;
3045                               int sllen, slmax;
3046 
3047                               slmax = extra_space(&ctl);
3048                               if (slmax > 0xff)
3049                                         slmax = 0xff;
3050                               if (bp != NULL)
3051                                         nc = &bp[6];
3052                               else
3053                                         nc = NULL;
3054                               cf = cl = NULL;
3055                               sllen = 0;
3056                               while (*sl && sllen + 11 < slmax) {
3057                                         if (sl_last == '\0' && sl[0] == '/') {
3058                                                   /*
3059                                                    *     flg  len
3060                                                    *    +----+----+
3061                                                    *    | 08 | 00 | ROOT component.
3062                                                    *    +----+----+ ("/")
3063                                                    *
3064                                                    * Root component has to appear
3065                                                    * at the first component only.
3066                                                    */
3067                                                   if (nc != NULL) {
3068                                                             cf = nc++;
3069                                                             *cf = 0x08; /* ROOT */
3070                                                             *nc++ = 0;
3071                                                   }
3072                                                   sllen += 2;
3073                                                   sl++;
3074                                                   sl_last = '/';
3075                                                   cl = NULL;
3076                                                   continue;
3077                                         }
3078                                         if (((sl_last == '\0' || sl_last == '/') &&
3079                                               sl[0] == '.' && sl[1] == '.' &&
3080                                              (sl[2] == '/' || sl[2] == '\0')) ||
3081                                             (sl[0] == '/' &&
3082                                               sl[1] == '.' && sl[2] == '.' &&
3083                                              (sl[3] == '/' || sl[3] == '\0'))) {
3084                                                   /*
3085                                                    *     flg  len
3086                                                    *    +----+----+
3087                                                    *    | 04 | 00 | PARENT component.
3088                                                    *    +----+----+ ("..")
3089                                                    */
3090                                                   if (nc != NULL) {
3091                                                             cf = nc++;
3092                                                             *cf = 0x04; /* PARENT */
3093                                                             *nc++ = 0;
3094                                                   }
3095                                                   sllen += 2;
3096                                                   if (sl[0] == '/')
3097                                                             sl += 3;/* skip "/.." */
3098                                                   else
3099                                                             sl += 2;/* skip ".." */
3100                                                   sl_last = '.';
3101                                                   cl = NULL;
3102                                                   continue;
3103                                         }
3104                                         if (((sl_last == '\0' || sl_last == '/') &&
3105                                               sl[0] == '.' &&
3106                                              (sl[1] == '/' || sl[1] == '\0')) ||
3107                                             (sl[0] == '/' && sl[1] == '.' &&
3108                                              (sl[2] == '/' || sl[2] == '\0'))) {
3109                                                   /*
3110                                                    *     flg  len
3111                                                    *    +----+----+
3112                                                    *    | 02 | 00 | CURRENT component.
3113                                                    *    +----+----+ (".")
3114                                                    */
3115                                                   if (nc != NULL) {
3116                                                             cf = nc++;
3117                                                             *cf = 0x02; /* CURRENT */
3118                                                             *nc++ = 0;
3119                                                   }
3120                                                   sllen += 2;
3121                                                   if (sl[0] == '/')
3122                                                             sl += 2;/* skip "/." */
3123                                                   else
3124                                                             sl ++;  /* skip "." */
3125                                                   sl_last = '.';
3126                                                   cl = NULL;
3127                                                   continue;
3128                                         }
3129                                         if (sl[0] == '/' || cl == NULL) {
3130                                                   if (nc != NULL) {
3131                                                             cf = nc++;
3132                                                             *cf = 0;
3133                                                             cl = nc++;
3134                                                             *cl = 0;
3135                                                   } else
3136                                                             cl = &cldmy;
3137                                                   sllen += 2;
3138                                                   if (sl[0] == '/') {
3139                                                             sl_last = *sl++;
3140                                                             continue;
3141                                                   }
3142                                         }
3143                                         sl_last = *sl++;
3144                                         if (nc != NULL) {
3145                                                   *nc++ = sl_last;
3146                                                   (*cl) ++;
3147                                         }
3148                                         sllen++;
3149                               }
3150                               if (*sl) {
3151                                         length = 5 + sllen;
3152                                         if (bp != NULL) {
3153                                                   /*
3154                                                    * Mark flg as CONTINUE component.
3155                                                    */
3156                                                   *cf |= 0x01;
3157                                                   /*
3158                                                    *               len  ver  flg
3159                                                    *    +----+----+----+----+----+-
3160                                                    *    | 'S'| 'L'| XX | 01 | 01 |
3161                                                    *    +----+----+----+----+----+-
3162                                                    *                           ^
3163                                                    *           continues in next "SL"
3164                                                    */
3165                                                   bp[3] = length;
3166                                                   bp[5] = 0x01;/* This Symbolic Link
3167                                                                   * continues in next
3168                                                                   * "SL" field */
3169                                                   bp += length;
3170                                         }
3171                                         extra_tell_used_size(&ctl, length);
3172                                         if (extra_space(&ctl) < 11)
3173                                                   bp = extra_next_record(&ctl, 11);
3174                                         if (bp != NULL) {
3175                                                   /* Next 'SL' */
3176                                                   bp[1] = 'S';
3177                                                   bp[2] = 'L';
3178                                                   bp[4] = 1;    /* version */
3179                                         }
3180                               } else {
3181                                         length = 5 + sllen;
3182                                         if (bp != NULL) {
3183                                                   bp[3] = length;
3184                                                   bp[5] = 0;
3185                                                   bp += length;
3186                                         }
3187                                         extra_tell_used_size(&ctl, length);
3188                                         break;
3189                               }
3190                     }
3191           }
3192 
3193           /* Write "TF" System Use Entry. */
3194           if (rr_flag & RR_USE_TF) {
3195                     /*
3196                      *   "TF" Format:
3197                      *               len  ver
3198                      *    +----+----+----+----+-----+-------------+
3199                      *    | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |
3200                      *    +----+----+----+----+-----+-------------+
3201                      *    0    1    2    3    4     5            XX
3202                      *    TIME STAMPS : ISO 9660 Standard 9.1.5.
3203                      *                  If TF_LONG_FORM FLAGS is set,
3204                      *                  use ISO9660 Standard 8.4.26.1.
3205                      */
3206 #define TF_CREATION 0x01      /* Creation time recorded               */
3207 #define TF_MODIFY   0x02      /* Modification time recorded           */
3208 #define TF_ACCESS   0x04      /* Last Access time recorded            */
3209 #define TF_ATTRIBUTES         0x08      /* Last Attribute Change time recorded  */
3210 #define TF_BACKUP   0x10      /* Last Backup time recorded            */
3211 #define TF_EXPIRATION         0x20      /* Expiration time recorded             */
3212 #define TF_EFFECTIVE          0x40      /* Effective time recorded              */
3213 #define TF_LONG_FORM          0x80      /* ISO 9660 17-byte time format used    */
3214                     unsigned char tf_flags;
3215 
3216                     length = 5;
3217                     tf_flags = 0;
3218 #ifndef COMPAT_MKISOFS
3219                     if (archive_entry_birthtime_is_set(file->entry) &&
3220                         archive_entry_birthtime(file->entry) <=
3221                         archive_entry_mtime(file->entry)) {
3222                               length += 7;
3223                               tf_flags |= TF_CREATION;
3224                     }
3225 #endif
3226                     if (archive_entry_mtime_is_set(file->entry)) {
3227                               length += 7;
3228                               tf_flags |= TF_MODIFY;
3229                     }
3230                     if (archive_entry_atime_is_set(file->entry)) {
3231                               length += 7;
3232                               tf_flags |= TF_ACCESS;
3233                     }
3234                     if (archive_entry_ctime_is_set(file->entry)) {
3235                               length += 7;
3236                               tf_flags |= TF_ATTRIBUTES;
3237                     }
3238                     if (extra_space(&ctl) < length)
3239                               bp = extra_next_record(&ctl, length);
3240                     if (bp != NULL) {
3241                               bp[1] = 'T';
3242                               bp[2] = 'F';
3243                               bp[3] = length;
3244                               bp[4] = 1;          /* version          */
3245                               bp[5] = tf_flags;
3246                               bp += 5;
3247                               /* Creation time */
3248                               if (tf_flags & TF_CREATION) {
3249                                         set_time_915(bp+1,
3250                                             archive_entry_birthtime(file->entry));
3251                                         bp += 7;
3252                               }
3253                               /* Modification time */
3254                               if (tf_flags & TF_MODIFY) {
3255                                         set_time_915(bp+1,
3256                                             archive_entry_mtime(file->entry));
3257                                         bp += 7;
3258                               }
3259                               /* Last Access time */
3260                               if (tf_flags & TF_ACCESS) {
3261                                         set_time_915(bp+1,
3262                                             archive_entry_atime(file->entry));
3263                                         bp += 7;
3264                               }
3265                               /* Last Attribute Change time */
3266                               if (tf_flags & TF_ATTRIBUTES) {
3267                                         set_time_915(bp+1,
3268                                             archive_entry_ctime(file->entry));
3269                                         bp += 7;
3270                               }
3271                     }
3272                     extra_tell_used_size(&ctl, length);
3273           }
3274 
3275           /* Write "RE" System Use Entry. */
3276           if (rr_flag & RR_USE_RE) {
3277                     /*
3278                      *   "RE" Format:
3279                      *               len  ver
3280                      *    +----+----+----+----+
3281                      *    | 'R'| 'E'| 04 | 01 |
3282                      *    +----+----+----+----+
3283                      *    0    1    2    3    4
3284                      */
3285                     length = 4;
3286                     if (extra_space(&ctl) < length)
3287                               bp = extra_next_record(&ctl, length);
3288                     if (bp != NULL) {
3289                               bp[1] = 'R';
3290                               bp[2] = 'E';
3291                               bp[3] = length;
3292                               bp[4] = 1;          /* version          */
3293                               bp += length;
3294                     }
3295                     extra_tell_used_size(&ctl, length);
3296           }
3297 
3298           /* Write "PL" System Use Entry. */
3299           if (rr_flag & RR_USE_PL) {
3300                     /*
3301                      *   "PL" Format:
3302                      *               len  ver
3303                      *    +----+----+----+----+------------+
3304                      *    | 'P'| 'L'| 0C | 01 | *LOCATION  |
3305                      *    +----+----+----+----+------------+
3306                      *    0    1    2    3    4           12
3307                      *    *LOCATION: location of parent directory
3308                      */
3309                     length = 12;
3310                     if (extra_space(&ctl) < length)
3311                               bp = extra_next_record(&ctl, length);
3312                     if (bp != NULL) {
3313                               bp[1] = 'P';
3314                               bp[2] = 'L';
3315                               bp[3] = length;
3316                               bp[4] = 1;          /* version          */
3317                               set_num_733(bp + 5,
3318                                   rr_parent->dir_location);
3319                               bp += length;
3320                     }
3321                     extra_tell_used_size(&ctl, length);
3322           }
3323 
3324           /* Write "CL" System Use Entry. */
3325           if (rr_flag & RR_USE_CL) {
3326                     /*
3327                      *   "CL" Format:
3328                      *               len  ver
3329                      *    +----+----+----+----+------------+
3330                      *    | 'C'| 'L'| 0C | 01 | *LOCATION  |
3331                      *    +----+----+----+----+------------+
3332                      *    0    1    2    3    4           12
3333                      *    *LOCATION: location of child directory
3334                      */
3335                     length = 12;
3336                     if (extra_space(&ctl) < length)
3337                               bp = extra_next_record(&ctl, length);
3338                     if (bp != NULL) {
3339                               bp[1] = 'C';
3340                               bp[2] = 'L';
3341                               bp[3] = length;
3342                               bp[4] = 1;          /* version          */
3343                               set_num_733(bp + 5,
3344                                   isoent->rr_child->dir_location);
3345                               bp += length;
3346                     }
3347                     extra_tell_used_size(&ctl, length);
3348           }
3349 
3350           /* Write "PN" System Use Entry. */
3351           if (rr_flag & RR_USE_PN) {
3352                     /*
3353                      *   "PN" Format:
3354                      *               len  ver
3355                      *    +----+----+----+----+------------+------------+
3356                      *    | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low  |
3357                      *    +----+----+----+----+------------+------------+
3358                      *    0    1    2    3    4           12           20
3359                      */
3360                     length = 20;
3361                     if (extra_space(&ctl) < length)
3362                               bp = extra_next_record(&ctl, length);
3363                     if (bp != NULL) {
3364                               uint64_t dev;
3365 
3366                               bp[1] = 'P';
3367                               bp[2] = 'N';
3368                               bp[3] = length;
3369                               bp[4] = 1;          /* version          */
3370                               dev = (uint64_t)archive_entry_rdev(file->entry);
3371                               set_num_733(bp + 5, (uint32_t)(dev >> 32));
3372                               set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
3373                               bp += length;
3374                     }
3375                     extra_tell_used_size(&ctl, length);
3376           }
3377 
3378           /* Write "ZF" System Use Entry. */
3379           if (file->zisofs.header_size) {
3380                     /*
3381                      *   "ZF" Format:
3382                      *               len  ver
3383                      *    +----+----+----+----+----+----+-------------+
3384                      *    | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |
3385                      *    +----+----+----+----+----+----+-------------+
3386                      *    0    1    2    3    4    5    6             7
3387                      *    +--------------------+-------------------+
3388                      *    | Log2 of block Size | Uncompressed Size |
3389                      *    +--------------------+-------------------+
3390                      *    7                    8                   16
3391                      */
3392                     length = 16;
3393                     if (extra_space(&ctl) < length)
3394                               bp = extra_next_record(&ctl, length);
3395                     if (bp != NULL) {
3396                               bp[1] = 'Z';
3397                               bp[2] = 'F';
3398                               bp[3] = length;
3399                               bp[4] = 1;          /* version          */
3400                               bp[5] = 'p';
3401                               bp[6] = 'z';
3402                               bp[7] = file->zisofs.header_size;
3403                               bp[8] = file->zisofs.log2_bs;
3404                               set_num_733(bp + 9, file->zisofs.uncompressed_size);
3405                               bp += length;
3406                     }
3407                     extra_tell_used_size(&ctl, length);
3408           }
3409 
3410           /* Write "CE" System Use Entry. */
3411           if (t == DIR_REC_SELF && isoent == isoent->parent) {
3412                     length = RR_CE_SIZE;
3413                     if (bp != NULL)
3414                               set_SUSP_CE(bp+1, iso9660->location_rrip_er,
3415                                   0, RRIP_ER_SIZE);
3416                     extra_tell_used_size(&ctl, length);
3417           }
3418 
3419           extra_close_record(&ctl, 0);
3420 
3421           return (ctl.dr_len);
3422 }
3423 
3424 /*
3425  * Write data of a Directory Record or calculate writing bytes itself.
3426  * If parameter `p' is NULL, calculates the size of writing data, which
3427  * a Directory Record needs to write, then it saved and return
3428  * the calculated size.
3429  * Parameter `n' is a remaining size of buffer. when parameter `p' is
3430  * not NULL, check whether that `n' is not less than the saved size.
3431  * if that `n' is small, return zero.
3432  *
3433  * This format of the Directory Record is according to
3434  * ISO9660 Standard 9.1
3435  */
3436 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)3437 set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
3438     struct iso9660 *iso9660, enum dir_rec_type t,
3439     enum vdd_type vdd_type)
3440 {
3441           unsigned char *bp;
3442           size_t dr_len;
3443           size_t fi_len;
3444 
3445           if (p != NULL) {
3446                     /*
3447                      * Check whether a write buffer size is less than the
3448                      * saved size which is needed to write this Directory
3449                      * Record.
3450                      */
3451                     switch (t) {
3452                     case DIR_REC_VD:
3453                               dr_len = isoent->dr_len.vd; break;
3454                     case DIR_REC_SELF:
3455                               dr_len = isoent->dr_len.self; break;
3456                     case DIR_REC_PARENT:
3457                               dr_len = isoent->dr_len.parent; break;
3458                     case DIR_REC_NORMAL:
3459                     default:
3460                               dr_len = isoent->dr_len.normal; break;
3461                     }
3462                     if (dr_len > n)
3463                               return (0);/* Needs more buffer size. */
3464           }
3465 
3466           if (t == DIR_REC_NORMAL && isoent->identifier != NULL)
3467                     fi_len = isoent->id_len;
3468           else
3469                     fi_len = 1;
3470 
3471           if (p != NULL) {
3472                     struct isoent *xisoent;
3473                     struct isofile *file;
3474                     unsigned char flag;
3475 
3476                     if (t == DIR_REC_PARENT)
3477                               xisoent = isoent->parent;
3478                     else
3479                               xisoent = isoent;
3480                     file = isoent->file;
3481                     if (file->hardlink_target != NULL)
3482                               file = file->hardlink_target;
3483                     /* Make a file flag. */
3484                     if (xisoent->dir)
3485                               flag = FILE_FLAG_DIRECTORY;
3486                     else {
3487                               if (file->cur_content->next != NULL)
3488                                         flag = FILE_FLAG_MULTI_EXTENT;
3489                               else
3490                                         flag = 0;
3491                     }
3492 
3493                     bp = p -1;
3494                     /* Extended Attribute Record Length */
3495                     set_num_711(bp+2, 0);
3496                     /* Location of Extent */
3497                     if (xisoent->dir)
3498                               set_num_733(bp+3, xisoent->dir_location);
3499                     else
3500                               set_num_733(bp+3, file->cur_content->location);
3501                     /* Data Length */
3502                     if (xisoent->dir)
3503                               set_num_733(bp+11,
3504                                   xisoent->dir_block * LOGICAL_BLOCK_SIZE);
3505                     else
3506                               set_num_733(bp+11, (uint32_t)file->cur_content->size);
3507                     /* Recording Date and Time */
3508                     /* NOTE:
3509                      *  If a file type is symbolic link, you are seeing this
3510                      *  field value is different from a value mkisofs makes.
3511                      *  libarchive uses lstat to get this one, but it
3512                      *  seems mkisofs uses stat to get.
3513                      */
3514                     set_time_915(bp+19,
3515                         archive_entry_mtime(xisoent->file->entry));
3516                     /* File Flags */
3517                     bp[26] = flag;
3518                     /* File Unit Size */
3519                     set_num_711(bp+27, 0);
3520                     /* Interleave Gap Size */
3521                     set_num_711(bp+28, 0);
3522                     /* Volume Sequence Number */
3523                     set_num_723(bp+29, iso9660->volume_sequence_number);
3524                     /* Length of File Identifier */
3525                     set_num_711(bp+33, (unsigned char)fi_len);
3526                     /* File Identifier */
3527                     switch (t) {
3528                     case DIR_REC_VD:
3529                     case DIR_REC_SELF:
3530                               set_num_711(bp+34, 0);
3531                               break;
3532                     case DIR_REC_PARENT:
3533                               set_num_711(bp+34, 1);
3534                               break;
3535                     case DIR_REC_NORMAL:
3536                               if (isoent->identifier != NULL)
3537                                         memcpy(bp+34, isoent->identifier, fi_len);
3538                               else
3539                                         set_num_711(bp+34, 0);
3540                               break;
3541                     }
3542           } else
3543                     bp = NULL;
3544           dr_len = 33 + fi_len;
3545           /* Padding Field */
3546           if (dr_len & 0x01) {
3547                     dr_len ++;
3548                     if (p != NULL)
3549                               bp[dr_len] = 0;
3550           }
3551 
3552           /* Volume Descriptor does not record extension. */
3553           if (t == DIR_REC_VD) {
3554                     if (p != NULL)
3555                               /* Length of Directory Record */
3556                               set_num_711(p, (unsigned char)dr_len);
3557                     else
3558                               isoent->dr_len.vd = (int)dr_len;
3559                     return ((int)dr_len);
3560           }
3561 
3562           /* Rockridge */
3563           if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
3564                     dr_len = set_directory_record_rr(bp, (int)dr_len,
3565                         isoent, iso9660, t);
3566 
3567           if (p != NULL)
3568                     /* Length of Directory Record */
3569                     set_num_711(p, (unsigned char)dr_len);
3570           else {
3571                     /*
3572                      * Save the size which is needed to write this
3573                      * Directory Record.
3574                      */
3575                     switch (t) {
3576                     case DIR_REC_VD:
3577                               /* This case does not come, but compiler
3578                                * complains that DIR_REC_VD not handled
3579                                *  in switch ....  */
3580                               break;
3581                     case DIR_REC_SELF:
3582                               isoent->dr_len.self = (int)dr_len; break;
3583                     case DIR_REC_PARENT:
3584                               isoent->dr_len.parent = (int)dr_len; break;
3585                     case DIR_REC_NORMAL:
3586                               isoent->dr_len.normal = (int)dr_len; break;
3587                     }
3588           }
3589 
3590           return ((int)dr_len);
3591 }
3592 
3593 /*
3594  * Calculate the size of a directory record.
3595  */
3596 static inline int
get_dir_rec_size(struct iso9660 * iso9660,struct isoent * isoent,enum dir_rec_type t,enum vdd_type vdd_type)3597 get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
3598     enum dir_rec_type t, enum vdd_type vdd_type)
3599 {
3600 
3601           return (set_directory_record(NULL, SIZE_MAX,
3602               isoent, iso9660, t, vdd_type));
3603 }
3604 
3605 /*
3606  * Manage to write ISO-image data with wbuff to reduce calling
3607  * __archive_write_output() for performance.
3608  */
3609 
3610 
3611 static inline unsigned char *
wb_buffptr(struct archive_write * a)3612 wb_buffptr(struct archive_write *a)
3613 {
3614           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3615 
3616           return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
3617                     - iso9660->wbuff_remaining]));
3618 }
3619 
3620 static int
wb_write_out(struct archive_write * a)3621 wb_write_out(struct archive_write *a)
3622 {
3623           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3624           size_t wsize, nw;
3625           int r;
3626 
3627           wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
3628           nw = wsize % LOGICAL_BLOCK_SIZE;
3629           if (iso9660->wbuff_type == WB_TO_STREAM)
3630                     r = __archive_write_output(a, iso9660->wbuff, wsize - nw);
3631           else
3632                     r = write_to_temp(a, iso9660->wbuff, wsize - nw);
3633           /* Increase the offset. */
3634           iso9660->wbuff_offset += wsize - nw;
3635           if (iso9660->wbuff_offset > iso9660->wbuff_written)
3636                     iso9660->wbuff_written = iso9660->wbuff_offset;
3637           iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3638           if (nw) {
3639                     iso9660->wbuff_remaining -= nw;
3640                     memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);
3641           }
3642           return (r);
3643 }
3644 
3645 static int
wb_consume(struct archive_write * a,size_t size)3646 wb_consume(struct archive_write *a, size_t size)
3647 {
3648           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3649 
3650           if (size > iso9660->wbuff_remaining ||
3651               iso9660->wbuff_remaining == 0) {
3652                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3653                         "Internal Programming error: iso9660:wb_consume()"
3654                         " size=%jd, wbuff_remaining=%jd",
3655                         (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);
3656                     return (ARCHIVE_FATAL);
3657           }
3658           iso9660->wbuff_remaining -= size;
3659           if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)
3660                     return (wb_write_out(a));
3661           return (ARCHIVE_OK);
3662 }
3663 
3664 #ifdef HAVE_ZLIB_H
3665 
3666 static int
wb_set_offset(struct archive_write * a,int64_t off)3667 wb_set_offset(struct archive_write *a, int64_t off)
3668 {
3669           struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
3670           int64_t used, ext_bytes;
3671 
3672           if (iso9660->wbuff_type != WB_TO_TEMP) {
3673                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3674                         "Internal Programming error: iso9660:wb_set_offset()");
3675                     return (ARCHIVE_FATAL);
3676           }
3677 
3678           used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
3679           if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)
3680                     iso9660->wbuff_tail = iso9660->wbuff_offset + used;
3681           if (iso9660->wbuff_offset < iso9660->wbuff_written) {
3682                     if (used > 0 &&
3683                         write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
3684                               return (ARCHIVE_FATAL);
3685                     iso9660->wbuff_offset = iso9660->wbuff_written;
3686                     lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
3687                     iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3688                     used = 0;
3689           }
3690           if (off < iso9660->wbuff_offset) {
3691                     /*
3692                      * Write out waiting data.
3693                      */
3694                     if (used > 0) {
3695                               if (wb_write_out(a) != ARCHIVE_OK)
3696                                         return (ARCHIVE_FATAL);
3697                     }
3698                     lseek(iso9660->temp_fd, off, SEEK_SET);
3699                     iso9660->wbuff_offset = off;
3700                     iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
3701           } else if (off <= iso9660->wbuff_tail) {
3702                     iso9660->wbuff_remaining = (size_t)
3703                         (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
3704           } else {
3705                     ext_bytes = off - iso9660->wbuff_tail;
3706                     iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
3707                        - (iso9660->wbuff_tail - iso9660->wbuff_offset));
3708                     while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
3709                               if (write_null(a, (size_t)iso9660->wbuff_remaining)
3710                                   != ARCHIVE_OK)
3711                                         return (ARCHIVE_FATAL);
3712                               ext_bytes -= iso9660->wbuff_remaining;
3713                     }
3714                     if (ext_bytes > 0) {
3715                               if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)
3716                                         return (ARCHIVE_FATAL);
3717                     }
3718           }
3719           return (ARCHIVE_OK);
3720 }
3721 
3722 #endif /* HAVE_ZLIB_H */
3723 
3724 static int
write_null(struct archive_write * a,size_t size)3725 write_null(struct archive_write *a, size_t size)
3726 {
3727           size_t remaining;
3728           unsigned char *p, *old;
3729           int r;
3730 
3731           remaining = wb_remaining(a);
3732           p = wb_buffptr(a);
3733           if (size <= remaining) {
3734                     memset(p, 0, size);
3735                     return (wb_consume(a, size));
3736           }
3737           memset(p, 0, remaining);
3738           r = wb_consume(a, remaining);
3739           if (r != ARCHIVE_OK)
3740                     return (r);
3741           size -= remaining;
3742           old = p;
3743           p = wb_buffptr(a);
3744           memset(p, 0, old - p);
3745           remaining = wb_remaining(a);
3746           while (size) {
3747                     size_t wsize = size;
3748 
3749                     if (wsize > remaining)
3750                               wsize = remaining;
3751                     r = wb_consume(a, wsize);
3752                     if (r != ARCHIVE_OK)
3753                               return (r);
3754                     size -= wsize;
3755           }
3756           return (ARCHIVE_OK);
3757 }
3758 
3759 /*
3760  * Write Volume Descriptor Set Terminator
3761  */
3762 static int
write_VD_terminator(struct archive_write * a)3763 write_VD_terminator(struct archive_write *a)
3764 {
3765           unsigned char *bp;
3766 
3767           bp = wb_buffptr(a) -1;
3768           set_VD_bp(bp, VDT_TERMINATOR, 1);
3769           set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);
3770 
3771           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
3772 }
3773 
3774 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)3775 set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
3776     struct archive_write *a, struct vdd *vdd, struct archive_string *id,
3777     const char *label, int leading_under, enum char_type char_type)
3778 {
3779           char identifier[256];
3780           struct isoent *isoent;
3781           const char *ids;
3782           size_t len;
3783           int r;
3784 
3785           if (id->length > 0 && leading_under && id->s[0] != '_') {
3786                     if (char_type == A_CHAR)
3787                               r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);
3788                     else
3789                               r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);
3790           } else if (id->length > 0) {
3791                     ids = id->s;
3792                     if (leading_under)
3793                               ids++;
3794                     isoent = isoent_find_entry(vdd->rootent, ids);
3795                     if (isoent == NULL) {
3796                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
3797                                   "Not Found %s `%s'.",
3798                                   label, ids);
3799                               return (ARCHIVE_FATAL);
3800                     }
3801                     len = isoent->ext_off + isoent->ext_len;
3802                     if (vdd->vdd_type == VDD_JOLIET) {
3803                               if (len > sizeof(identifier)-2)
3804                                         len = sizeof(identifier)-2;
3805                     } else {
3806                               if (len > sizeof(identifier)-1)
3807                                         len = sizeof(identifier)-1;
3808                     }
3809                     memcpy(identifier, isoent->identifier, len);
3810                     identifier[len] = '\0';
3811                     if (vdd->vdd_type == VDD_JOLIET) {
3812                               identifier[len+1] = 0;
3813                               vdc = VDC_UCS2_DIRECT;
3814                     }
3815                     if (char_type == A_CHAR)
3816                               r = set_str_a_characters_bp(a, bp, from, to,
3817                                   identifier, vdc);
3818                     else
3819                               r = set_str_d_characters_bp(a, bp, from, to,
3820                                   identifier, vdc);
3821           } else {
3822                     if (char_type == A_CHAR)
3823                               r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);
3824                     else
3825                               r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);
3826           }
3827           return (r);
3828 }
3829 
3830 /*
3831  * Write Primary/Supplementary Volume Descriptor
3832  */
3833 static int
write_VD(struct archive_write * a,struct vdd * vdd)3834 write_VD(struct archive_write *a, struct vdd *vdd)
3835 {
3836           struct iso9660 *iso9660;
3837           unsigned char *bp;
3838           uint16_t volume_set_size = 1;
3839           char identifier[256];
3840           enum VD_type vdt;
3841           enum vdc vdc;
3842           unsigned char vd_ver, fst_ver;
3843           int r;
3844 
3845           iso9660 = a->format_data;
3846           switch (vdd->vdd_type) {
3847           case VDD_JOLIET:
3848                     vdt = VDT_SUPPLEMENTARY;
3849                     vd_ver = fst_ver = 1;
3850                     vdc = VDC_UCS2;
3851                     break;
3852           case VDD_ENHANCED:
3853                     vdt = VDT_SUPPLEMENTARY;
3854                     vd_ver = fst_ver = 2;
3855                     vdc = VDC_LOWERCASE;
3856                     break;
3857           case VDD_PRIMARY:
3858           default:
3859                     vdt = VDT_PRIMARY;
3860                     vd_ver = fst_ver = 1;
3861 #ifdef COMPAT_MKISOFS
3862                     vdc = VDC_LOWERCASE;
3863 #else
3864                     vdc = VDC_STD;
3865 #endif
3866                     break;
3867           }
3868 
3869           bp = wb_buffptr(a) -1;
3870           /* Volume Descriptor Type */
3871           set_VD_bp(bp, vdt, vd_ver);
3872           /* Unused Field */
3873           set_unused_field_bp(bp, 8, 8);
3874           /* System Identifier */
3875           get_system_identitier(identifier, sizeof(identifier));
3876           r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);
3877           if (r != ARCHIVE_OK)
3878                     return (r);
3879           /* Volume Identifier */
3880           r = set_str_d_characters_bp(a, bp, 41, 72,
3881               iso9660->volume_identifier.s, vdc);
3882           if (r != ARCHIVE_OK)
3883                     return (r);
3884           /* Unused Field */
3885           set_unused_field_bp(bp, 73, 80);
3886           /* Volume Space Size */
3887           set_num_733(bp+81, iso9660->volume_space_size);
3888           if (vdd->vdd_type == VDD_JOLIET) {
3889                     /* Escape Sequences */
3890                     bp[89] = 0x25;/* UCS-2 Level 3 */
3891                     bp[90] = 0x2F;
3892                     bp[91] = 0x45;
3893                     memset(bp + 92, 0, 120 - 92 + 1);
3894           } else {
3895                     /* Unused Field */
3896                     set_unused_field_bp(bp, 89, 120);
3897           }
3898           /* Volume Set Size */
3899           set_num_723(bp+121, volume_set_size);
3900           /* Volume Sequence Number */
3901           set_num_723(bp+125, iso9660->volume_sequence_number);
3902           /* Logical Block Size */
3903           set_num_723(bp+129, LOGICAL_BLOCK_SIZE);
3904           /* Path Table Size */
3905           set_num_733(bp+133, vdd->path_table_size);
3906           /* Location of Occurrence of Type L Path Table */
3907           set_num_731(bp+141, vdd->location_type_L_path_table);
3908           /* Location of Optional Occurrence of Type L Path Table */
3909           set_num_731(bp+145, 0);
3910           /* Location of Occurrence of Type M Path Table */
3911           set_num_732(bp+149, vdd->location_type_M_path_table);
3912           /* Location of Optional Occurrence of Type M Path Table */
3913           set_num_732(bp+153, 0);
3914           /* Directory Record for Root Directory(BP 157 to 190) */
3915           set_directory_record(bp+157, 190-157+1, vdd->rootent,
3916               iso9660, DIR_REC_VD, vdd->vdd_type);
3917           /* Volume Set Identifier */
3918           r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);
3919           if (r != ARCHIVE_OK)
3920                     return (r);
3921           /* Publisher Identifier */
3922           r = set_file_identifier(bp, 319, 446, vdc, a, vdd,
3923               &(iso9660->publisher_identifier),
3924               "Publisher File", 1, A_CHAR);
3925           if (r != ARCHIVE_OK)
3926                     return (r);
3927           /* Data Preparer Identifier */
3928           r = set_file_identifier(bp, 447, 574, vdc, a, vdd,
3929               &(iso9660->data_preparer_identifier),
3930               "Data Preparer File", 1, A_CHAR);
3931           if (r != ARCHIVE_OK)
3932                     return (r);
3933           /* Application Identifier */
3934           r = set_file_identifier(bp, 575, 702, vdc, a, vdd,
3935               &(iso9660->application_identifier),
3936               "Application File", 1, A_CHAR);
3937           if (r != ARCHIVE_OK)
3938                     return (r);
3939           /* Copyright File Identifier */
3940           r = set_file_identifier(bp, 703, 739, vdc, a, vdd,
3941               &(iso9660->copyright_file_identifier),
3942               "Copyright File", 0, D_CHAR);
3943           if (r != ARCHIVE_OK)
3944                     return (r);
3945           /* Abstract File Identifier */
3946           r = set_file_identifier(bp, 740, 776, vdc, a, vdd,
3947               &(iso9660->abstract_file_identifier),
3948               "Abstract File", 0, D_CHAR);
3949           if (r != ARCHIVE_OK)
3950                     return (r);
3951           /* Bibliographic File Identifier */
3952           r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
3953               &(iso9660->bibliographic_file_identifier),
3954               "Bibliongraphic File", 0, D_CHAR);
3955           if (r != ARCHIVE_OK)
3956                     return (r);
3957           /* Volume Creation Date and Time */
3958           set_date_time(bp+814, iso9660->birth_time);
3959           /* Volume Modification Date and Time */
3960           set_date_time(bp+831, iso9660->birth_time);
3961           /* Volume Expiration Date and Time(obsolete) */
3962           set_date_time_null(bp+848);
3963           /* Volume Effective Date and Time */
3964           set_date_time(bp+865, iso9660->birth_time);
3965           /* File Structure Version */
3966           bp[882] = fst_ver;
3967           /* Reserved */
3968           bp[883] = 0;
3969           /* Application Use */
3970           memset(bp + 884, 0x20, 1395 - 884 + 1);
3971           /* Reserved */
3972           set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);
3973 
3974           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
3975 }
3976 
3977 /*
3978  * Write Boot Record Volume Descriptor
3979  */
3980 static int
write_VD_boot_record(struct archive_write * a)3981 write_VD_boot_record(struct archive_write *a)
3982 {
3983           struct iso9660 *iso9660;
3984           unsigned char *bp;
3985 
3986           iso9660 = a->format_data;
3987           bp = wb_buffptr(a) -1;
3988           /* Volume Descriptor Type */
3989           set_VD_bp(bp, VDT_BOOT_RECORD, 1);
3990           /* Boot System Identifier */
3991           memcpy(bp+8, "EL TORITO SPECIFICATION", 23);
3992           set_unused_field_bp(bp, 8+23, 39);
3993           /* Unused */
3994           set_unused_field_bp(bp, 40, 71);
3995           /* Absolute pointer to first sector of Boot Catalog */
3996           set_num_731(bp+72,
3997               iso9660->el_torito.catalog->file->content.location);
3998           /* Unused */
3999           set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);
4000 
4001           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4002 }
4003 
4004 enum keytype {
4005           KEY_FLG,
4006           KEY_STR,
4007           KEY_INT,
4008           KEY_HEX
4009 };
4010 static void
set_option_info(struct archive_string * info,int * opt,const char * key,enum keytype type,...)4011 set_option_info(struct archive_string *info, int *opt, const char *key,
4012     enum keytype type,  ...)
4013 {
4014           va_list ap;
4015           char prefix;
4016           const char *s;
4017           int d;
4018 
4019           prefix = (*opt==0)? ' ':',';
4020           va_start(ap, type);
4021           switch (type) {
4022           case KEY_FLG:
4023                     d = va_arg(ap, int);
4024                     archive_string_sprintf(info, "%c%s%s",
4025                         prefix, (d == 0)?"!":"", key);
4026                     break;
4027           case KEY_STR:
4028                     s = va_arg(ap, const char *);
4029                     archive_string_sprintf(info, "%c%s=%s",
4030                         prefix, key, s);
4031                     break;
4032           case KEY_INT:
4033                     d = va_arg(ap, int);
4034                     archive_string_sprintf(info, "%c%s=%d",
4035                         prefix, key, d);
4036                     break;
4037           case KEY_HEX:
4038                     d = va_arg(ap, int);
4039                     archive_string_sprintf(info, "%c%s=%x",
4040                         prefix, key, d);
4041                     break;
4042           }
4043           va_end(ap);
4044 
4045           *opt = 1;
4046 }
4047 
4048 /*
4049  * Make Non-ISO File System Information
4050  */
4051 static int
write_information_block(struct archive_write * a)4052 write_information_block(struct archive_write *a)
4053 {
4054           struct iso9660 *iso9660;
4055           char buf[128];
4056           const char *v;
4057           int opt, r;
4058           struct archive_string info;
4059           size_t info_size = LOGICAL_BLOCK_SIZE *
4060                                      NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
4061 
4062           iso9660 = (struct iso9660 *)a->format_data;
4063           if (info_size > wb_remaining(a)) {
4064                     r = wb_write_out(a);
4065                     if (r != ARCHIVE_OK)
4066                               return (r);
4067           }
4068           archive_string_init(&info);
4069           if (archive_string_ensure(&info, info_size) == NULL) {
4070                     archive_set_error(&a->archive, ENOMEM,
4071                         "Can't allocate memory");
4072                     return (ARCHIVE_FATAL);
4073           }
4074           memset(info.s, 0, info_size);
4075           opt = 0;
4076 #if defined(HAVE_CTIME_S)
4077           ctime_s(buf, sizeof(buf), &(iso9660->birth_time));
4078 #elif defined(HAVE_CTIME_R)
4079           ctime_r(&(iso9660->birth_time), buf);
4080 #else
4081           strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);
4082           buf[sizeof(buf)-1] = '\0';
4083 #endif
4084           archive_string_sprintf(&info,
4085               "INFO %s%s", buf, archive_version_string());
4086           if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)
4087                     set_option_info(&info, &opt, "abstract-file",
4088                         KEY_STR, iso9660->abstract_file_identifier.s);
4089           if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)
4090                     set_option_info(&info, &opt, "application-id",
4091                         KEY_STR, iso9660->application_identifier.s);
4092           if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)
4093                     set_option_info(&info, &opt, "allow-vernum",
4094                         KEY_FLG, iso9660->opt.allow_vernum);
4095           if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)
4096                     set_option_info(&info, &opt, "biblio-file",
4097                         KEY_STR, iso9660->bibliographic_file_identifier.s);
4098           if (iso9660->opt.boot != OPT_BOOT_DEFAULT)
4099                     set_option_info(&info, &opt, "boot",
4100                         KEY_STR, iso9660->el_torito.boot_filename.s);
4101           if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)
4102                     set_option_info(&info, &opt, "boot-catalog",
4103                         KEY_STR, iso9660->el_torito.catalog_filename.s);
4104           if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)
4105                     set_option_info(&info, &opt, "boot-info-table",
4106                         KEY_FLG, iso9660->opt.boot_info_table);
4107           if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)
4108                     set_option_info(&info, &opt, "boot-load-seg",
4109                         KEY_HEX, iso9660->el_torito.boot_load_seg);
4110           if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)
4111                     set_option_info(&info, &opt, "boot-load-size",
4112                         KEY_INT, iso9660->el_torito.boot_load_size);
4113           if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {
4114                     v = "no-emulation";
4115                     if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)
4116                               v = "fd";
4117                     if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)
4118                               v = "hard-disk";
4119                     set_option_info(&info, &opt, "boot-type",
4120                         KEY_STR, v);
4121           }
4122 #ifdef HAVE_ZLIB_H
4123           if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)
4124                     set_option_info(&info, &opt, "compression-level",
4125                         KEY_INT, iso9660->zisofs.compression_level);
4126 #endif
4127           if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)
4128                     set_option_info(&info, &opt, "copyright-file",
4129                         KEY_STR, iso9660->copyright_file_identifier.s);
4130           if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)
4131                     set_option_info(&info, &opt, "iso-level",
4132                         KEY_INT, iso9660->opt.iso_level);
4133           if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {
4134                     if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
4135                               set_option_info(&info, &opt, "joliet",
4136                                   KEY_STR, "long");
4137                     else
4138                               set_option_info(&info, &opt, "joliet",
4139                                   KEY_FLG, iso9660->opt.joliet);
4140           }
4141           if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)
4142                     set_option_info(&info, &opt, "limit-depth",
4143                         KEY_FLG, iso9660->opt.limit_depth);
4144           if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)
4145                     set_option_info(&info, &opt, "limit-dirs",
4146                         KEY_FLG, iso9660->opt.limit_dirs);
4147           if (iso9660->opt.pad != OPT_PAD_DEFAULT)
4148                     set_option_info(&info, &opt, "pad",
4149                         KEY_FLG, iso9660->opt.pad);
4150           if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)
4151                     set_option_info(&info, &opt, "publisher",
4152                         KEY_STR, iso9660->publisher_identifier.s);
4153           if (iso9660->opt.rr != OPT_RR_DEFAULT) {
4154                     if (iso9660->opt.rr == OPT_RR_DISABLED)
4155                               set_option_info(&info, &opt, "rockridge",
4156                                   KEY_FLG, iso9660->opt.rr);
4157                     else if (iso9660->opt.rr == OPT_RR_STRICT)
4158                               set_option_info(&info, &opt, "rockridge",
4159                                   KEY_STR, "strict");
4160                     else if (iso9660->opt.rr == OPT_RR_USEFUL)
4161                               set_option_info(&info, &opt, "rockridge",
4162                                   KEY_STR, "useful");
4163           }
4164           if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)
4165                     set_option_info(&info, &opt, "volume-id",
4166                         KEY_STR, iso9660->volume_identifier.s);
4167           if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)
4168                     set_option_info(&info, &opt, "zisofs",
4169                         KEY_FLG, iso9660->opt.zisofs);
4170 
4171           memcpy(wb_buffptr(a), info.s, info_size);
4172           archive_string_free(&info);
4173           return (wb_consume(a, info_size));
4174 }
4175 
4176 static int
write_rr_ER(struct archive_write * a)4177 write_rr_ER(struct archive_write *a)
4178 {
4179           unsigned char *p;
4180 
4181           p = wb_buffptr(a);
4182 
4183           memset(p, 0, LOGICAL_BLOCK_SIZE);
4184           p[0] = 'E';
4185           p[1] = 'R';
4186           p[3] = 0x01;
4187           p[2] = RRIP_ER_SIZE;
4188           p[4] = RRIP_ER_ID_SIZE;
4189           p[5] = RRIP_ER_DSC_SIZE;
4190           p[6] = RRIP_ER_SRC_SIZE;
4191           p[7] = 0x01;
4192           memcpy(&p[8], rrip_identifier, p[4]);
4193           memcpy(&p[8+p[4]], rrip_descriptor, p[5]);
4194           memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);
4195 
4196           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4197 }
4198 
4199 static void
calculate_path_table_size(struct vdd * vdd)4200 calculate_path_table_size(struct vdd *vdd)
4201 {
4202           int depth, size;
4203           struct path_table *pt;
4204 
4205           pt = vdd->pathtbl;
4206           size = 0;
4207           for (depth = 0; depth < vdd->max_depth; depth++) {
4208                     struct isoent **ptbl;
4209                     int i, cnt;
4210 
4211                     if ((cnt = pt[depth].cnt) == 0)
4212                               break;
4213 
4214                     ptbl = pt[depth].sorted;
4215                     for (i = 0; i < cnt; i++) {
4216                               int len;
4217 
4218                               if (ptbl[i]->identifier == NULL)
4219                                         len = 1; /* root directory */
4220                               else
4221                                         len = ptbl[i]->id_len;
4222                               if (len & 0x01)
4223                                         len++; /* Padding Field */
4224                               size += 8 + len;
4225                     }
4226           }
4227           vdd->path_table_size = size;
4228           vdd->path_table_block =
4229               ((size + PATH_TABLE_BLOCK_SIZE -1) /
4230               PATH_TABLE_BLOCK_SIZE) *
4231               (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);
4232 }
4233 
4234 static int
_write_path_table(struct archive_write * a,int type_m,int depth,struct vdd * vdd)4235 _write_path_table(struct archive_write *a, int type_m, int depth,
4236     struct vdd *vdd)
4237 {
4238           unsigned char *bp, *wb;
4239           struct isoent **ptbl;
4240           size_t wbremaining;
4241           int i, r, wsize;
4242 
4243           if (vdd->pathtbl[depth].cnt == 0)
4244                     return (0);
4245 
4246           wsize = 0;
4247           wb = wb_buffptr(a);
4248           wbremaining = wb_remaining(a);
4249           bp = wb - 1;
4250           ptbl = vdd->pathtbl[depth].sorted;
4251           for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {
4252                     struct isoent *np;
4253                     size_t len;
4254 
4255                     np = ptbl[i];
4256                     if (np->identifier == NULL)
4257                               len = 1; /* root directory */
4258                     else
4259                               len = np->id_len;
4260                     if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {
4261                               r = wb_consume(a, (bp+1) - wb);
4262                               if (r < 0)
4263                                         return (r);
4264                               wb = wb_buffptr(a);
4265                               wbremaining = wb_remaining(a);
4266                               bp = wb -1;
4267                     }
4268                     /* Length of Directory Identifier */
4269                     set_num_711(bp+1, (unsigned char)len);
4270                     /* Extended Attribute Record Length */
4271                     set_num_711(bp+2, 0);
4272                     /* Location of Extent */
4273                     if (type_m)
4274                               set_num_732(bp+3, np->dir_location);
4275                     else
4276                               set_num_731(bp+3, np->dir_location);
4277                     /* Parent Directory Number */
4278                     if (type_m)
4279                               set_num_722(bp+7, np->parent->dir_number);
4280                     else
4281                               set_num_721(bp+7, np->parent->dir_number);
4282                     /* Directory Identifier */
4283                     if (np->identifier == NULL)
4284                               bp[9] = 0;
4285                     else
4286                               memcpy(&bp[9], np->identifier, len);
4287                     if (len & 0x01) {
4288                               /* Padding Field */
4289                               bp[9+len] = 0;
4290                               len++;
4291                     }
4292                     wsize += 8 + (int)len;
4293                     bp += 8 + len;
4294           }
4295           if ((bp + 1) > wb) {
4296                     r = wb_consume(a, (bp+1)-wb);
4297                     if (r < 0)
4298                               return (r);
4299           }
4300           return (wsize);
4301 }
4302 
4303 static int
write_path_table(struct archive_write * a,int type_m,struct vdd * vdd)4304 write_path_table(struct archive_write *a, int type_m, struct vdd *vdd)
4305 {
4306           int depth, r;
4307           size_t path_table_size;
4308 
4309           r = ARCHIVE_OK;
4310           path_table_size = 0;
4311           for (depth = 0; depth < vdd->max_depth; depth++) {
4312                     r = _write_path_table(a, type_m, depth, vdd);
4313                     if (r < 0)
4314                               return (r);
4315                     path_table_size += r;
4316           }
4317 
4318           /* Write padding data. */
4319           path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;
4320           if (path_table_size > 0)
4321                     r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);
4322           return (r);
4323 }
4324 
4325 static int
calculate_directory_descriptors(struct iso9660 * iso9660,struct vdd * vdd,struct isoent * isoent,int depth)4326 calculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,
4327     struct isoent *isoent, int depth)
4328 {
4329           struct isoent **enttbl;
4330           int bs, block, i;
4331 
4332           block = 1;
4333           bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);
4334           bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);
4335 
4336           if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
4337               !iso9660->opt.rr && depth + 1 >= vdd->max_depth))
4338                     return (block);
4339 
4340           enttbl = isoent->children_sorted;
4341           for (i = 0; i < isoent->children.cnt; i++) {
4342                     struct isoent *np = enttbl[i];
4343                     struct isofile *file;
4344 
4345                     file = np->file;
4346                     if (file->hardlink_target != NULL)
4347                               file = file->hardlink_target;
4348                     file->cur_content = &(file->content);
4349                     do {
4350                               int dr_l;
4351 
4352                               dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,
4353                                   vdd->vdd_type);
4354                               if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {
4355                                         block ++;
4356                                         bs = dr_l;
4357                               } else
4358                                         bs += dr_l;
4359                               file->cur_content = file->cur_content->next;
4360                     } while (file->cur_content != NULL);
4361           }
4362           return (block);
4363 }
4364 
4365 static int
_write_directory_descriptors(struct archive_write * a,struct vdd * vdd,struct isoent * isoent,int depth)4366 _write_directory_descriptors(struct archive_write *a, struct vdd *vdd,
4367     struct isoent *isoent, int depth)
4368 {
4369           struct iso9660 *iso9660 = a->format_data;
4370           struct isoent **enttbl;
4371           unsigned char *p, *wb;
4372           int i, r;
4373           int dr_l;
4374 
4375           p = wb = wb_buffptr(a);
4376 #define WD_REMAINING          (LOGICAL_BLOCK_SIZE - (p - wb))
4377           p += set_directory_record(p, WD_REMAINING, isoent,
4378               iso9660, DIR_REC_SELF, vdd->vdd_type);
4379           p += set_directory_record(p, WD_REMAINING, isoent,
4380               iso9660, DIR_REC_PARENT, vdd->vdd_type);
4381 
4382           if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
4383               !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {
4384                     memset(p, 0, WD_REMAINING);
4385                     return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4386           }
4387 
4388           enttbl = isoent->children_sorted;
4389           for (i = 0; i < isoent->children.cnt; i++) {
4390                     struct isoent *np = enttbl[i];
4391                     struct isofile *file = np->file;
4392 
4393                     if (file->hardlink_target != NULL)
4394                               file = file->hardlink_target;
4395                     file->cur_content = &(file->content);
4396                     do {
4397                               dr_l = set_directory_record(p, WD_REMAINING,
4398                                   np, iso9660, DIR_REC_NORMAL,
4399                                   vdd->vdd_type);
4400                               if (dr_l == 0) {
4401                                         memset(p, 0, WD_REMAINING);
4402                                         r = wb_consume(a, LOGICAL_BLOCK_SIZE);
4403                                         if (r < 0)
4404                                                   return (r);
4405                                         p = wb = wb_buffptr(a);
4406                                         dr_l = set_directory_record(p,
4407                                             WD_REMAINING, np, iso9660,
4408                                             DIR_REC_NORMAL, vdd->vdd_type);
4409                               }
4410                               p += dr_l;
4411                               file->cur_content = file->cur_content->next;
4412                     } while (file->cur_content != NULL);
4413           }
4414           memset(p, 0, WD_REMAINING);
4415           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
4416 }
4417 
4418 static int
write_directory_descriptors(struct archive_write * a,struct vdd * vdd)4419 write_directory_descriptors(struct archive_write *a, struct vdd *vdd)
4420 {
4421           struct isoent *np;
4422           int depth, r;
4423 
4424           depth = 0;
4425           np = vdd->rootent;
4426           do {
4427                     struct extr_rec *extr;
4428 
4429                     r = _write_directory_descriptors(a, vdd, np, depth);
4430                     if (r < 0)
4431                               return (r);
4432                     if (vdd->vdd_type != VDD_JOLIET) {
4433                               /*
4434                                * This extract record is used by SUSP,RRIP.
4435                                * Not for joliet.
4436                                */
4437                               for (extr = np->extr_rec_list.first;
4438                                   extr != NULL;
4439                                   extr = extr->next) {
4440                                         unsigned char *wb;
4441 
4442                                         wb = wb_buffptr(a);
4443                                         memcpy(wb, extr->buf, extr->offset);
4444                                         memset(wb + extr->offset, 0,
4445                                             LOGICAL_BLOCK_SIZE - extr->offset);
4446                                         r = wb_consume(a, LOGICAL_BLOCK_SIZE);
4447                                         if (r < 0)
4448                                                   return (r);
4449                               }
4450                     }
4451 
4452                     if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
4453                               /* Enter to sub directories. */
4454                               np = np->subdirs.first;
4455                               depth++;
4456                               continue;
4457                     }
4458                     while (np != np->parent) {
4459                               if (np->drnext == NULL) {
4460                                         /* Return to the parent directory. */
4461                                         np = np->parent;
4462                                         depth--;
4463                               } else {
4464                                         np = np->drnext;
4465                                         break;
4466                               }
4467                     }
4468           } while (np != np->parent);
4469 
4470           return (ARCHIVE_OK);
4471 }
4472 
4473 /*
4474  * Read file contents from the temporary file, and write it.
4475  */
4476 static int
write_file_contents(struct archive_write * a,int64_t offset,int64_t size)4477 write_file_contents(struct archive_write *a, int64_t offset, int64_t size)
4478 {
4479           struct iso9660 *iso9660 = a->format_data;
4480           int r;
4481 
4482           lseek(iso9660->temp_fd, offset, SEEK_SET);
4483 
4484           while (size) {
4485                     size_t rsize;
4486                     ssize_t rs;
4487                     unsigned char *wb;
4488 
4489                     wb = wb_buffptr(a);
4490                     rsize = wb_remaining(a);
4491                     if (rsize > (size_t)size)
4492                               rsize = (size_t)size;
4493                     rs = read(iso9660->temp_fd, wb, rsize);
4494                     if (rs <= 0) {
4495                               archive_set_error(&a->archive, errno,
4496                                   "Can't read temporary file(%jd)", (intmax_t)rs);
4497                               return (ARCHIVE_FATAL);
4498                     }
4499                     size -= rs;
4500                     r = wb_consume(a, rs);
4501                     if (r < 0)
4502                               return (r);
4503           }
4504           return (ARCHIVE_OK);
4505 }
4506 
4507 static int
write_file_descriptors(struct archive_write * a)4508 write_file_descriptors(struct archive_write *a)
4509 {
4510           struct iso9660 *iso9660 = a->format_data;
4511           struct isofile *file;
4512           int64_t blocks, offset;
4513           int r;
4514 
4515           blocks = 0;
4516           offset = 0;
4517 
4518           /* Make the boot catalog contents, and write it. */
4519           if (iso9660->el_torito.catalog != NULL) {
4520                     r = make_boot_catalog(a);
4521                     if (r < 0)
4522                               return (r);
4523           }
4524 
4525           /* Write the boot file contents. */
4526           if (iso9660->el_torito.boot != NULL) {
4527                     file = iso9660->el_torito.boot->file;
4528                     blocks = file->content.blocks;
4529                     offset = file->content.offset_of_temp;
4530                     if (offset != 0) {
4531                               r = write_file_contents(a, offset,
4532                                   blocks << LOGICAL_BLOCK_BITS);
4533                               if (r < 0)
4534                                         return (r);
4535                               blocks = 0;
4536                               offset = 0;
4537                     }
4538           }
4539 
4540           /* Write out all file contents. */
4541           for (file = iso9660->data_file_list.first;
4542               file != NULL; file = file->datanext) {
4543 
4544                     if (!file->write_content)
4545                               continue;
4546 
4547                     if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <
4548                          file->content.offset_of_temp) {
4549                               if (blocks > 0) {
4550                                         r = write_file_contents(a, offset,
4551                                             blocks << LOGICAL_BLOCK_BITS);
4552                                         if (r < 0)
4553                                                   return (r);
4554                               }
4555                               blocks = 0;
4556                               offset = file->content.offset_of_temp;
4557                     }
4558 
4559                     file->cur_content = &(file->content);
4560                     do {
4561                               blocks += file->cur_content->blocks;
4562                               /* Next fragment */
4563                               file->cur_content = file->cur_content->next;
4564                     } while (file->cur_content != NULL);
4565           }
4566 
4567           /* Flush out remaining blocks. */
4568           if (blocks > 0) {
4569                     r = write_file_contents(a, offset,
4570                         blocks << LOGICAL_BLOCK_BITS);
4571                     if (r < 0)
4572                               return (r);
4573           }
4574 
4575           return (ARCHIVE_OK);
4576 }
4577 
4578 static void
isofile_init_entry_list(struct iso9660 * iso9660)4579 isofile_init_entry_list(struct iso9660 *iso9660)
4580 {
4581           iso9660->all_file_list.first = NULL;
4582           iso9660->all_file_list.last = &(iso9660->all_file_list.first);
4583 }
4584 
4585 static void
isofile_add_entry(struct iso9660 * iso9660,struct isofile * file)4586 isofile_add_entry(struct iso9660 *iso9660, struct isofile *file)
4587 {
4588           file->allnext = NULL;
4589           *iso9660->all_file_list.last = file;
4590           iso9660->all_file_list.last = &(file->allnext);
4591 }
4592 
4593 static void
isofile_free_all_entries(struct iso9660 * iso9660)4594 isofile_free_all_entries(struct iso9660 *iso9660)
4595 {
4596           struct isofile *file, *file_next;
4597 
4598           file = iso9660->all_file_list.first;
4599           while (file != NULL) {
4600                     file_next = file->allnext;
4601                     isofile_free(file);
4602                     file = file_next;
4603           }
4604 }
4605 
4606 static void
isofile_init_entry_data_file_list(struct iso9660 * iso9660)4607 isofile_init_entry_data_file_list(struct iso9660 *iso9660)
4608 {
4609           iso9660->data_file_list.first = NULL;
4610           iso9660->data_file_list.last = &(iso9660->data_file_list.first);
4611 }
4612 
4613 static void
isofile_add_data_file(struct iso9660 * iso9660,struct isofile * file)4614 isofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)
4615 {
4616           file->datanext = NULL;
4617           *iso9660->data_file_list.last = file;
4618           iso9660->data_file_list.last = &(file->datanext);
4619 }
4620 
4621 
4622 static struct isofile *
isofile_new(struct archive_write * a,struct archive_entry * entry)4623 isofile_new(struct archive_write *a, struct archive_entry *entry)
4624 {
4625           struct isofile *file;
4626 
4627           file = calloc(1, sizeof(*file));
4628           if (file == NULL)
4629                     return (NULL);
4630 
4631           if (entry != NULL)
4632                     file->entry = archive_entry_clone(entry);
4633           else
4634                     file->entry = archive_entry_new2(&a->archive);
4635           if (file->entry == NULL) {
4636                     free(file);
4637                     return (NULL);
4638           }
4639           archive_string_init(&(file->parentdir));
4640           archive_string_init(&(file->basename));
4641           archive_string_init(&(file->basename_utf16));
4642           archive_string_init(&(file->symlink));
4643           file->cur_content = &(file->content);
4644 
4645           return (file);
4646 }
4647 
4648 static void
isofile_free(struct isofile * file)4649 isofile_free(struct isofile *file)
4650 {
4651           struct content *con, *tmp;
4652 
4653           con = file->content.next;
4654           while (con != NULL) {
4655                     tmp = con;
4656                     con = con->next;
4657                     free(tmp);
4658           }
4659           archive_entry_free(file->entry);
4660           archive_string_free(&(file->parentdir));
4661           archive_string_free(&(file->basename));
4662           archive_string_free(&(file->basename_utf16));
4663           archive_string_free(&(file->symlink));
4664           free(file);
4665 }
4666 
4667 #if defined(_WIN32) || defined(__CYGWIN__)
4668 static int
cleanup_backslash_1(char * p)4669 cleanup_backslash_1(char *p)
4670 {
4671           int mb, dos;
4672 
4673           mb = dos = 0;
4674           while (*p) {
4675                     if (*(unsigned char *)p > 127)
4676                               mb = 1;
4677                     if (*p == '\\') {
4678                               /* If we have not met any multi-byte characters,
4679                                * we can replace '\' with '/'. */
4680                               if (!mb)
4681                                         *p = '/';
4682                               dos = 1;
4683                     }
4684                     p++;
4685           }
4686           if (!mb || !dos)
4687                     return (0);
4688           return (-1);
4689 }
4690 
4691 static void
cleanup_backslash_2(wchar_t * p)4692 cleanup_backslash_2(wchar_t *p)
4693 {
4694 
4695           /* Convert a path-separator from '\' to  '/' */
4696           while (*p != L'\0') {
4697                     if (*p == L'\\')
4698                               *p = L'/';
4699                     p++;
4700           }
4701 }
4702 #endif
4703 
4704 /*
4705  * Generate a parent directory name and a base name from a pathname.
4706  */
4707 static int
isofile_gen_utility_names(struct archive_write * a,struct isofile * file)4708 isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
4709 {
4710           struct iso9660 *iso9660;
4711           const char *pathname;
4712           char *p, *dirname, *slash;
4713           size_t len;
4714           int ret = ARCHIVE_OK;
4715 
4716           iso9660 = a->format_data;
4717 
4718           archive_string_empty(&(file->parentdir));
4719           archive_string_empty(&(file->basename));
4720           archive_string_empty(&(file->basename_utf16));
4721           archive_string_empty(&(file->symlink));
4722 
4723           pathname =  archive_entry_pathname(file->entry);
4724           if (pathname == NULL || pathname[0] == '\0') {/* virtual root */
4725                     file->dircnt = 0;
4726                     return (ret);
4727           }
4728 
4729           /*
4730            * Make a UTF-16BE basename if Joliet extension enabled.
4731            */
4732           if (iso9660->opt.joliet) {
4733                     const char *u16, *ulast;
4734                     size_t u16len, ulen_last;
4735 
4736                     if (iso9660->sconv_to_utf16be == NULL) {
4737                               iso9660->sconv_to_utf16be =
4738                                   archive_string_conversion_to_charset(
4739                                         &(a->archive), "UTF-16BE", 1);
4740                               if (iso9660->sconv_to_utf16be == NULL)
4741                                         /* Couldn't allocate memory */
4742                                         return (ARCHIVE_FATAL);
4743                               iso9660->sconv_from_utf16be =
4744                                   archive_string_conversion_from_charset(
4745                                         &(a->archive), "UTF-16BE", 1);
4746                               if (iso9660->sconv_from_utf16be == NULL)
4747                                         /* Couldn't allocate memory */
4748                                         return (ARCHIVE_FATAL);
4749                     }
4750 
4751                     /*
4752                      * Convert a filename to UTF-16BE.
4753                      */
4754                     if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
4755                         iso9660->sconv_to_utf16be)) {
4756                               if (errno == ENOMEM) {
4757                                         archive_set_error(&a->archive, ENOMEM,
4758                                             "Can't allocate memory for UTF-16BE");
4759                                         return (ARCHIVE_FATAL);
4760                               }
4761                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4762                                   "A filename cannot be converted to UTF-16BE;"
4763                                   "You should disable making Joliet extension");
4764                               ret = ARCHIVE_WARN;
4765                     }
4766 
4767                     /*
4768                      * Make sure a path separator is not in the last;
4769                      * Remove trailing '/'.
4770                      */
4771                     while (u16len >= 2) {
4772 #if defined(_WIN32) || defined(__CYGWIN__)
4773                               if (u16[u16len-2] == 0 &&
4774                                   (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))
4775 #else
4776                               if (u16[u16len-2] == 0 && u16[u16len-1] == '/')
4777 #endif
4778                               {
4779                                         u16len -= 2;
4780                               } else
4781                                         break;
4782                     }
4783 
4784                     /*
4785                      * Find a basename in UTF-16BE.
4786                      */
4787                     ulast = u16;
4788                     u16len >>= 1;
4789                     ulen_last = u16len;
4790                     while (u16len > 0) {
4791 #if defined(_WIN32) || defined(__CYGWIN__)
4792                               if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))
4793 #else
4794                               if (u16[0] == 0 && u16[1] == '/')
4795 #endif
4796                               {
4797                                         ulast = u16 + 2;
4798                                         ulen_last = u16len -1;
4799                               }
4800                               u16 += 2;
4801                               u16len --;
4802                     }
4803                     ulen_last <<= 1;
4804                     if (archive_string_ensure(&(file->basename_utf16),
4805                         ulen_last) == NULL) {
4806                               archive_set_error(&a->archive, ENOMEM,
4807                                   "Can't allocate memory for UTF-16BE");
4808                               return (ARCHIVE_FATAL);
4809                     }
4810 
4811                     /*
4812                      * Set UTF-16BE basename.
4813                      */
4814                     memcpy(file->basename_utf16.s, ulast, ulen_last);
4815                     file->basename_utf16.length = ulen_last;
4816           }
4817 
4818           archive_strcpy(&(file->parentdir), pathname);
4819 #if defined(_WIN32) || defined(__CYGWIN__)
4820           /*
4821            * Convert a path-separator from '\' to  '/'
4822            */
4823           if (cleanup_backslash_1(file->parentdir.s) != 0) {
4824                     const wchar_t *wp = archive_entry_pathname_w(file->entry);
4825                     struct archive_wstring ws;
4826 
4827                     if (wp != NULL) {
4828                               int r;
4829                               archive_string_init(&ws);
4830                               archive_wstrcpy(&ws, wp);
4831                               cleanup_backslash_2(ws.s);
4832                               archive_string_empty(&(file->parentdir));
4833                               r = archive_string_append_from_wcs(&(file->parentdir),
4834                                   ws.s, ws.length);
4835                               archive_wstring_free(&ws);
4836                               if (r < 0 && errno == ENOMEM) {
4837                                         archive_set_error(&a->archive, ENOMEM,
4838                                             "Can't allocate memory");
4839                                         return (ARCHIVE_FATAL);
4840                               }
4841                     }
4842           }
4843 #endif
4844 
4845           len = file->parentdir.length;
4846           p = dirname = file->parentdir.s;
4847 
4848           /*
4849            * Remove leading '/', '../' and './' elements
4850            */
4851           while (*p) {
4852                     if (p[0] == '/') {
4853                               p++;
4854                               len--;
4855                     } else if (p[0] != '.')
4856                               break;
4857                     else if (p[1] == '.' && p[2] == '/') {
4858                               p += 3;
4859                               len -= 3;
4860                     } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
4861                               p += 2;
4862                               len -= 2;
4863                     } else if (p[1] == '\0') {
4864                               p++;
4865                               len--;
4866                     } else
4867                               break;
4868           }
4869           if (p != dirname) {
4870                     memmove(dirname, p, len+1);
4871                     p = dirname;
4872           }
4873           /*
4874            * Remove "/","/." and "/.." elements from tail.
4875            */
4876           while (len > 0) {
4877                     size_t ll = len;
4878 
4879                     if (len > 0 && p[len-1] == '/') {
4880                               p[len-1] = '\0';
4881                               len--;
4882                     }
4883                     if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
4884                               p[len-2] = '\0';
4885                               len -= 2;
4886                     }
4887                     if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
4888                         p[len-1] == '.') {
4889                               p[len-3] = '\0';
4890                               len -= 3;
4891                     }
4892                     if (ll == len)
4893                               break;
4894           }
4895           while (*p) {
4896                     if (p[0] == '/') {
4897                               if (p[1] == '/')
4898                                         /* Convert '//' --> '/' */
4899                                         memmove(p, p+1, strlen(p+1) + 1);
4900                               else if (p[1] == '.' && p[2] == '/')
4901                                         /* Convert '/./' --> '/' */
4902                                         memmove(p, p+2, strlen(p+2) + 1);
4903                               else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
4904                                         /* Convert 'dir/dir1/../dir2/'
4905                                          *     --> 'dir/dir2/'
4906                                          */
4907                                         char *rp = p -1;
4908                                         while (rp >= dirname) {
4909                                                   if (*rp == '/')
4910                                                             break;
4911                                                   --rp;
4912                                         }
4913                                         if (rp > dirname) {
4914                                                   strcpy(rp, p+3);
4915                                                   p = rp;
4916                                         } else {
4917                                                   strcpy(dirname, p+4);
4918                                                   p = dirname;
4919                                         }
4920                               } else
4921                                         p++;
4922                     } else
4923                               p++;
4924           }
4925           p = dirname;
4926           len = strlen(p);
4927 
4928           if (archive_entry_filetype(file->entry) == AE_IFLNK) {
4929                     /* Convert symlink name too. */
4930                     pathname = archive_entry_symlink(file->entry);
4931                     archive_strcpy(&(file->symlink),  pathname);
4932 #if defined(_WIN32) || defined(__CYGWIN__)
4933                     /*
4934                      * Convert a path-separator from '\' to  '/'
4935                      */
4936                     if (archive_strlen(&(file->symlink)) > 0 &&
4937                         cleanup_backslash_1(file->symlink.s) != 0) {
4938                               const wchar_t *wp =
4939                                   archive_entry_symlink_w(file->entry);
4940                               struct archive_wstring ws;
4941 
4942                               if (wp != NULL) {
4943                                         int r;
4944                                         archive_string_init(&ws);
4945                                         archive_wstrcpy(&ws, wp);
4946                                         cleanup_backslash_2(ws.s);
4947                                         archive_string_empty(&(file->symlink));
4948                                         r = archive_string_append_from_wcs(
4949                                             &(file->symlink),
4950                                             ws.s, ws.length);
4951                                         archive_wstring_free(&ws);
4952                                         if (r < 0 && errno == ENOMEM) {
4953                                                   archive_set_error(&a->archive, ENOMEM,
4954                                                       "Can't allocate memory");
4955                                                   return (ARCHIVE_FATAL);
4956                                         }
4957                               }
4958                     }
4959 #endif
4960           }
4961           /*
4962            * - Count up directory elements.
4963            * - Find out the position which points the last position of
4964            *   path separator('/').
4965            */
4966           slash = NULL;
4967           file->dircnt = 0;
4968           for (; *p != '\0'; p++)
4969                     if (*p == '/') {
4970                               slash = p;
4971                               file->dircnt++;
4972                     }
4973           if (slash == NULL) {
4974                     /* The pathname doesn't have a parent directory. */
4975                     file->parentdir.length = len;
4976                     archive_string_copy(&(file->basename), &(file->parentdir));
4977                     archive_string_empty(&(file->parentdir));
4978                     *file->parentdir.s = '\0';
4979                     return (ret);
4980           }
4981 
4982           /* Make a basename from dirname and slash */
4983           *slash  = '\0';
4984           file->parentdir.length = slash - dirname;
4985           archive_strcpy(&(file->basename),  slash + 1);
4986           if (archive_entry_filetype(file->entry) == AE_IFDIR)
4987                     file->dircnt ++;
4988           return (ret);
4989 }
4990 
4991 /*
4992  * Register a entry to get a hardlink target.
4993  */
4994 static int
isofile_register_hardlink(struct archive_write * a,struct isofile * file)4995 isofile_register_hardlink(struct archive_write *a, struct isofile *file)
4996 {
4997           struct iso9660 *iso9660 = a->format_data;
4998           struct hardlink *hl;
4999           const char *pathname;
5000 
5001           archive_entry_set_nlink(file->entry, 1);
5002           pathname = archive_entry_hardlink(file->entry);
5003           if (pathname == NULL) {
5004                     /* This `file` is a hardlink target. */
5005                     hl = malloc(sizeof(*hl));
5006                     if (hl == NULL) {
5007                               archive_set_error(&a->archive, ENOMEM,
5008                                   "Can't allocate memory");
5009                               return (ARCHIVE_FATAL);
5010                     }
5011                     hl->nlink = 1;
5012                     /* A hardlink target must be the first position. */
5013                     file->hlnext = NULL;
5014                     hl->file_list.first = file;
5015                     hl->file_list.last = &(file->hlnext);
5016                     __archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),
5017                         (struct archive_rb_node *)hl);
5018           } else {
5019                     hl = (struct hardlink *)__archive_rb_tree_find_node(
5020                         &(iso9660->hardlink_rbtree), pathname);
5021                     if (hl != NULL) {
5022                               /* Insert `file` entry into the tail. */
5023                               file->hlnext = NULL;
5024                               *hl->file_list.last = file;
5025                               hl->file_list.last = &(file->hlnext);
5026                               hl->nlink++;
5027                     }
5028                     archive_entry_unset_size(file->entry);
5029           }
5030 
5031           return (ARCHIVE_OK);
5032 }
5033 
5034 /*
5035  * Hardlinked files have to have the same location of extent.
5036  * We have to find out hardlink target entries for the entries
5037  * which have a hardlink target name.
5038  */
5039 static void
isofile_connect_hardlink_files(struct iso9660 * iso9660)5040 isofile_connect_hardlink_files(struct iso9660 *iso9660)
5041 {
5042           struct archive_rb_node *n;
5043           struct hardlink *hl;
5044           struct isofile *target, *nf;
5045 
5046           ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {
5047                     hl = (struct hardlink *)n;
5048 
5049                     /* The first entry must be a hardlink target. */
5050                     target = hl->file_list.first;
5051                     archive_entry_set_nlink(target->entry, hl->nlink);
5052                     /* Set a hardlink target to reference entries. */
5053                     for (nf = target->hlnext;
5054                         nf != NULL; nf = nf->hlnext) {
5055                               nf->hardlink_target = target;
5056                               archive_entry_set_nlink(nf->entry, hl->nlink);
5057                     }
5058           }
5059 }
5060 
5061 static int
isofile_hd_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)5062 isofile_hd_cmp_node(const struct archive_rb_node *n1,
5063     const struct archive_rb_node *n2)
5064 {
5065           const struct hardlink *h1 = (const struct hardlink *)n1;
5066           const struct hardlink *h2 = (const struct hardlink *)n2;
5067 
5068           return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
5069                            archive_entry_pathname(h2->file_list.first->entry)));
5070 }
5071 
5072 static int
isofile_hd_cmp_key(const struct archive_rb_node * n,const void * key)5073 isofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
5074 {
5075           const struct hardlink *h = (const struct hardlink *)n;
5076 
5077           return (strcmp(archive_entry_pathname(h->file_list.first->entry),
5078                            (const char *)key));
5079 }
5080 
5081 static void
isofile_init_hardlinks(struct iso9660 * iso9660)5082 isofile_init_hardlinks(struct iso9660 *iso9660)
5083 {
5084           static const struct archive_rb_tree_ops rb_ops = {
5085                     isofile_hd_cmp_node, isofile_hd_cmp_key,
5086           };
5087 
5088           __archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);
5089 }
5090 
5091 static void
isofile_free_hardlinks(struct iso9660 * iso9660)5092 isofile_free_hardlinks(struct iso9660 *iso9660)
5093 {
5094           struct archive_rb_node *n, *tmp;
5095 
5096           ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(iso9660->hardlink_rbtree), tmp) {
5097                     __archive_rb_tree_remove_node(&(iso9660->hardlink_rbtree), n);
5098                     free(n);
5099           }
5100 }
5101 
5102 static struct isoent *
isoent_new(struct isofile * file)5103 isoent_new(struct isofile *file)
5104 {
5105           struct isoent *isoent;
5106           static const struct archive_rb_tree_ops rb_ops = {
5107                     isoent_cmp_node, isoent_cmp_key,
5108           };
5109 
5110           isoent = calloc(1, sizeof(*isoent));
5111           if (isoent == NULL)
5112                     return (NULL);
5113           isoent->file = file;
5114           isoent->children.first = NULL;
5115           isoent->children.last = &(isoent->children.first);
5116           __archive_rb_tree_init(&(isoent->rbtree), &rb_ops);
5117           isoent->subdirs.first = NULL;
5118           isoent->subdirs.last = &(isoent->subdirs.first);
5119           isoent->extr_rec_list.first = NULL;
5120           isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);
5121           isoent->extr_rec_list.current = NULL;
5122           if (archive_entry_filetype(file->entry) == AE_IFDIR)
5123                     isoent->dir = 1;
5124 
5125           return (isoent);
5126 }
5127 
5128 static inline struct isoent *
isoent_clone(struct isoent * src)5129 isoent_clone(struct isoent *src)
5130 {
5131           return (isoent_new(src->file));
5132 }
5133 
5134 static void
_isoent_free(struct isoent * isoent)5135 _isoent_free(struct isoent *isoent)
5136 {
5137           struct extr_rec *er, *er_next;
5138 
5139           free(isoent->children_sorted);
5140           free(isoent->identifier);
5141           er = isoent->extr_rec_list.first;
5142           while (er != NULL) {
5143                     er_next = er->next;
5144                     free(er);
5145                     er = er_next;
5146           }
5147           free(isoent);
5148 }
5149 
5150 static void
isoent_free_all(struct isoent * isoent)5151 isoent_free_all(struct isoent *isoent)
5152 {
5153           struct isoent *np, *np_temp;
5154 
5155           if (isoent == NULL)
5156                     return;
5157           np = isoent;
5158           for (;;) {
5159                     if (np->dir) {
5160                               if (np->children.first != NULL) {
5161                                         /* Enter to sub directories. */
5162                                         np = np->children.first;
5163                                         continue;
5164                               }
5165                     }
5166                     for (;;) {
5167                               np_temp = np;
5168                               if (np->chnext == NULL) {
5169                                         /* Return to the parent directory. */
5170                                         np = np->parent;
5171                                         _isoent_free(np_temp);
5172                                         if (np == np_temp)
5173                                                   return;
5174                               } else {
5175                                         np = np->chnext;
5176                                         _isoent_free(np_temp);
5177                                         break;
5178                               }
5179                     }
5180           }
5181 }
5182 
5183 static struct isoent *
isoent_create_virtual_dir(struct archive_write * a,struct iso9660 * iso9660,const char * pathname)5184 isoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)
5185 {
5186           struct isofile *file;
5187           struct isoent *isoent;
5188 
5189           file = isofile_new(a, NULL);
5190           if (file == NULL)
5191                     return (NULL);
5192           archive_entry_set_pathname(file->entry, pathname);
5193           archive_entry_unset_mtime(file->entry);
5194           archive_entry_unset_atime(file->entry);
5195           archive_entry_unset_ctime(file->entry);
5196           archive_entry_set_uid(file->entry, getuid());
5197           archive_entry_set_gid(file->entry, getgid());
5198           archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
5199           archive_entry_set_nlink(file->entry, 2);
5200           if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
5201                     isofile_free(file);
5202                     return (NULL);
5203           }
5204           isofile_add_entry(iso9660, file);
5205 
5206           isoent = isoent_new(file);
5207           if (isoent == NULL)
5208                     return (NULL);
5209           isoent->dir = 1;
5210           isoent->virtual = 1;
5211 
5212           return (isoent);
5213 }
5214 
5215 static int
isoent_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)5216 isoent_cmp_node(const struct archive_rb_node *n1,
5217     const struct archive_rb_node *n2)
5218 {
5219           const struct isoent *e1 = (const struct isoent *)n1;
5220           const struct isoent *e2 = (const struct isoent *)n2;
5221 
5222           return (strcmp(e1->file->basename.s, e2->file->basename.s));
5223 }
5224 
5225 static int
isoent_cmp_key(const struct archive_rb_node * n,const void * key)5226 isoent_cmp_key(const struct archive_rb_node *n, const void *key)
5227 {
5228           const struct isoent *e = (const struct isoent *)n;
5229 
5230           return (strcmp(e->file->basename.s, (const char *)key));
5231 }
5232 
5233 static int
isoent_add_child_head(struct isoent * parent,struct isoent * child)5234 isoent_add_child_head(struct isoent *parent, struct isoent *child)
5235 {
5236 
5237           if (!__archive_rb_tree_insert_node(
5238               &(parent->rbtree), (struct archive_rb_node *)child))
5239                     return (0);
5240           if ((child->chnext = parent->children.first) == NULL)
5241                     parent->children.last = &(child->chnext);
5242           parent->children.first = child;
5243           parent->children.cnt++;
5244           child->parent = parent;
5245 
5246           /* Add a child to a sub-directory chain */
5247           if (child->dir) {
5248                     if ((child->drnext = parent->subdirs.first) == NULL)
5249                               parent->subdirs.last = &(child->drnext);
5250                     parent->subdirs.first = child;
5251                     parent->subdirs.cnt++;
5252                     child->parent = parent;
5253           } else
5254                     child->drnext = NULL;
5255           return (1);
5256 }
5257 
5258 static int
isoent_add_child_tail(struct isoent * parent,struct isoent * child)5259 isoent_add_child_tail(struct isoent *parent, struct isoent *child)
5260 {
5261 
5262           if (!__archive_rb_tree_insert_node(
5263               &(parent->rbtree), (struct archive_rb_node *)child))
5264                     return (0);
5265           child->chnext = NULL;
5266           *parent->children.last = child;
5267           parent->children.last = &(child->chnext);
5268           parent->children.cnt++;
5269           child->parent = parent;
5270 
5271           /* Add a child to a sub-directory chain */
5272           child->drnext = NULL;
5273           if (child->dir) {
5274                     *parent->subdirs.last = child;
5275                     parent->subdirs.last = &(child->drnext);
5276                     parent->subdirs.cnt++;
5277                     child->parent = parent;
5278           }
5279           return (1);
5280 }
5281 
5282 static void
isoent_remove_child(struct isoent * parent,struct isoent * child)5283 isoent_remove_child(struct isoent *parent, struct isoent *child)
5284 {
5285           struct isoent *ent;
5286 
5287           /* Remove a child entry from children chain. */
5288           ent = parent->children.first;
5289           while (ent->chnext != child)
5290                     ent = ent->chnext;
5291           if ((ent->chnext = ent->chnext->chnext) == NULL)
5292                     parent->children.last = &(ent->chnext);
5293           parent->children.cnt--;
5294 
5295           if (child->dir) {
5296                     /* Remove a child entry from sub-directory chain. */
5297                     ent = parent->subdirs.first;
5298                     while (ent->drnext != child)
5299                               ent = ent->drnext;
5300                     if ((ent->drnext = ent->drnext->drnext) == NULL)
5301                               parent->subdirs.last = &(ent->drnext);
5302                     parent->subdirs.cnt--;
5303           }
5304 
5305           __archive_rb_tree_remove_node(&(parent->rbtree),
5306               (struct archive_rb_node *)child);
5307 }
5308 
5309 static int
isoent_clone_tree(struct archive_write * a,struct isoent ** nroot,struct isoent * root)5310 isoent_clone_tree(struct archive_write *a, struct isoent **nroot,
5311     struct isoent *root)
5312 {
5313           struct isoent *np, *xroot, *newent;
5314 
5315           np = root;
5316           xroot = NULL;
5317           do {
5318                     newent = isoent_clone(np);
5319                     if (newent == NULL) {
5320                               archive_set_error(&a->archive, ENOMEM,
5321                                   "Can't allocate memory");
5322                               return (ARCHIVE_FATAL);
5323                     }
5324                     if (xroot == NULL) {
5325                               *nroot = xroot = newent;
5326                               newent->parent = xroot;
5327                     } else
5328                               isoent_add_child_tail(xroot, newent);
5329                     if (np->dir && np->children.first != NULL) {
5330                               /* Enter to sub directories. */
5331                               np = np->children.first;
5332                               xroot = newent;
5333                               continue;
5334                     }
5335                     while (np != np->parent) {
5336                               if (np->chnext == NULL) {
5337                                         /* Return to the parent directory. */
5338                                         np = np->parent;
5339                                         xroot = xroot->parent;
5340                               } else {
5341                                         np = np->chnext;
5342                                         break;
5343                               }
5344                     }
5345           } while (np != np->parent);
5346 
5347           return (ARCHIVE_OK);
5348 }
5349 
5350 /*
5351  * Setup directory locations.
5352  */
5353 static void
isoent_setup_directory_location(struct iso9660 * iso9660,int location,struct vdd * vdd)5354 isoent_setup_directory_location(struct iso9660 *iso9660, int location,
5355     struct vdd *vdd)
5356 {
5357           struct isoent *np;
5358           int depth;
5359 
5360           vdd->total_dir_block = 0;
5361           depth = 0;
5362           np = vdd->rootent;
5363           do {
5364                     int block;
5365 
5366                     np->dir_block = calculate_directory_descriptors(
5367                         iso9660, vdd, np, depth);
5368                     vdd->total_dir_block += np->dir_block;
5369                     np->dir_location = location;
5370                     location += np->dir_block;
5371                     block = extra_setup_location(np, location);
5372                     vdd->total_dir_block += block;
5373                     location += block;
5374 
5375                     if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
5376                               /* Enter to sub directories. */
5377                               np = np->subdirs.first;
5378                               depth++;
5379                               continue;
5380                     }
5381                     while (np != np->parent) {
5382                               if (np->drnext == NULL) {
5383                                         /* Return to the parent directory. */
5384                                         np = np->parent;
5385                                         depth--;
5386                               } else {
5387                                         np = np->drnext;
5388                                         break;
5389                               }
5390                     }
5391           } while (np != np->parent);
5392 }
5393 
5394 static void
_isoent_file_location(struct iso9660 * iso9660,struct isoent * isoent,int * symlocation)5395 _isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,
5396     int *symlocation)
5397 {
5398           struct isoent **children;
5399           int n;
5400 
5401           if (isoent->children.cnt == 0)
5402                     return;
5403 
5404           children = isoent->children_sorted;
5405           for (n = 0; n < isoent->children.cnt; n++) {
5406                     struct isoent *np;
5407                     struct isofile *file;
5408 
5409                     np = children[n];
5410                     if (np->dir)
5411                               continue;
5412                     if (np == iso9660->el_torito.boot)
5413                               continue;
5414                     file = np->file;
5415                     if (file->boot || file->hardlink_target != NULL)
5416                               continue;
5417                     if (archive_entry_filetype(file->entry) == AE_IFLNK ||
5418                         file->content.size == 0) {
5419                               /*
5420                                * Do not point a valid location.
5421                                * Make sure entry is not hardlink file.
5422                                */
5423                               file->content.location = (*symlocation)--;
5424                               continue;
5425                     }
5426 
5427                     file->write_content = 1;
5428           }
5429 }
5430 
5431 /*
5432  * Setup file locations.
5433  */
5434 static void
isoent_setup_file_location(struct iso9660 * iso9660,int location)5435 isoent_setup_file_location(struct iso9660 *iso9660, int location)
5436 {
5437           struct isoent *isoent;
5438           struct isoent *np;
5439           struct isofile *file;
5440           size_t size;
5441           int block;
5442           int depth;
5443           int joliet;
5444           int symlocation;
5445           int total_block;
5446 
5447           iso9660->total_file_block = 0;
5448           if ((isoent = iso9660->el_torito.catalog) != NULL) {
5449                     isoent->file->content.location = location;
5450                     block = (int)((archive_entry_size(isoent->file->entry) +
5451                         LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
5452                     location += block;
5453                     iso9660->total_file_block += block;
5454           }
5455           if ((isoent = iso9660->el_torito.boot) != NULL) {
5456                     isoent->file->content.location = location;
5457                     size = fd_boot_image_size(iso9660->el_torito.media_type);
5458                     if (size == 0)
5459                               size = (size_t)archive_entry_size(isoent->file->entry);
5460                     block = ((int)size + LOGICAL_BLOCK_SIZE -1)
5461                         >> LOGICAL_BLOCK_BITS;
5462                     location += block;
5463                     iso9660->total_file_block += block;
5464                     isoent->file->content.blocks = block;
5465           }
5466 
5467           depth = 0;
5468           symlocation = -16;
5469           if (!iso9660->opt.rr && iso9660->opt.joliet) {
5470                     joliet = 1;
5471                     np = iso9660->joliet.rootent;
5472           } else {
5473                     joliet = 0;
5474                     np = iso9660->primary.rootent;
5475           }
5476           do {
5477                     _isoent_file_location(iso9660, np, &symlocation);
5478 
5479                     if (np->subdirs.first != NULL &&
5480                         (joliet ||
5481                         ((iso9660->opt.rr == OPT_RR_DISABLED &&
5482                           depth + 2 < iso9660->primary.max_depth) ||
5483                          (iso9660->opt.rr &&
5484                           depth + 1 < iso9660->primary.max_depth)))) {
5485                               /* Enter to sub directories. */
5486                               np = np->subdirs.first;
5487                               depth++;
5488                               continue;
5489                     }
5490                     while (np != np->parent) {
5491                               if (np->drnext == NULL) {
5492                                         /* Return to the parent directory. */
5493                                         np = np->parent;
5494                                         depth--;
5495                               } else {
5496                                         np = np->drnext;
5497                                         break;
5498                               }
5499                     }
5500           } while (np != np->parent);
5501 
5502           total_block = 0;
5503           for (file = iso9660->data_file_list.first;
5504               file != NULL; file = file->datanext) {
5505 
5506                     if (!file->write_content)
5507                               continue;
5508 
5509                     file->cur_content = &(file->content);
5510                     do {
5511                               file->cur_content->location = location;
5512                               location += file->cur_content->blocks;
5513                               total_block += file->cur_content->blocks;
5514                               /* Next fragment */
5515                               file->cur_content = file->cur_content->next;
5516                     } while (file->cur_content != NULL);
5517           }
5518           iso9660->total_file_block += total_block;
5519 }
5520 
5521 static int
get_path_component(char * name,size_t n,const char * fn)5522 get_path_component(char *name, size_t n, const char *fn)
5523 {
5524           char *p;
5525           size_t l;
5526 
5527           p = strchr(fn, '/');
5528           if (p == NULL) {
5529                     if ((l = strlen(fn)) == 0)
5530                               return (0);
5531           } else
5532                     l = p - fn;
5533           if (l > n -1)
5534                     return (-1);
5535           memcpy(name, fn, l);
5536           name[l] = '\0';
5537 
5538           return ((int)l);
5539 }
5540 
5541 /*
5542  * Add a new entry into the tree.
5543  */
5544 static int
isoent_tree(struct archive_write * a,struct isoent ** isoentpp)5545 isoent_tree(struct archive_write *a, struct isoent **isoentpp)
5546 {
5547 #if defined(_WIN32) && !defined(__CYGWIN__)
5548           char name[_MAX_FNAME];/* Included null terminator size. */
5549 #elif defined(NAME_MAX) && NAME_MAX >= 255
5550           char name[NAME_MAX+1];
5551 #else
5552           char name[256];
5553 #endif
5554           struct iso9660 *iso9660 = a->format_data;
5555           struct isoent *dent, *isoent, *np;
5556           struct isofile *f1, *f2;
5557           const char *fn, *p;
5558           int l;
5559 
5560           isoent = *isoentpp;
5561           dent = iso9660->primary.rootent;
5562           if (isoent->file->parentdir.length > 0)
5563                     fn = p = isoent->file->parentdir.s;
5564           else
5565                     fn = p = "";
5566 
5567           /*
5568            * If the path of the parent directory of `isoent' entry is
5569            * the same as the path of `cur_dirent', add isoent to
5570            * `cur_dirent'.
5571            */
5572           if (archive_strlen(&(iso9660->cur_dirstr))
5573                 == archive_strlen(&(isoent->file->parentdir)) &&
5574               strcmp(iso9660->cur_dirstr.s, fn) == 0) {
5575                     if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {
5576                               np = (struct isoent *)__archive_rb_tree_find_node(
5577                                   &(iso9660->cur_dirent->rbtree),
5578                                   isoent->file->basename.s);
5579                               goto same_entry;
5580                     }
5581                     return (ARCHIVE_OK);
5582           }
5583 
5584           for (;;) {
5585                     l = get_path_component(name, sizeof(name), fn);
5586                     if (l == 0) {
5587                               np = NULL;
5588                               break;
5589                     }
5590                     if (l < 0) {
5591                               archive_set_error(&a->archive,
5592                                   ARCHIVE_ERRNO_MISC,
5593                                   "A name buffer is too small");
5594                               _isoent_free(isoent);
5595                               return (ARCHIVE_FATAL);
5596                     }
5597 
5598                     np = isoent_find_child(dent, name);
5599                     if (np == NULL || fn[0] == '\0')
5600                               break;
5601 
5602                     /* Find next subdirectory. */
5603                     if (!np->dir) {
5604                               /* NOT Directory! */
5605                               archive_set_error(&a->archive,
5606                                   ARCHIVE_ERRNO_MISC,
5607                                   "`%s' is not directory, we cannot insert `%s' ",
5608                                   archive_entry_pathname(np->file->entry),
5609                                   archive_entry_pathname(isoent->file->entry));
5610                               _isoent_free(isoent);
5611                               *isoentpp = NULL;
5612                               return (ARCHIVE_FAILED);
5613                     }
5614                     fn += l;
5615                     if (fn[0] == '/')
5616                               fn++;
5617                     dent = np;
5618           }
5619           if (np == NULL) {
5620                     /*
5621                      * Create virtual parent directories.
5622                      */
5623                     while (fn[0] != '\0') {
5624                               struct isoent *vp;
5625                               struct archive_string as;
5626 
5627                               archive_string_init(&as);
5628                               archive_strncat(&as, p, fn - p + l);
5629                               if (as.s[as.length-1] == '/') {
5630                                         as.s[as.length-1] = '\0';
5631                                         as.length--;
5632                               }
5633                               vp = isoent_create_virtual_dir(a, iso9660, as.s);
5634                               if (vp == NULL) {
5635                                         archive_string_free(&as);
5636                                         archive_set_error(&a->archive, ENOMEM,
5637                                             "Can't allocate memory");
5638                                         _isoent_free(isoent);
5639                                         *isoentpp = NULL;
5640                                         return (ARCHIVE_FATAL);
5641                               }
5642                               archive_string_free(&as);
5643 
5644                               if (vp->file->dircnt > iso9660->dircnt_max)
5645                                         iso9660->dircnt_max = vp->file->dircnt;
5646                               isoent_add_child_tail(dent, vp);
5647                               np = vp;
5648 
5649                               fn += l;
5650                               if (fn[0] == '/')
5651                                         fn++;
5652                               l = get_path_component(name, sizeof(name), fn);
5653                               if (l < 0) {
5654                                         archive_string_free(&as);
5655                                         archive_set_error(&a->archive,
5656                                             ARCHIVE_ERRNO_MISC,
5657                                             "A name buffer is too small");
5658                                         _isoent_free(isoent);
5659                                         *isoentpp = NULL;
5660                                         return (ARCHIVE_FATAL);
5661                               }
5662                               dent = np;
5663                     }
5664 
5665                     /* Found out the parent directory where isoent can be
5666                      * inserted. */
5667                     iso9660->cur_dirent = dent;
5668                     archive_string_empty(&(iso9660->cur_dirstr));
5669                     archive_string_ensure(&(iso9660->cur_dirstr),
5670                         archive_strlen(&(dent->file->parentdir)) +
5671                         archive_strlen(&(dent->file->basename)) + 2);
5672                     if (archive_strlen(&(dent->file->parentdir)) +
5673                         archive_strlen(&(dent->file->basename)) == 0)
5674                               iso9660->cur_dirstr.s[0] = 0;
5675                     else {
5676                               if (archive_strlen(&(dent->file->parentdir)) > 0) {
5677                                         archive_string_copy(&(iso9660->cur_dirstr),
5678                                             &(dent->file->parentdir));
5679                                         archive_strappend_char(&(iso9660->cur_dirstr), '/');
5680                               }
5681                               archive_string_concat(&(iso9660->cur_dirstr),
5682                                   &(dent->file->basename));
5683                     }
5684 
5685                     if (!isoent_add_child_tail(dent, isoent)) {
5686                               np = (struct isoent *)__archive_rb_tree_find_node(
5687                                   &(dent->rbtree), isoent->file->basename.s);
5688                               goto same_entry;
5689                     }
5690                     return (ARCHIVE_OK);
5691           }
5692 
5693 same_entry:
5694           /*
5695            * We have already has the entry the filename of which is
5696            * the same.
5697            */
5698           f1 = np->file;
5699           f2 = isoent->file;
5700 
5701           /* If the file type of entries is different,
5702            * we cannot handle it. */
5703           if (archive_entry_filetype(f1->entry) !=
5704               archive_entry_filetype(f2->entry)) {
5705                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
5706                         "Found duplicate entries `%s' and its file type is "
5707                         "different",
5708                         archive_entry_pathname(f1->entry));
5709                     _isoent_free(isoent);
5710                     *isoentpp = NULL;
5711                     return (ARCHIVE_FAILED);
5712           }
5713 
5714           /* Swap file entries. */
5715           np->file = f2;
5716           isoent->file = f1;
5717           np->virtual = 0;
5718 
5719           _isoent_free(isoent);
5720           *isoentpp = np;
5721           return (ARCHIVE_OK);
5722 }
5723 
5724 /*
5725  * Find a entry from `isoent'
5726  */
5727 static struct isoent *
isoent_find_child(struct isoent * isoent,const char * child_name)5728 isoent_find_child(struct isoent *isoent, const char *child_name)
5729 {
5730           struct isoent *np;
5731 
5732           np = (struct isoent *)__archive_rb_tree_find_node(
5733               &(isoent->rbtree), child_name);
5734           return (np);
5735 }
5736 
5737 /*
5738  * Find a entry full-path of which is specified by `fn' parameter,
5739  * in the tree.
5740  */
5741 static struct isoent *
isoent_find_entry(struct isoent * rootent,const char * fn)5742 isoent_find_entry(struct isoent *rootent, const char *fn)
5743 {
5744 #if defined(_WIN32) && !defined(__CYGWIN__)
5745           char name[_MAX_FNAME];/* Included null terminator size. */
5746 #elif defined(NAME_MAX) && NAME_MAX >= 255
5747           char name[NAME_MAX+1];
5748 #else
5749           char name[256];
5750 #endif
5751           struct isoent *isoent, *np;
5752           int l;
5753 
5754           isoent = rootent;
5755           np = NULL;
5756           for (;;) {
5757                     l = get_path_component(name, sizeof(name), fn);
5758                     if (l == 0)
5759                               break;
5760                     fn += l;
5761                     if (fn[0] == '/')
5762                               fn++;
5763 
5764                     np = isoent_find_child(isoent, name);
5765                     if (np == NULL)
5766                               break;
5767                     if (fn[0] == '\0')
5768                               break;/* We found out the entry */
5769 
5770                     /* Try sub directory. */
5771                     isoent = np;
5772                     np = NULL;
5773                     if (!isoent->dir)
5774                               break;/* Not directory */
5775           }
5776 
5777           return (np);
5778 }
5779 
5780 /*
5781  * Following idr_* functions are used for resolving duplicated filenames
5782  * and unreceivable filenames to generate ISO9660/Joliet Identifiers.
5783  */
5784 
5785 static void
idr_relaxed_filenames(char * map)5786 idr_relaxed_filenames(char *map)
5787 {
5788           int i;
5789 
5790           for (i = 0x21; i <= 0x2F; i++)
5791                     map[i] = 1;
5792           for (i = 0x3A; i <= 0x41; i++)
5793                     map[i] = 1;
5794           for (i = 0x5B; i <= 0x5E; i++)
5795                     map[i] = 1;
5796           map[0x60] = 1;
5797           for (i = 0x7B; i <= 0x7E; i++)
5798                     map[i] = 1;
5799 }
5800 
5801 static void
idr_init(struct iso9660 * iso9660,struct vdd * vdd,struct idr * idr)5802 idr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)
5803 {
5804 
5805           idr->idrent_pool = NULL;
5806           idr->pool_size = 0;
5807           if (vdd->vdd_type != VDD_JOLIET) {
5808                     if (iso9660->opt.iso_level <= 3) {
5809                               memcpy(idr->char_map, d_characters_map,
5810                                   sizeof(idr->char_map));
5811                     } else {
5812                               memcpy(idr->char_map, d1_characters_map,
5813                                   sizeof(idr->char_map));
5814                               idr_relaxed_filenames(idr->char_map);
5815                     }
5816           }
5817 }
5818 
5819 static void
idr_cleanup(struct idr * idr)5820 idr_cleanup(struct idr *idr)
5821 {
5822           free(idr->idrent_pool);
5823 }
5824 
5825 static int
idr_ensure_poolsize(struct archive_write * a,struct idr * idr,int cnt)5826 idr_ensure_poolsize(struct archive_write *a, struct idr *idr,
5827     int cnt)
5828 {
5829 
5830           if (idr->pool_size < cnt) {
5831                     void *p;
5832                     const int bk = (1 << 7) - 1;
5833                     int psize;
5834 
5835                     psize = (cnt + bk) & ~bk;
5836                     p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
5837                     if (p == NULL) {
5838                               archive_set_error(&a->archive, ENOMEM,
5839                                   "Can't allocate memory");
5840                               return (ARCHIVE_FATAL);
5841                     }
5842                     idr->idrent_pool = (struct idrent *)p;
5843                     idr->pool_size = psize;
5844           }
5845           return (ARCHIVE_OK);
5846 }
5847 
5848 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)5849 idr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,
5850     int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)
5851 {
5852           int r;
5853 
5854           (void)ffmax; /* UNUSED */
5855 
5856           r = idr_ensure_poolsize(a, idr, cnt);
5857           if (r != ARCHIVE_OK)
5858                     return (r);
5859           __archive_rb_tree_init(&(idr->rbtree), rbt_ops);
5860           idr->wait_list.first = NULL;
5861           idr->wait_list.last = &(idr->wait_list.first);
5862           idr->pool_idx = 0;
5863           idr->num_size = num_size;
5864           idr->null_size = null_size;
5865           return (ARCHIVE_OK);
5866 }
5867 
5868 static void
idr_register(struct idr * idr,struct isoent * isoent,int weight,int noff)5869 idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
5870 {
5871           struct idrent *idrent, *n;
5872 
5873           idrent = &(idr->idrent_pool[idr->pool_idx++]);
5874           idrent->wnext = idrent->avail = NULL;
5875           idrent->isoent = isoent;
5876           idrent->weight = weight;
5877           idrent->noff = noff;
5878           idrent->rename_num = 0;
5879 
5880           if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {
5881                     n = (struct idrent *)__archive_rb_tree_find_node(
5882                         &(idr->rbtree), idrent->isoent);
5883                     if (n != NULL) {
5884                               /* this `idrent' needs to rename. */
5885                               idrent->avail = n;
5886                               *idr->wait_list.last = idrent;
5887                               idr->wait_list.last = &(idrent->wnext);
5888                     }
5889           }
5890 }
5891 
5892 static void
idr_extend_identifier(struct idrent * wnp,int numsize,int nullsize)5893 idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
5894 {
5895           unsigned char *p;
5896           int wnp_ext_off;
5897 
5898           wnp_ext_off = wnp->isoent->ext_off;
5899           if (wnp->noff + numsize != wnp_ext_off) {
5900                     p = (unsigned char *)wnp->isoent->identifier;
5901                     /* Extend the filename; foo.c --> foo___.c */
5902                     memmove(p + wnp->noff + numsize, p + wnp_ext_off,
5903                         wnp->isoent->ext_len + nullsize);
5904                     wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
5905                     wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
5906           }
5907 }
5908 
5909 static void
idr_resolve(struct idr * idr,void (* fsetnum)(unsigned char * p,int num))5910 idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
5911 {
5912           struct idrent *n;
5913           unsigned char *p;
5914 
5915           for (n = idr->wait_list.first; n != NULL; n = n->wnext) {
5916                     idr_extend_identifier(n, idr->num_size, idr->null_size);
5917                     p = (unsigned char *)n->isoent->identifier + n->noff;
5918                     do {
5919                               fsetnum(p, n->avail->rename_num++);
5920                     } while (!__archive_rb_tree_insert_node(
5921                         &(idr->rbtree), &(n->rbnode)));
5922           }
5923 }
5924 
5925 static void
idr_set_num(unsigned char * p,int num)5926 idr_set_num(unsigned char *p, int num)
5927 {
5928           static const char xdig[] = {
5929                     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5930                     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
5931                     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
5932                     'U', 'V', 'W', 'X', 'Y', 'Z'
5933           };
5934 
5935           num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);
5936           p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];
5937           num %= sizeof(xdig) * sizeof(xdig);
5938           p[1] = xdig[ (num / sizeof(xdig))];
5939           num %= sizeof(xdig);
5940           p[2] = xdig[num];
5941 }
5942 
5943 static void
idr_set_num_beutf16(unsigned char * p,int num)5944 idr_set_num_beutf16(unsigned char *p, int num)
5945 {
5946           static const uint16_t xdig[] = {
5947                     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
5948                     0x0036, 0x0037, 0x0038, 0x0039,
5949                     0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
5950                     0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,
5951                     0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
5952                     0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
5953                     0x0059, 0x005A
5954           };
5955 #define XDIG_CNT    (sizeof(xdig)/sizeof(xdig[0]))
5956 
5957           num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;
5958           archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);
5959           num %= XDIG_CNT * XDIG_CNT;
5960           archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);
5961           num %= XDIG_CNT;
5962           archive_be16enc(p+4, xdig[num]);
5963 }
5964 
5965 /*
5966  * Generate ISO9660 Identifier.
5967  */
5968 static int
isoent_gen_iso9660_identifier(struct archive_write * a,struct isoent * isoent,struct idr * idr)5969 isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
5970     struct idr *idr)
5971 {
5972           struct iso9660 *iso9660;
5973           struct isoent *np;
5974           char *p;
5975           int l, r;
5976           const char *char_map;
5977           char allow_ldots, allow_multidot, allow_period, allow_vernum;
5978           int fnmax, ffmax, dnmax;
5979           static const struct archive_rb_tree_ops rb_ops = {
5980                     isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
5981           };
5982 
5983           if (isoent->children.cnt == 0)
5984                     return (0);
5985 
5986           iso9660 = a->format_data;
5987           char_map = idr->char_map;
5988           if (iso9660->opt.iso_level <= 3) {
5989                     allow_ldots = 0;
5990                     allow_multidot = 0;
5991                     allow_period = 1;
5992                     allow_vernum = iso9660->opt.allow_vernum;
5993                     if (iso9660->opt.iso_level == 1) {
5994                               fnmax = 8;
5995                               ffmax = 12;/* fnmax + '.' + 3 */
5996                               dnmax = 8;
5997                     } else {
5998                               fnmax = 30;
5999                               ffmax = 31;
6000                               dnmax = 31;
6001                     }
6002           } else {
6003                     allow_ldots = allow_multidot = 1;
6004                     allow_period = allow_vernum = 0;
6005                     if (iso9660->opt.rr)
6006                               /*
6007                                * MDR : The maximum size of Directory Record(254).
6008                                * DRL : A Directory Record Length(33).
6009                                * CE  : A size of SUSP CE System Use Entry(28).
6010                                * MDR - DRL - CE = 254 - 33 - 28 = 193.
6011                                */
6012                               fnmax = ffmax = dnmax = 193;
6013                     else
6014                               /*
6015                                * XA  : CD-ROM XA System Use Extension
6016                                *       Information(14).
6017                                * MDR - DRL - XA = 254 - 33 -14 = 207.
6018                                */
6019                               fnmax = ffmax = dnmax = 207;
6020           }
6021 
6022           r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
6023           if (r < 0)
6024                     return (r);
6025 
6026           for (np = isoent->children.first; np != NULL; np = np->chnext) {
6027                     char *dot, *xdot;
6028                     int ext_off, noff, weight;
6029 
6030                     l = (int)np->file->basename.length;
6031                     p = malloc(l+31+2+1);
6032                     if (p == NULL) {
6033                               archive_set_error(&a->archive, ENOMEM,
6034                                   "Can't allocate memory");
6035                               return (ARCHIVE_FATAL);
6036                     }
6037                     memcpy(p, np->file->basename.s, l);
6038                     p[l] = '\0';
6039                     np->identifier = p;
6040 
6041                     dot = xdot = NULL;
6042                     if (!allow_ldots) {
6043                               /*
6044                                * If there is a '.' character at the first byte,
6045                                * it has to be replaced by '_' character.
6046                                */
6047                               if (*p == '.')
6048                                         *p++ = '_';
6049                     }
6050                     for (;*p; p++) {
6051                               if (*p & 0x80) {
6052                                         *p = '_';
6053                                         continue;
6054                               }
6055                               if (char_map[(unsigned char)*p]) {
6056                                         /* if iso-level is '4', a character '.' is
6057                                          * allowed by char_map. */
6058                                         if (*p == '.') {
6059                                                   xdot = dot;
6060                                                   dot = p;
6061                                         }
6062                                         continue;
6063                               }
6064                               if (*p >= 'a' && *p <= 'z') {
6065                                         *p -= 'a' - 'A';
6066                                         continue;
6067                               }
6068                               if (*p == '.') {
6069                                         xdot = dot;
6070                                         dot = p;
6071                                         if (allow_multidot)
6072                                                   continue;
6073                               }
6074                               *p = '_';
6075                     }
6076                     p = np->identifier;
6077                     weight = -1;
6078                     if (dot == NULL) {
6079                               int nammax;
6080 
6081                               if (np->dir)
6082                                         nammax = dnmax;
6083                               else
6084                                         nammax = fnmax;
6085 
6086                               if (l > nammax) {
6087                                         p[nammax] = '\0';
6088                                         weight = nammax;
6089                                         ext_off = nammax;
6090                               } else
6091                                         ext_off = l;
6092                     } else {
6093                               *dot = '.';
6094                               ext_off = (int)(dot - p);
6095 
6096                               if (iso9660->opt.iso_level == 1) {
6097                                         if (dot - p <= 8) {
6098                                                   if (strlen(dot) > 4) {
6099                                                             /* A length of a file extension
6100                                                              * must be less than 4 */
6101                                                             dot[4] = '\0';
6102                                                             weight = 0;
6103                                                   }
6104                                         } else {
6105                                                   p[8] = dot[0];
6106                                                   p[9] = dot[1];
6107                                                   p[10] = dot[2];
6108                                                   p[11] = dot[3];
6109                                                   p[12] = '\0';
6110                                                   weight = 8;
6111                                                   ext_off = 8;
6112                                         }
6113                               } else if (np->dir) {
6114                                         if (l > dnmax) {
6115                                                   p[dnmax] = '\0';
6116                                                   weight = dnmax;
6117                                                   if (ext_off > dnmax)
6118                                                             ext_off = dnmax;
6119                                         }
6120                               } else if (l > ffmax) {
6121                                         int extlen = (int)strlen(dot);
6122                                         int xdoff;
6123 
6124                                         if (xdot != NULL)
6125                                                   xdoff = (int)(xdot - p);
6126                                         else
6127                                                   xdoff = 0;
6128 
6129                                         if (extlen > 1 && xdoff < fnmax-1) {
6130                                                   int off;
6131 
6132                                                   if (extlen > ffmax)
6133                                                             extlen = ffmax;
6134                                                   off = ffmax - extlen;
6135                                                   if (off == 0) {
6136                                                             /* A dot('.')  character
6137                                                              * doesn't place to the first
6138                                                              * byte of identifier. */
6139                                                             off ++;
6140                                                             extlen --;
6141                                                   }
6142                                                   memmove(p+off, dot, extlen);
6143                                                   p[ffmax] = '\0';
6144                                                   ext_off = off;
6145                                                   weight = off;
6146 #ifdef COMPAT_MKISOFS
6147                                         } else if (xdoff >= fnmax-1) {
6148                                                   /* Simulate a bug(?) of mkisofs. */
6149                                                   p[fnmax-1] = '\0';
6150                                                   ext_off = fnmax-1;
6151                                                   weight = fnmax-1;
6152 #endif
6153                                         } else {
6154                                                   p[fnmax] = '\0';
6155                                                   ext_off = fnmax;
6156                                                   weight = fnmax;
6157                                         }
6158                               }
6159                     }
6160                     /* Save an offset of a file name extension to sort files. */
6161                     np->ext_off = ext_off;
6162                     np->ext_len = (int)strlen(&p[ext_off]);
6163                     np->id_len = l = ext_off + np->ext_len;
6164 
6165                     /* Make an offset of the number which is used to be set
6166                      * hexadecimal number to avoid duplicate identifier. */
6167                     if (iso9660->opt.iso_level == 1) {
6168                               if (ext_off >= 5)
6169                                         noff = 5;
6170                               else
6171                                         noff = ext_off;
6172                     } else {
6173                               if (l == ffmax)
6174                                         noff = ext_off - 3;
6175                               else if (l == ffmax-1)
6176                                         noff = ext_off - 2;
6177                               else if (l == ffmax-2)
6178                                         noff = ext_off - 1;
6179                               else
6180                                         noff = ext_off;
6181                     }
6182                     /* Register entry to the identifier resolver. */
6183                     idr_register(idr, np, weight, noff);
6184           }
6185 
6186           /* Resolve duplicate identifier. */
6187           idr_resolve(idr, idr_set_num);
6188 
6189           /* Add a period and a version number to identifiers. */
6190           for (np = isoent->children.first; np != NULL; np = np->chnext) {
6191                     if (!np->dir && np->rr_child == NULL) {
6192                               p = np->identifier + np->ext_off + np->ext_len;
6193                               if (np->ext_len == 0 && allow_period) {
6194                                         *p++ = '.';
6195                                         np->ext_len = 1;
6196                               }
6197                               if (np->ext_len == 1 && !allow_period) {
6198                                         *--p = '\0';
6199                                         np->ext_len = 0;
6200                               }
6201                               np->id_len = np->ext_off + np->ext_len;
6202                               if (allow_vernum) {
6203                                         *p++ = ';';
6204                                         *p++ = '1';
6205                                         np->id_len += 2;
6206                               }
6207                               *p = '\0';
6208                     } else
6209                               np->id_len = np->ext_off + np->ext_len;
6210                     np->mb_len = np->id_len;
6211           }
6212           return (ARCHIVE_OK);
6213 }
6214 
6215 /*
6216  * Generate Joliet Identifier.
6217  */
6218 static int
isoent_gen_joliet_identifier(struct archive_write * a,struct isoent * isoent,struct idr * idr)6219 isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
6220     struct idr *idr)
6221 {
6222           struct iso9660 *iso9660;
6223           struct isoent *np;
6224           unsigned char *p;
6225           size_t l;
6226           int r;
6227           size_t ffmax, parent_len;
6228           static const struct archive_rb_tree_ops rb_ops = {
6229                     isoent_cmp_node_joliet, isoent_cmp_key_joliet
6230           };
6231 
6232           if (isoent->children.cnt == 0)
6233                     return (0);
6234 
6235           iso9660 = a->format_data;
6236           if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
6237                     ffmax = 206;
6238           else
6239                     ffmax = 128;
6240 
6241           r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
6242           if (r < 0)
6243                     return (r);
6244 
6245           parent_len = 1;
6246           for (np = isoent; np->parent != np; np = np->parent)
6247                     parent_len += np->mb_len + 1;
6248 
6249           for (np = isoent->children.first; np != NULL; np = np->chnext) {
6250                     unsigned char *dot;
6251                     int ext_off, noff, weight;
6252                     size_t lt;
6253 
6254                     if ((l = np->file->basename_utf16.length) > ffmax)
6255                               l = ffmax;
6256 
6257                     p = malloc((l+1)*2);
6258                     if (p == NULL) {
6259                               archive_set_error(&a->archive, ENOMEM,
6260                                   "Can't allocate memory");
6261                               return (ARCHIVE_FATAL);
6262                     }
6263                     memcpy(p, np->file->basename_utf16.s, l);
6264                     p[l] = 0;
6265                     p[l+1] = 0;
6266 
6267                     np->identifier = (char *)p;
6268                     lt = l;
6269                     dot = p + l;
6270                     weight = 0;
6271                     while (lt > 0) {
6272                               if (!joliet_allowed_char(p[0], p[1]))
6273                                         archive_be16enc(p, 0x005F); /* '_' */
6274                               else if (p[0] == 0 && p[1] == 0x2E) /* '.' */
6275                                         dot = p;
6276                               p += 2;
6277                               lt -= 2;
6278                     }
6279                     ext_off = (int)(dot - (unsigned char *)np->identifier);
6280                     np->ext_off = ext_off;
6281                     np->ext_len = (int)l - ext_off;
6282                     np->id_len = (int)l;
6283 
6284                     /*
6285                      * Get a length of MBS of a full-pathname.
6286                      */
6287                     if (np->file->basename_utf16.length > ffmax) {
6288                               if (archive_strncpy_l(&iso9660->mbs,
6289                                   (const char *)np->identifier, l,
6290                                         iso9660->sconv_from_utf16be) != 0 &&
6291                                   errno == ENOMEM) {
6292                                         archive_set_error(&a->archive, errno,
6293                                             "No memory");
6294                                         return (ARCHIVE_FATAL);
6295                               }
6296                               np->mb_len = (int)iso9660->mbs.length;
6297                               if (np->mb_len != (int)np->file->basename.length)
6298                                         weight = np->mb_len;
6299                     } else
6300                               np->mb_len = (int)np->file->basename.length;
6301 
6302                     /* If a length of full-pathname is longer than 240 bytes,
6303                      * it violates Joliet extensions regulation. */
6304                     if (parent_len > 240
6305                         || np->mb_len > 240
6306                         || parent_len + np->mb_len > 240) {
6307                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
6308                                   "The regulation of Joliet extensions;"
6309                                   " A length of a full-pathname of `%s' is "
6310                                   "longer than 240 bytes, (p=%d, b=%d)",
6311                                   archive_entry_pathname(np->file->entry),
6312                                   (int)parent_len, (int)np->mb_len);
6313                               return (ARCHIVE_FATAL);
6314                     }
6315 
6316                     /* Make an offset of the number which is used to be set
6317                      * hexadecimal number to avoid duplicate identifier. */
6318                     if (l == ffmax)
6319                               noff = ext_off - 6;
6320                     else if (l == ffmax-2)
6321                               noff = ext_off - 4;
6322                     else if (l == ffmax-4)
6323                               noff = ext_off - 2;
6324                     else
6325                               noff = ext_off;
6326                     /* Register entry to the identifier resolver. */
6327                     idr_register(idr, np, weight, noff);
6328           }
6329 
6330           /* Resolve duplicate identifier with Joliet Volume. */
6331           idr_resolve(idr, idr_set_num_beutf16);
6332 
6333           return (ARCHIVE_OK);
6334 }
6335 
6336 /*
6337  * This comparing rule is according to ISO9660 Standard 9.3
6338  */
6339 static int
isoent_cmp_iso9660_identifier(const struct isoent * p1,const struct isoent * p2)6340 isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
6341 {
6342           const char *s1, *s2;
6343           int cmp;
6344           int l;
6345 
6346           s1 = p1->identifier;
6347           s2 = p2->identifier;
6348 
6349           /* Compare File Name */
6350           l = p1->ext_off;
6351           if (l > p2->ext_off)
6352                     l = p2->ext_off;
6353           cmp = memcmp(s1, s2, l);
6354           if (cmp != 0)
6355                     return (cmp);
6356           if (p1->ext_off < p2->ext_off) {
6357                     s2 += l;
6358                     l = p2->ext_off - p1->ext_off;
6359                     while (l--)
6360                               if (0x20 != *s2++)
6361                                         return (0x20
6362                                             - *(const unsigned char *)(s2 - 1));
6363           } else if (p1->ext_off > p2->ext_off) {
6364                     s1 += l;
6365                     l = p1->ext_off - p2->ext_off;
6366                     while (l--)
6367                               if (0x20 != *s1++)
6368                                         return (*(const unsigned char *)(s1 - 1)
6369                                             - 0x20);
6370           }
6371           /* Compare File Name Extension */
6372           if (p1->ext_len == 0 && p2->ext_len == 0)
6373                     return (0);
6374           if (p1->ext_len == 1 && p2->ext_len == 1)
6375                     return (0);
6376           if (p1->ext_len <= 1)
6377                     return (-1);
6378           if (p2->ext_len <= 1)
6379                     return (1);
6380           l = p1->ext_len;
6381           if (l > p2->ext_len)
6382                     l = p2->ext_len;
6383           s1 = p1->identifier + p1->ext_off;
6384           s2 = p2->identifier + p2->ext_off;
6385           if (l > 1) {
6386                     cmp = memcmp(s1, s2, l);
6387                     if (cmp != 0)
6388                               return (cmp);
6389           }
6390           if (p1->ext_len < p2->ext_len) {
6391                     s2 += l;
6392                     l = p2->ext_len - p1->ext_len;
6393                     while (l--)
6394                               if (0x20 != *s2++)
6395                                         return (0x20
6396                                             - *(const unsigned char *)(s2 - 1));
6397           } else if (p1->ext_len > p2->ext_len) {
6398                     s1 += l;
6399                     l = p1->ext_len - p2->ext_len;
6400                     while (l--)
6401                               if (0x20 != *s1++)
6402                                         return (*(const unsigned char *)(s1 - 1)
6403                                             - 0x20);
6404           }
6405           /* Compare File Version Number */
6406           /* No operation. The File Version Number is always one. */
6407 
6408           return (cmp);
6409 }
6410 
6411 static int
isoent_cmp_node_iso9660(const struct archive_rb_node * n1,const struct archive_rb_node * n2)6412 isoent_cmp_node_iso9660(const struct archive_rb_node *n1,
6413     const struct archive_rb_node *n2)
6414 {
6415           const struct idrent *e1 = (const struct idrent *)n1;
6416           const struct idrent *e2 = (const struct idrent *)n2;
6417 
6418           return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));
6419 }
6420 
6421 static int
isoent_cmp_key_iso9660(const struct archive_rb_node * node,const void * key)6422 isoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)
6423 {
6424           const struct isoent *isoent = (const struct isoent *)key;
6425           const struct idrent *idrent = (const struct idrent *)node;
6426 
6427           return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));
6428 }
6429 
6430 static int
isoent_cmp_joliet_identifier(const struct isoent * p1,const struct isoent * p2)6431 isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
6432 {
6433           const unsigned char *s1, *s2;
6434           int cmp;
6435           int l;
6436 
6437           s1 = (const unsigned char *)p1->identifier;
6438           s2 = (const unsigned char *)p2->identifier;
6439 
6440           /* Compare File Name */
6441           l = p1->ext_off;
6442           if (l > p2->ext_off)
6443                     l = p2->ext_off;
6444           cmp = memcmp(s1, s2, l);
6445           if (cmp != 0)
6446                     return (cmp);
6447           if (p1->ext_off < p2->ext_off) {
6448                     s2 += l;
6449                     l = p2->ext_off - p1->ext_off;
6450                     while (l--)
6451                               if (0 != *s2++)
6452                                         return (- *(const unsigned char *)(s2 - 1));
6453           } else if (p1->ext_off > p2->ext_off) {
6454                     s1 += l;
6455                     l = p1->ext_off - p2->ext_off;
6456                     while (l--)
6457                               if (0 != *s1++)
6458                                         return (*(const unsigned char *)(s1 - 1));
6459           }
6460           /* Compare File Name Extension */
6461           if (p1->ext_len == 0 && p2->ext_len == 0)
6462                     return (0);
6463           if (p1->ext_len == 2 && p2->ext_len == 2)
6464                     return (0);
6465           if (p1->ext_len <= 2)
6466                     return (-1);
6467           if (p2->ext_len <= 2)
6468                     return (1);
6469           l = p1->ext_len;
6470           if (l > p2->ext_len)
6471                     l = p2->ext_len;
6472           s1 = (unsigned char *)(p1->identifier + p1->ext_off);
6473           s2 = (unsigned char *)(p2->identifier + p2->ext_off);
6474           if (l > 1) {
6475                     cmp = memcmp(s1, s2, l);
6476                     if (cmp != 0)
6477                               return (cmp);
6478           }
6479           if (p1->ext_len < p2->ext_len) {
6480                     s2 += l;
6481                     l = p2->ext_len - p1->ext_len;
6482                     while (l--)
6483                               if (0 != *s2++)
6484                                         return (- *(const unsigned char *)(s2 - 1));
6485           } else if (p1->ext_len > p2->ext_len) {
6486                     s1 += l;
6487                     l = p1->ext_len - p2->ext_len;
6488                     while (l--)
6489                               if (0 != *s1++)
6490                                         return (*(const unsigned char *)(s1 - 1));
6491           }
6492           /* Compare File Version Number */
6493           /* No operation. The File Version Number is always one. */
6494 
6495           return (cmp);
6496 }
6497 
6498 static int
isoent_cmp_node_joliet(const struct archive_rb_node * n1,const struct archive_rb_node * n2)6499 isoent_cmp_node_joliet(const struct archive_rb_node *n1,
6500     const struct archive_rb_node *n2)
6501 {
6502           const struct idrent *e1 = (const struct idrent *)n1;
6503           const struct idrent *e2 = (const struct idrent *)n2;
6504 
6505           return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));
6506 }
6507 
6508 static int
isoent_cmp_key_joliet(const struct archive_rb_node * node,const void * key)6509 isoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)
6510 {
6511           const struct isoent *isoent = (const struct isoent *)key;
6512           const struct idrent *idrent = (const struct idrent *)node;
6513 
6514           return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));
6515 }
6516 
6517 static int
isoent_make_sorted_files(struct archive_write * a,struct isoent * isoent,struct idr * idr)6518 isoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,
6519     struct idr *idr)
6520 {
6521           struct archive_rb_node *rn;
6522           struct isoent **children;
6523 
6524           children = malloc(isoent->children.cnt * sizeof(struct isoent *));
6525           if (children == NULL) {
6526                     archive_set_error(&a->archive, ENOMEM,
6527                         "Can't allocate memory");
6528                     return (ARCHIVE_FATAL);
6529           }
6530           isoent->children_sorted = children;
6531 
6532           ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {
6533                     struct idrent *idrent = (struct idrent *)rn;
6534                     *children ++ = idrent->isoent;
6535           }
6536           return (ARCHIVE_OK);
6537 }
6538 
6539 /*
6540  * - Generate ISO9660 and Joliet identifiers from basenames.
6541  * - Sort files by each directory.
6542  */
6543 static int
isoent_traverse_tree(struct archive_write * a,struct vdd * vdd)6544 isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
6545 {
6546           struct iso9660 *iso9660 = a->format_data;
6547           struct isoent *np;
6548           struct idr idr;
6549           int depth;
6550           int r;
6551           int (*genid)(struct archive_write *, struct isoent *, struct idr *);
6552 
6553           idr_init(iso9660, vdd, &idr);
6554           np = vdd->rootent;
6555           depth = 0;
6556           if (vdd->vdd_type == VDD_JOLIET)
6557                     genid = isoent_gen_joliet_identifier;
6558           else
6559                     genid = isoent_gen_iso9660_identifier;
6560           do {
6561                     if (np->virtual &&
6562                         !archive_entry_mtime_is_set(np->file->entry)) {
6563                               /* Set properly times to virtual directory */
6564                               archive_entry_set_mtime(np->file->entry,
6565                                   iso9660->birth_time, 0);
6566                               archive_entry_set_atime(np->file->entry,
6567                                   iso9660->birth_time, 0);
6568                               archive_entry_set_ctime(np->file->entry,
6569                                   iso9660->birth_time, 0);
6570                     }
6571                     if (np->children.first != NULL) {
6572                               if (vdd->vdd_type != VDD_JOLIET &&
6573                                   !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {
6574                                         if (np->children.cnt > 0)
6575                                                   iso9660->directories_too_deep = np;
6576                               } else {
6577                                         /* Generate Identifier */
6578                                         r = genid(a, np, &idr);
6579                                         if (r < 0)
6580                                                   goto exit_traverse_tree;
6581                                         r = isoent_make_sorted_files(a, np, &idr);
6582                                         if (r < 0)
6583                                                   goto exit_traverse_tree;
6584 
6585                                         if (np->subdirs.first != NULL &&
6586                                             depth + 1 < vdd->max_depth) {
6587                                                   /* Enter to sub directories. */
6588                                                   np = np->subdirs.first;
6589                                                   depth++;
6590                                                   continue;
6591                                         }
6592                               }
6593                     }
6594                     while (np != np->parent) {
6595                               if (np->drnext == NULL) {
6596                                         /* Return to the parent directory. */
6597                                         np = np->parent;
6598                                         depth--;
6599                               } else {
6600                                         np = np->drnext;
6601                                         break;
6602                               }
6603                     }
6604           } while (np != np->parent);
6605 
6606           r = ARCHIVE_OK;
6607 exit_traverse_tree:
6608           idr_cleanup(&idr);
6609 
6610           return (r);
6611 }
6612 
6613 /*
6614  * Collect directory entries into path_table by a directory depth.
6615  */
6616 static int
isoent_collect_dirs(struct vdd * vdd,struct isoent * rootent,int depth)6617 isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
6618 {
6619           struct isoent *np;
6620 
6621           if (rootent == NULL)
6622                     rootent = vdd->rootent;
6623           np = rootent;
6624           do {
6625                     /* Register current directory to pathtable. */
6626                     path_table_add_entry(&(vdd->pathtbl[depth]), np);
6627 
6628                     if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
6629                               /* Enter to sub directories. */
6630                               np = np->subdirs.first;
6631                               depth++;
6632                               continue;
6633                     }
6634                     while (np != rootent) {
6635                               if (np->drnext == NULL) {
6636                                         /* Return to the parent directory. */
6637                                         np = np->parent;
6638                                         depth--;
6639                               } else {
6640                                         np = np->drnext;
6641                                         break;
6642                               }
6643                     }
6644           } while (np != rootent);
6645 
6646           return (ARCHIVE_OK);
6647 }
6648 
6649 /*
6650  * The entry whose number of levels in a directory hierarchy is
6651  * large than eight relocate to rr_move directory.
6652  */
6653 static int
isoent_rr_move_dir(struct archive_write * a,struct isoent ** rr_moved,struct isoent * curent,struct isoent ** newent)6654 isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
6655     struct isoent *curent, struct isoent **newent)
6656 {
6657           struct iso9660 *iso9660 = a->format_data;
6658           struct isoent *rrmoved, *mvent, *np;
6659 
6660           if ((rrmoved = *rr_moved) == NULL) {
6661                     struct isoent *rootent = iso9660->primary.rootent;
6662                     /* There isn't rr_move entry.
6663                      * Create rr_move entry and insert it into the root entry.
6664                      */
6665                     rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");
6666                     if (rrmoved == NULL) {
6667                               archive_set_error(&a->archive, ENOMEM,
6668                                   "Can't allocate memory");
6669                               return (ARCHIVE_FATAL);
6670                     }
6671                     /* Add "rr_moved" entry to the root entry. */
6672                     isoent_add_child_head(rootent, rrmoved);
6673                     archive_entry_set_nlink(rootent->file->entry,
6674                         archive_entry_nlink(rootent->file->entry) + 1);
6675                     /* Register "rr_moved" entry to second level pathtable. */
6676                     path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);
6677                     /* Save rr_moved. */
6678                     *rr_moved = rrmoved;
6679           }
6680           /*
6681            * Make a clone of curent which is going to be relocated
6682            * to rr_moved.
6683            */
6684           mvent = isoent_clone(curent);
6685           if (mvent == NULL) {
6686                     archive_set_error(&a->archive, ENOMEM,
6687                         "Can't allocate memory");
6688                     return (ARCHIVE_FATAL);
6689           }
6690           /* linking..  and use for creating "CL", "PL" and "RE" */
6691           mvent->rr_parent = curent->parent;
6692           curent->rr_child = mvent;
6693           /*
6694            * Move subdirectories from the curent to mvent
6695            */
6696           if (curent->children.first != NULL) {
6697                     *mvent->children.last = curent->children.first;
6698                     mvent->children.last = curent->children.last;
6699           }
6700           for (np = mvent->children.first; np != NULL; np = np->chnext)
6701                     np->parent = mvent;
6702           mvent->children.cnt = curent->children.cnt;
6703           curent->children.cnt = 0;
6704           curent->children.first = NULL;
6705           curent->children.last = &curent->children.first;
6706 
6707           if (curent->subdirs.first != NULL) {
6708                     *mvent->subdirs.last = curent->subdirs.first;
6709                     mvent->subdirs.last = curent->subdirs.last;
6710           }
6711           mvent->subdirs.cnt = curent->subdirs.cnt;
6712           curent->subdirs.cnt = 0;
6713           curent->subdirs.first = NULL;
6714           curent->subdirs.last = &curent->subdirs.first;
6715 
6716           /*
6717            * The mvent becomes a child of the rr_moved entry.
6718            */
6719           isoent_add_child_tail(rrmoved, mvent);
6720           archive_entry_set_nlink(rrmoved->file->entry,
6721               archive_entry_nlink(rrmoved->file->entry) + 1);
6722           /*
6723            * This entry which relocated to the rr_moved directory
6724            * has to set the flag as a file.
6725            * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
6726            */
6727           curent->dir = 0;
6728 
6729           *newent = mvent;
6730 
6731           return (ARCHIVE_OK);
6732 }
6733 
6734 static int
isoent_rr_move(struct archive_write * a)6735 isoent_rr_move(struct archive_write *a)
6736 {
6737           struct iso9660 *iso9660 = a->format_data;
6738           struct path_table *pt;
6739           struct isoent *rootent, *rr_moved;
6740           struct isoent *np, *last;
6741           int r;
6742 
6743           pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
6744           /* There aren't level 8 directories reaching a deeper level. */
6745           if (pt->cnt == 0)
6746                     return (ARCHIVE_OK);
6747 
6748           rootent = iso9660->primary.rootent;
6749           /* If "rr_moved" directory is already existing,
6750            * we have to use it. */
6751           rr_moved = isoent_find_child(rootent, "rr_moved");
6752           if (rr_moved != NULL &&
6753               rr_moved != rootent->children.first) {
6754                     /*
6755                      * It's necessary that rr_move is the first entry
6756                      * of the root.
6757                      */
6758                     /* Remove "rr_moved" entry from children chain. */
6759                     isoent_remove_child(rootent, rr_moved);
6760 
6761                     /* Add "rr_moved" entry into the head of children chain. */
6762                     isoent_add_child_head(rootent, rr_moved);
6763           }
6764 
6765           /*
6766            * Check level 8 path_table.
6767            * If find out sub directory entries, that entries move to rr_move.
6768            */
6769           np = pt->first;
6770           while (np != NULL) {
6771                     last = path_table_last_entry(pt);
6772                     for (; np != NULL; np = np->ptnext) {
6773                               struct isoent *mvent;
6774                               struct isoent *newent;
6775 
6776                               if (!np->dir)
6777                                         continue;
6778                               for (mvent = np->subdirs.first;
6779                                   mvent != NULL; mvent = mvent->drnext) {
6780                                         r = isoent_rr_move_dir(a, &rr_moved,
6781                                             mvent, &newent);
6782                                         if (r < 0)
6783                                                   return (r);
6784                                         isoent_collect_dirs(&(iso9660->primary),
6785                                             newent, 2);
6786                               }
6787                     }
6788                     /* If new entries are added to level 8 path_talbe,
6789                      * its sub directory entries move to rr_move too.
6790                      */
6791                     np = last->ptnext;
6792           }
6793 
6794           return (ARCHIVE_OK);
6795 }
6796 
6797 /*
6798  * This comparing rule is according to ISO9660 Standard 6.9.1
6799  */
6800 static int
6801 __LA_LIBC_CC
_compare_path_table(const void * v1,const void * v2)6802 _compare_path_table(const void *v1, const void *v2)
6803 {
6804           const struct isoent *p1, *p2;
6805           const char *s1, *s2;
6806           int cmp, l;
6807 
6808           p1 = *((const struct isoent **)(uintptr_t)v1);
6809           p2 = *((const struct isoent **)(uintptr_t)v2);
6810 
6811           /* Compare parent directory number */
6812           cmp = p1->parent->dir_number - p2->parent->dir_number;
6813           if (cmp != 0)
6814                     return (cmp);
6815 
6816           /* Compare identifier */
6817           s1 = p1->identifier;
6818           s2 = p2->identifier;
6819           l = p1->ext_off;
6820           if (l > p2->ext_off)
6821                     l = p2->ext_off;
6822           cmp = strncmp(s1, s2, l);
6823           if (cmp != 0)
6824                     return (cmp);
6825           if (p1->ext_off < p2->ext_off) {
6826                     s2 += l;
6827                     l = p2->ext_off - p1->ext_off;
6828                     while (l--)
6829                               if (0x20 != *s2++)
6830                                         return (0x20
6831                                             - *(const unsigned char *)(s2 - 1));
6832           } else if (p1->ext_off > p2->ext_off) {
6833                     s1 += l;
6834                     l = p1->ext_off - p2->ext_off;
6835                     while (l--)
6836                               if (0x20 != *s1++)
6837                                         return (*(const unsigned char *)(s1 - 1)
6838                                             - 0x20);
6839           }
6840           return (0);
6841 }
6842 
6843 static int
6844 __LA_LIBC_CC
_compare_path_table_joliet(const void * v1,const void * v2)6845 _compare_path_table_joliet(const void *v1, const void *v2)
6846 {
6847           const struct isoent *p1, *p2;
6848           const unsigned char *s1, *s2;
6849           int cmp, l;
6850 
6851           p1 = *((const struct isoent **)(uintptr_t)v1);
6852           p2 = *((const struct isoent **)(uintptr_t)v2);
6853 
6854           /* Compare parent directory number */
6855           cmp = p1->parent->dir_number - p2->parent->dir_number;
6856           if (cmp != 0)
6857                     return (cmp);
6858 
6859           /* Compare identifier */
6860           s1 = (const unsigned char *)p1->identifier;
6861           s2 = (const unsigned char *)p2->identifier;
6862           l = p1->ext_off;
6863           if (l > p2->ext_off)
6864                     l = p2->ext_off;
6865           cmp = memcmp(s1, s2, l);
6866           if (cmp != 0)
6867                     return (cmp);
6868           if (p1->ext_off < p2->ext_off) {
6869                     s2 += l;
6870                     l = p2->ext_off - p1->ext_off;
6871                     while (l--)
6872                               if (0 != *s2++)
6873                                         return (- *(const unsigned char *)(s2 - 1));
6874           } else if (p1->ext_off > p2->ext_off) {
6875                     s1 += l;
6876                     l = p1->ext_off - p2->ext_off;
6877                     while (l--)
6878                               if (0 != *s1++)
6879                                         return (*(const unsigned char *)(s1 - 1));
6880           }
6881           return (0);
6882 }
6883 
6884 static inline void
path_table_add_entry(struct path_table * pathtbl,struct isoent * ent)6885 path_table_add_entry(struct path_table *pathtbl, struct isoent *ent)
6886 {
6887           ent->ptnext = NULL;
6888           *pathtbl->last = ent;
6889           pathtbl->last = &(ent->ptnext);
6890           pathtbl->cnt ++;
6891 }
6892 
6893 static inline struct isoent *
path_table_last_entry(struct path_table * pathtbl)6894 path_table_last_entry(struct path_table *pathtbl)
6895 {
6896           if (pathtbl->first == NULL)
6897                     return (NULL);
6898           return (((struct isoent *)(void *)
6899                     ((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));
6900 }
6901 
6902 /*
6903  * Sort directory entries in path_table
6904  * and assign directory number to each entries.
6905  */
6906 static int
isoent_make_path_table_2(struct archive_write * a,struct vdd * vdd,int depth,int * dir_number)6907 isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
6908     int depth, int *dir_number)
6909 {
6910           struct isoent *np;
6911           struct isoent **enttbl;
6912           struct path_table *pt;
6913           int i;
6914 
6915           pt = &vdd->pathtbl[depth];
6916           if (pt->cnt == 0) {
6917                     pt->sorted = NULL;
6918                     return (ARCHIVE_OK);
6919           }
6920           enttbl = malloc(pt->cnt * sizeof(struct isoent *));
6921           if (enttbl == NULL) {
6922                     archive_set_error(&a->archive, ENOMEM,
6923                         "Can't allocate memory");
6924                     return (ARCHIVE_FATAL);
6925           }
6926           pt->sorted = enttbl;
6927           for (np = pt->first; np != NULL; np = np->ptnext)
6928                     *enttbl ++ = np;
6929           enttbl = pt->sorted;
6930 
6931           switch (vdd->vdd_type) {
6932           case VDD_PRIMARY:
6933           case VDD_ENHANCED:
6934 #ifdef __COMPAR_FN_T
6935                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6936                         (__compar_fn_t)_compare_path_table);
6937 #else
6938                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6939                         _compare_path_table);
6940 #endif
6941                     break;
6942           case VDD_JOLIET:
6943 #ifdef __COMPAR_FN_T
6944                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6945                         (__compar_fn_t)_compare_path_table_joliet);
6946 #else
6947                     qsort(enttbl, pt->cnt, sizeof(struct isoent *),
6948                         _compare_path_table_joliet);
6949 #endif
6950                     break;
6951           }
6952           for (i = 0; i < pt->cnt; i++)
6953                     enttbl[i]->dir_number = (*dir_number)++;
6954 
6955           return (ARCHIVE_OK);
6956 }
6957 
6958 static int
isoent_alloc_path_table(struct archive_write * a,struct vdd * vdd,int max_depth)6959 isoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,
6960     int max_depth)
6961 {
6962           int i;
6963 
6964           vdd->max_depth = max_depth;
6965           vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);
6966           if (vdd->pathtbl == NULL) {
6967                     archive_set_error(&a->archive, ENOMEM,
6968                         "Can't allocate memory");
6969                     return (ARCHIVE_FATAL);
6970           }
6971           for (i = 0; i < vdd->max_depth; i++) {
6972                     vdd->pathtbl[i].first = NULL;
6973                     vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);
6974                     vdd->pathtbl[i].sorted = NULL;
6975                     vdd->pathtbl[i].cnt = 0;
6976           }
6977           return (ARCHIVE_OK);
6978 }
6979 
6980 /*
6981  * Make Path Tables
6982  */
6983 static int
isoent_make_path_table(struct archive_write * a)6984 isoent_make_path_table(struct archive_write *a)
6985 {
6986           struct iso9660 *iso9660 = a->format_data;
6987           int depth, r;
6988           int dir_number;
6989 
6990           /*
6991            * Init Path Table.
6992            */
6993           if (iso9660->dircnt_max >= MAX_DEPTH &&
6994               (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))
6995                     r = isoent_alloc_path_table(a, &(iso9660->primary),
6996                         iso9660->dircnt_max + 1);
6997           else
6998                     /* The number of levels in the hierarchy cannot exceed
6999                      * eight. */
7000                     r = isoent_alloc_path_table(a, &(iso9660->primary),
7001                         MAX_DEPTH);
7002           if (r < 0)
7003                     return (r);
7004           if (iso9660->opt.joliet) {
7005                     r = isoent_alloc_path_table(a, &(iso9660->joliet),
7006                         iso9660->dircnt_max + 1);
7007                     if (r < 0)
7008                               return (r);
7009           }
7010 
7011           /* Step 0.
7012            * - Collect directories for primary and joliet.
7013            */
7014           isoent_collect_dirs(&(iso9660->primary), NULL, 0);
7015           if (iso9660->opt.joliet)
7016                     isoent_collect_dirs(&(iso9660->joliet), NULL, 0);
7017           /*
7018            * Rockridge; move deeper depth directories to rr_moved.
7019            */
7020           if (iso9660->opt.rr) {
7021                     r = isoent_rr_move(a);
7022                     if (r < 0)
7023                               return (r);
7024           }
7025 
7026           /* Update nlink. */
7027           isofile_connect_hardlink_files(iso9660);
7028 
7029           /* Step 1.
7030            * - Renew a value of the depth of that directories.
7031            * - Resolve hardlinks.
7032            * - Convert pathnames to ISO9660 name or UCS2(joliet).
7033            * - Sort files by each directory.
7034            */
7035           r = isoent_traverse_tree(a, &(iso9660->primary));
7036           if (r < 0)
7037                     return (r);
7038           if (iso9660->opt.joliet) {
7039                     r = isoent_traverse_tree(a, &(iso9660->joliet));
7040                     if (r < 0)
7041                               return (r);
7042           }
7043 
7044           /* Step 2.
7045            * - Sort directories.
7046            * - Assign all directory number.
7047            */
7048           dir_number = 1;
7049           for (depth = 0; depth < iso9660->primary.max_depth; depth++) {
7050                     r = isoent_make_path_table_2(a, &(iso9660->primary),
7051                         depth, &dir_number);
7052                     if (r < 0)
7053                               return (r);
7054           }
7055           if (iso9660->opt.joliet) {
7056                     dir_number = 1;
7057                     for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {
7058                               r = isoent_make_path_table_2(a, &(iso9660->joliet),
7059                                   depth, &dir_number);
7060                               if (r < 0)
7061                                         return (r);
7062                     }
7063           }
7064           if (iso9660->opt.limit_dirs && dir_number > 0xffff) {
7065                     /*
7066                      * Maximum number of directories is 65535(0xffff)
7067                      * doe to size(16bit) of Parent Directory Number of
7068                      * the Path Table.
7069                      * See also ISO9660 Standard 9.4.
7070                      */
7071                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7072                         "Too many directories(%d) over 65535.", dir_number);
7073                     return (ARCHIVE_FATAL);
7074           }
7075 
7076           /* Get the size of the Path Table. */
7077           calculate_path_table_size(&(iso9660->primary));
7078           if (iso9660->opt.joliet)
7079                     calculate_path_table_size(&(iso9660->joliet));
7080 
7081           return (ARCHIVE_OK);
7082 }
7083 
7084 static int
isoent_find_out_boot_file(struct archive_write * a,struct isoent * rootent)7085 isoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)
7086 {
7087           struct iso9660 *iso9660 = a->format_data;
7088 
7089           /* Find a isoent of the boot file. */
7090           iso9660->el_torito.boot = isoent_find_entry(rootent,
7091               iso9660->el_torito.boot_filename.s);
7092           if (iso9660->el_torito.boot == NULL) {
7093                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7094                         "Can't find the boot image file ``%s''",
7095                         iso9660->el_torito.boot_filename.s);
7096                     return (ARCHIVE_FATAL);
7097           }
7098           iso9660->el_torito.boot->file->boot = BOOT_IMAGE;
7099           return (ARCHIVE_OK);
7100 }
7101 
7102 static int
isoent_create_boot_catalog(struct archive_write * a,struct isoent * rootent)7103 isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
7104 {
7105           struct iso9660 *iso9660 = a->format_data;
7106           struct isofile *file;
7107           struct isoent *isoent;
7108           struct archive_entry *entry;
7109 
7110           (void)rootent; /* UNUSED */
7111           /*
7112            * Create the entry which is the "boot.catalog" file.
7113            */
7114           file = isofile_new(a, NULL);
7115           if (file == NULL) {
7116                     archive_set_error(&a->archive, ENOMEM,
7117                         "Can't allocate memory");
7118                     return (ARCHIVE_FATAL);
7119           }
7120           archive_entry_set_pathname(file->entry,
7121               iso9660->el_torito.catalog_filename.s);
7122           archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);
7123           archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);
7124           archive_entry_set_atime(file->entry, iso9660->birth_time, 0);
7125           archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);
7126           archive_entry_set_uid(file->entry, getuid());
7127           archive_entry_set_gid(file->entry, getgid());
7128           archive_entry_set_mode(file->entry, AE_IFREG | 0444);
7129           archive_entry_set_nlink(file->entry, 1);
7130 
7131           if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
7132                     isofile_free(file);
7133                     return (ARCHIVE_FATAL);
7134           }
7135           file->boot = BOOT_CATALOG;
7136           file->content.size = LOGICAL_BLOCK_SIZE;
7137           isofile_add_entry(iso9660, file);
7138 
7139           isoent = isoent_new(file);
7140           if (isoent == NULL) {
7141                     archive_set_error(&a->archive, ENOMEM,
7142                         "Can't allocate memory");
7143                     return (ARCHIVE_FATAL);
7144           }
7145           isoent->virtual = 1;
7146 
7147           /* Add the "boot.catalog" entry into tree */
7148           if (isoent_tree(a, &isoent) != ARCHIVE_OK)
7149                     return (ARCHIVE_FATAL);
7150 
7151           iso9660->el_torito.catalog = isoent;
7152           /*
7153            * Get a boot media type.
7154            */
7155           switch (iso9660->opt.boot_type) {
7156           default:
7157           case OPT_BOOT_TYPE_AUTO:
7158                     /* Try detecting a media type of the boot image. */
7159                     entry = iso9660->el_torito.boot->file->entry;
7160                     if (archive_entry_size(entry) == FD_1_2M_SIZE)
7161                               iso9660->el_torito.media_type =
7162                                   BOOT_MEDIA_1_2M_DISKETTE;
7163                     else if (archive_entry_size(entry) == FD_1_44M_SIZE)
7164                               iso9660->el_torito.media_type =
7165                                   BOOT_MEDIA_1_44M_DISKETTE;
7166                     else if (archive_entry_size(entry) == FD_2_88M_SIZE)
7167                               iso9660->el_torito.media_type =
7168                                   BOOT_MEDIA_2_88M_DISKETTE;
7169                     else
7170                               /* We cannot decide whether the boot image is
7171                                * hard-disk. */
7172                               iso9660->el_torito.media_type =
7173                                   BOOT_MEDIA_NO_EMULATION;
7174                     break;
7175           case OPT_BOOT_TYPE_NO_EMU:
7176                     iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;
7177                     break;
7178           case OPT_BOOT_TYPE_HARD_DISK:
7179                     iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;
7180                     break;
7181           case OPT_BOOT_TYPE_FD:
7182                     entry = iso9660->el_torito.boot->file->entry;
7183                     if (archive_entry_size(entry) <= FD_1_2M_SIZE)
7184                               iso9660->el_torito.media_type =
7185                                   BOOT_MEDIA_1_2M_DISKETTE;
7186                     else if (archive_entry_size(entry) <= FD_1_44M_SIZE)
7187                               iso9660->el_torito.media_type =
7188                                   BOOT_MEDIA_1_44M_DISKETTE;
7189                     else if (archive_entry_size(entry) <= FD_2_88M_SIZE)
7190                               iso9660->el_torito.media_type =
7191                                   BOOT_MEDIA_2_88M_DISKETTE;
7192                     else {
7193                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7194                                   "Boot image file(``%s'') size is too big "
7195                                   "for fd type.",
7196                                   iso9660->el_torito.boot_filename.s);
7197                               return (ARCHIVE_FATAL);
7198                     }
7199                     break;
7200           }
7201 
7202           /*
7203            * Get a system type.
7204            * TODO: `El Torito' specification says "A copy of byte 5 from the
7205            *       Partition Table found in the boot image".
7206            */
7207           iso9660->el_torito.system_type = 0;
7208 
7209           /*
7210            * Get an ID.
7211            */
7212           if (iso9660->opt.publisher)
7213                     archive_string_copy(&(iso9660->el_torito.id),
7214                         &(iso9660->publisher_identifier));
7215 
7216 
7217           return (ARCHIVE_OK);
7218 }
7219 
7220 /*
7221  * If a media type is floppy, return its image size.
7222  * otherwise return 0.
7223  */
7224 static size_t
fd_boot_image_size(int media_type)7225 fd_boot_image_size(int media_type)
7226 {
7227           switch (media_type) {
7228           case BOOT_MEDIA_1_2M_DISKETTE:
7229                     return (FD_1_2M_SIZE);
7230           case BOOT_MEDIA_1_44M_DISKETTE:
7231                     return (FD_1_44M_SIZE);
7232           case BOOT_MEDIA_2_88M_DISKETTE:
7233                     return (FD_2_88M_SIZE);
7234           default:
7235                     return (0);
7236           }
7237 }
7238 
7239 /*
7240  * Make a boot catalog image data.
7241  */
7242 static int
make_boot_catalog(struct archive_write * a)7243 make_boot_catalog(struct archive_write *a)
7244 {
7245           struct iso9660 *iso9660 = a->format_data;
7246           unsigned char *block;
7247           unsigned char *p;
7248           uint16_t sum, *wp;
7249 
7250           block = wb_buffptr(a);
7251           memset(block, 0, LOGICAL_BLOCK_SIZE);
7252           p = block;
7253           /*
7254            * Validation Entry
7255            */
7256           /* Header ID */
7257           p[0] = 1;
7258           /* Platform ID */
7259           p[1] = iso9660->el_torito.platform_id;
7260           /* Reserved */
7261           p[2] = p[3] = 0;
7262           /* ID */
7263           if (archive_strlen(&(iso9660->el_torito.id)) > 0)
7264                     strncpy((char *)p+4, iso9660->el_torito.id.s, 23);
7265           p[27] = 0;
7266           /* Checksum */
7267           p[28] = p[29] = 0;
7268           /* Key */
7269           p[30] = 0x55;
7270           p[31] = 0xAA;
7271 
7272           sum = 0;
7273           wp = (uint16_t *)block;
7274           while (wp < (uint16_t *)&block[32])
7275                     sum += archive_le16dec(wp++);
7276           set_num_721(&block[28], (~sum) + 1);
7277 
7278           /*
7279            * Initial/Default Entry
7280            */
7281           p = &block[32];
7282           /* Boot Indicator */
7283           p[0] = 0x88;
7284           /* Boot media type */
7285           p[1] = iso9660->el_torito.media_type;
7286           /* Load Segment */
7287           if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
7288                     set_num_721(&p[2], iso9660->el_torito.boot_load_seg);
7289           else
7290                     set_num_721(&p[2], 0);
7291           /* System Type */
7292           p[4] = iso9660->el_torito.system_type;
7293           /* Unused */
7294           p[5] = 0;
7295           /* Sector Count */
7296           if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
7297                     set_num_721(&p[6], iso9660->el_torito.boot_load_size);
7298           else
7299                     set_num_721(&p[6], 1);
7300           /* Load RBA */
7301           set_num_731(&p[8],
7302               iso9660->el_torito.boot->file->content.location);
7303           /* Unused */
7304           memset(&p[12], 0, 20);
7305 
7306           return (wb_consume(a, LOGICAL_BLOCK_SIZE));
7307 }
7308 
7309 static int
setup_boot_information(struct archive_write * a)7310 setup_boot_information(struct archive_write *a)
7311 {
7312           struct iso9660 *iso9660 = a->format_data;
7313           struct isoent *np;
7314           int64_t size;
7315           uint32_t sum;
7316           unsigned char buff[4096];
7317 
7318           np = iso9660->el_torito.boot;
7319           lseek(iso9660->temp_fd,
7320               np->file->content.offset_of_temp + 64, SEEK_SET);
7321           size = archive_entry_size(np->file->entry) - 64;
7322           if (size <= 0) {
7323                     archive_set_error(&a->archive, errno,
7324                         "Boot file(%jd) is too small", (intmax_t)size + 64);
7325                     return (ARCHIVE_FATAL);
7326           }
7327           sum = 0;
7328           while (size > 0) {
7329                     size_t rsize;
7330                     ssize_t i, rs;
7331 
7332                     if (size > (int64_t)sizeof(buff))
7333                               rsize = sizeof(buff);
7334                     else
7335                               rsize = (size_t)size;
7336 
7337                     rs = read(iso9660->temp_fd, buff, rsize);
7338                     if (rs <= 0) {
7339                               archive_set_error(&a->archive, errno,
7340                                   "Can't read temporary file(%jd)",
7341                                   (intmax_t)rs);
7342                               return (ARCHIVE_FATAL);
7343                     }
7344                     for (i = 0; i < rs; i += 4)
7345                               sum += archive_le32dec(buff + i);
7346                     size -= rs;
7347           }
7348           /* Set the location of Primary Volume Descriptor. */
7349           set_num_731(buff, SYSTEM_AREA_BLOCK);
7350           /* Set the location of the boot file. */
7351           set_num_731(buff+4, np->file->content.location);
7352           /* Set the size of the boot file. */
7353           size = fd_boot_image_size(iso9660->el_torito.media_type);
7354           if (size == 0)
7355                     size = archive_entry_size(np->file->entry);
7356           set_num_731(buff+8, (uint32_t)size);
7357           /* Set the sum of the boot file. */
7358           set_num_731(buff+12, sum);
7359           /* Clear reserved bytes. */
7360           memset(buff+16, 0, 40);
7361 
7362           /* Overwrite the boot file. */
7363           lseek(iso9660->temp_fd,
7364               np->file->content.offset_of_temp + 8, SEEK_SET);
7365           return (write_to_temp(a, buff, 56));
7366 }
7367 
7368 #ifdef HAVE_ZLIB_H
7369 
7370 static int
zisofs_init_zstream(struct archive_write * a)7371 zisofs_init_zstream(struct archive_write *a)
7372 {
7373           struct iso9660 *iso9660 = a->format_data;
7374           int r;
7375 
7376           iso9660->zisofs.stream.next_in = NULL;
7377           iso9660->zisofs.stream.avail_in = 0;
7378           iso9660->zisofs.stream.total_in = 0;
7379           iso9660->zisofs.stream.total_out = 0;
7380           if (iso9660->zisofs.stream_valid)
7381                     r = deflateReset(&(iso9660->zisofs.stream));
7382           else {
7383                     r = deflateInit(&(iso9660->zisofs.stream),
7384                         iso9660->zisofs.compression_level);
7385                     iso9660->zisofs.stream_valid = 1;
7386           }
7387           switch (r) {
7388           case Z_OK:
7389                     break;
7390           default:
7391           case Z_STREAM_ERROR:
7392                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7393                         "Internal error initializing "
7394                         "compression library: invalid setup parameter");
7395                     return (ARCHIVE_FATAL);
7396           case Z_MEM_ERROR:
7397                     archive_set_error(&a->archive, ENOMEM,
7398                         "Internal error initializing "
7399                         "compression library");
7400                     return (ARCHIVE_FATAL);
7401           case Z_VERSION_ERROR:
7402                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7403                         "Internal error initializing "
7404                         "compression library: invalid library version");
7405                     return (ARCHIVE_FATAL);
7406           }
7407           return (ARCHIVE_OK);
7408 }
7409 
7410 #endif /* HAVE_ZLIB_H */
7411 
7412 static int
zisofs_init(struct archive_write * a,struct isofile * file)7413 zisofs_init(struct archive_write *a,  struct isofile *file)
7414 {
7415           struct iso9660 *iso9660 = a->format_data;
7416 #ifdef HAVE_ZLIB_H
7417           uint64_t tsize;
7418           size_t _ceil, bpsize;
7419           int r;
7420 #endif
7421 
7422           iso9660->zisofs.detect_magic = 0;
7423           iso9660->zisofs.making = 0;
7424 
7425           if (!iso9660->opt.rr || !iso9660->opt.zisofs)
7426                     return (ARCHIVE_OK);
7427 
7428           if (archive_entry_size(file->entry) >= 24 &&
7429               archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {
7430                     /* Acceptable file size for zisofs. */
7431                     iso9660->zisofs.detect_magic = 1;
7432                     iso9660->zisofs.magic_cnt = 0;
7433           }
7434           if (!iso9660->zisofs.detect_magic)
7435                     return (ARCHIVE_OK);
7436 
7437 #ifdef HAVE_ZLIB_H
7438           /* The number of Logical Blocks which uncompressed data
7439            * will use in iso-image file is the same as the number of
7440            * Logical Blocks which zisofs(compressed) data will use
7441            * in ISO-image file. It won't reduce iso-image file size. */
7442           if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)
7443                     return (ARCHIVE_OK);
7444 
7445           /* Initialize compression library */
7446           r = zisofs_init_zstream(a);
7447           if (r != ARCHIVE_OK)
7448                     return (ARCHIVE_FATAL);
7449 
7450           /* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
7451           file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
7452           file->zisofs.log2_bs = ZF_LOG2_BS;
7453           file->zisofs.uncompressed_size =
7454                     (uint32_t)archive_entry_size(file->entry);
7455 
7456           /* Calculate a size of Block Pointers of zisofs. */
7457           _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
7458                     >> file->zisofs.log2_bs;
7459           iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
7460           iso9660->zisofs.block_pointers_idx = 0;
7461 
7462           /* Ensure a buffer size used for Block Pointers */
7463           bpsize = iso9660->zisofs.block_pointers_cnt *
7464               sizeof(iso9660->zisofs.block_pointers[0]);
7465           if (iso9660->zisofs.block_pointers_allocated < bpsize) {
7466                     free(iso9660->zisofs.block_pointers);
7467                     iso9660->zisofs.block_pointers = malloc(bpsize);
7468                     if (iso9660->zisofs.block_pointers == NULL) {
7469                               archive_set_error(&a->archive, ENOMEM,
7470                                   "Can't allocate data");
7471                               return (ARCHIVE_FATAL);
7472                     }
7473                     iso9660->zisofs.block_pointers_allocated = bpsize;
7474           }
7475 
7476           /*
7477            * Skip zisofs header and Block Pointers, which we will write
7478            * after all compressed data of a file written to the temporary
7479            * file.
7480            */
7481           tsize = ZF_HEADER_SIZE + bpsize;
7482           if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
7483                     return (ARCHIVE_FATAL);
7484 
7485           /*
7486            * Initialize some variables to make zisofs.
7487            */
7488           archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
7489                     (uint32_t)tsize);
7490           iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
7491           iso9660->zisofs.making = 1;
7492           iso9660->zisofs.allzero = 1;
7493           iso9660->zisofs.block_offset = tsize;
7494           iso9660->zisofs.total_size = tsize;
7495           iso9660->cur_file->cur_content->size = tsize;
7496 #endif
7497 
7498           return (ARCHIVE_OK);
7499 }
7500 
7501 static void
zisofs_detect_magic(struct archive_write * a,const void * buff,size_t s)7502 zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
7503 {
7504           struct iso9660 *iso9660 = a->format_data;
7505           struct isofile *file = iso9660->cur_file;
7506           const unsigned char *p, *endp;
7507           const unsigned char *magic_buff;
7508           uint32_t uncompressed_size;
7509           unsigned char header_size;
7510           unsigned char log2_bs;
7511           size_t _ceil, doff;
7512           uint32_t bst, bed;
7513           int magic_max;
7514           int64_t entry_size;
7515 
7516           entry_size = archive_entry_size(file->entry);
7517           if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
7518                     magic_max = (int)entry_size;
7519           else
7520                     magic_max = sizeof(iso9660->zisofs.magic_buffer);
7521 
7522           if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)
7523                     /* It's unnecessary we copy buffer. */
7524                     magic_buff = buff;
7525           else {
7526                     if (iso9660->zisofs.magic_cnt < magic_max) {
7527                               size_t l;
7528 
7529                               l = sizeof(iso9660->zisofs.magic_buffer)
7530                                   - iso9660->zisofs.magic_cnt;
7531                               if (l > s)
7532                                         l = s;
7533                               memcpy(iso9660->zisofs.magic_buffer
7534                                   + iso9660->zisofs.magic_cnt, buff, l);
7535                               iso9660->zisofs.magic_cnt += (int)l;
7536                               if (iso9660->zisofs.magic_cnt < magic_max)
7537                                         return;
7538                     }
7539                     magic_buff = iso9660->zisofs.magic_buffer;
7540           }
7541           iso9660->zisofs.detect_magic = 0;
7542           p = magic_buff;
7543 
7544           /* Check the magic code of zisofs. */
7545           if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
7546                     /* This is not zisofs file which made by mkzftree. */
7547                     return;
7548           p += sizeof(zisofs_magic);
7549 
7550           /* Read a zisofs header. */
7551           uncompressed_size = archive_le32dec(p);
7552           header_size = p[4];
7553           log2_bs = p[5];
7554           if (uncompressed_size < 24 || header_size != 4 ||
7555               log2_bs > 30 || log2_bs < 7)
7556                     return;/* Invalid or not supported header. */
7557 
7558           /* Calculate a size of Block Pointers of zisofs. */
7559           _ceil = (uncompressed_size +
7560                   (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
7561           doff = (_ceil + 1) * 4 + 16;
7562           if (entry_size < (int64_t)doff)
7563                     return;/* Invalid data. */
7564 
7565           /* Check every Block Pointer has valid value. */
7566           p = magic_buff + 16;
7567           endp = magic_buff + magic_max;
7568           while (_ceil && p + 8 <= endp) {
7569                     bst = archive_le32dec(p);
7570                     if (bst != doff)
7571                               return;/* Invalid data. */
7572                     p += 4;
7573                     bed = archive_le32dec(p);
7574                     if (bed < bst || bed > entry_size)
7575                               return;/* Invalid data. */
7576                     doff += bed - bst;
7577                     _ceil--;
7578           }
7579 
7580           file->zisofs.uncompressed_size = uncompressed_size;
7581           file->zisofs.header_size = header_size;
7582           file->zisofs.log2_bs = log2_bs;
7583 
7584           /* Disable making a zisofs image. */
7585           iso9660->zisofs.making = 0;
7586 }
7587 
7588 #ifdef HAVE_ZLIB_H
7589 
7590 /*
7591  * Compress data and write it to a temporary file.
7592  */
7593 static int
zisofs_write_to_temp(struct archive_write * a,const void * buff,size_t s)7594 zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
7595 {
7596           struct iso9660 *iso9660 = a->format_data;
7597           struct isofile *file = iso9660->cur_file;
7598           const unsigned char *b;
7599           z_stream *zstrm;
7600           size_t avail, csize;
7601           int flush, r;
7602 
7603           zstrm = &(iso9660->zisofs.stream);
7604           zstrm->next_out = wb_buffptr(a);
7605           zstrm->avail_out = (uInt)wb_remaining(a);
7606           b = (const unsigned char *)buff;
7607           do {
7608                     avail = ZF_BLOCK_SIZE - zstrm->total_in;
7609                     if (s < avail) {
7610                               avail = s;
7611                               flush = Z_NO_FLUSH;
7612                     } else
7613                               flush = Z_FINISH;
7614                     iso9660->zisofs.remaining -= avail;
7615                     if (iso9660->zisofs.remaining <= 0)
7616                               flush = Z_FINISH;
7617 
7618                     zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
7619                     zstrm->avail_in = (uInt)avail;
7620 
7621                     /*
7622                      * Check if current data block are all zero.
7623                      */
7624                     if (iso9660->zisofs.allzero) {
7625                               const unsigned char *nonzero = b;
7626                               const unsigned char *nonzeroend = b + avail;
7627 
7628                               while (nonzero < nonzeroend)
7629                                         if (*nonzero++) {
7630                                                   iso9660->zisofs.allzero = 0;
7631                                                   break;
7632                                         }
7633                     }
7634                     b += avail;
7635                     s -= avail;
7636 
7637                     /*
7638                      * If current data block are all zero, we do not use
7639                      * compressed data.
7640                      */
7641                     if (flush == Z_FINISH && iso9660->zisofs.allzero &&
7642                         avail + zstrm->total_in == ZF_BLOCK_SIZE) {
7643                               if (iso9660->zisofs.block_offset !=
7644                                   file->cur_content->size) {
7645                                         int64_t diff;
7646 
7647                                         r = wb_set_offset(a,
7648                                             file->cur_content->offset_of_temp +
7649                                                 iso9660->zisofs.block_offset);
7650                                         if (r != ARCHIVE_OK)
7651                                                   return (r);
7652                                         diff = file->cur_content->size -
7653                                             iso9660->zisofs.block_offset;
7654                                         file->cur_content->size -= diff;
7655                                         iso9660->zisofs.total_size -= diff;
7656                               }
7657                               zstrm->avail_in = 0;
7658                     }
7659 
7660                     /*
7661                      * Compress file data.
7662                      */
7663                     while (zstrm->avail_in > 0) {
7664                               csize = zstrm->total_out;
7665                               r = deflate(zstrm, flush);
7666                               switch (r) {
7667                               case Z_OK:
7668                               case Z_STREAM_END:
7669                                         csize = zstrm->total_out - csize;
7670                                         if (wb_consume(a, csize) != ARCHIVE_OK)
7671                                                   return (ARCHIVE_FATAL);
7672                                         iso9660->zisofs.total_size += csize;
7673                                         iso9660->cur_file->cur_content->size += csize;
7674                                         zstrm->next_out = wb_buffptr(a);
7675                                         zstrm->avail_out = (uInt)wb_remaining(a);
7676                                         break;
7677                               default:
7678                                         archive_set_error(&a->archive,
7679                                             ARCHIVE_ERRNO_MISC,
7680                                             "Compression failed:"
7681                                             " deflate() call returned status %d",
7682                                             r);
7683                                         return (ARCHIVE_FATAL);
7684                               }
7685                     }
7686 
7687                     if (flush == Z_FINISH) {
7688                               /*
7689                                * Save the information of one zisofs block.
7690                                */
7691                               iso9660->zisofs.block_pointers_idx ++;
7692                               archive_le32enc(&(iso9660->zisofs.block_pointers[
7693                                   iso9660->zisofs.block_pointers_idx]),
7694                                         (uint32_t)iso9660->zisofs.total_size);
7695                               r = zisofs_init_zstream(a);
7696                               if (r != ARCHIVE_OK)
7697                                         return (ARCHIVE_FATAL);
7698                               iso9660->zisofs.allzero = 1;
7699                               iso9660->zisofs.block_offset = file->cur_content->size;
7700                     }
7701           } while (s);
7702 
7703           return (ARCHIVE_OK);
7704 }
7705 
7706 static int
zisofs_finish_entry(struct archive_write * a)7707 zisofs_finish_entry(struct archive_write *a)
7708 {
7709           struct iso9660 *iso9660 = a->format_data;
7710           struct isofile *file = iso9660->cur_file;
7711           unsigned char buff[16];
7712           size_t s;
7713           int64_t tail;
7714 
7715           /* Direct temp file stream to zisofs temp file stream. */
7716           archive_entry_set_size(file->entry, iso9660->zisofs.total_size);
7717 
7718           /*
7719            * Save a file pointer which points the end of current zisofs data.
7720            */
7721           tail = wb_offset(a);
7722 
7723           /*
7724            * Make a header.
7725            *
7726            * +-----------------+----------------+-----------------+
7727            * | Header 16 bytes | Block Pointers | Compressed data |
7728            * +-----------------+----------------+-----------------+
7729            * 0                16               +X
7730            * Block Pointers :
7731            *   4 * (((Uncompressed file size + block_size -1) / block_size) + 1)
7732            *
7733            * Write zisofs header.
7734            *    Magic number
7735            * +----+----+----+----+----+----+----+----+
7736            * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |
7737            * +----+----+----+----+----+----+----+----+
7738            * 0    1    2    3    4    5    6    7    8
7739            *
7740            * +------------------------+------------------+
7741            * | Uncompressed file size | header_size >> 2 |
7742            * +------------------------+------------------+
7743            * 8                       12                 13
7744            *
7745            * +-----------------+----------------+
7746            * | log2 block_size | Reserved(0000) |
7747            * +-----------------+----------------+
7748            * 13               14               16
7749            */
7750           memcpy(buff, zisofs_magic, 8);
7751           set_num_731(buff+8, file->zisofs.uncompressed_size);
7752           buff[12] = file->zisofs.header_size;
7753           buff[13] = file->zisofs.log2_bs;
7754           buff[14] = buff[15] = 0;/* Reserved */
7755 
7756           /* Move to the right position to write the header. */
7757           wb_set_offset(a, file->content.offset_of_temp);
7758 
7759           /* Write the header. */
7760           if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)
7761                     return (ARCHIVE_FATAL);
7762 
7763           /*
7764            * Write zisofs Block Pointers.
7765            */
7766           s = iso9660->zisofs.block_pointers_cnt *
7767               sizeof(iso9660->zisofs.block_pointers[0]);
7768           if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)
7769               != ARCHIVE_OK)
7770                     return (ARCHIVE_FATAL);
7771 
7772           /* Set a file pointer back to the end of the temporary file. */
7773           wb_set_offset(a, tail);
7774 
7775           return (ARCHIVE_OK);
7776 }
7777 
7778 static int
zisofs_free(struct archive_write * a)7779 zisofs_free(struct archive_write *a)
7780 {
7781           struct iso9660 *iso9660 = a->format_data;
7782           int ret = ARCHIVE_OK;
7783 
7784           free(iso9660->zisofs.block_pointers);
7785           if (iso9660->zisofs.stream_valid &&
7786               deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {
7787                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7788                         "Failed to clean up compressor");
7789                     ret = ARCHIVE_FATAL;
7790           }
7791           iso9660->zisofs.block_pointers = NULL;
7792           iso9660->zisofs.stream_valid = 0;
7793           return (ret);
7794 }
7795 
7796 struct zisofs_extract {
7797           int                  pz_log2_bs; /* Log2 of block size */
7798           uint64_t   pz_uncompressed_size;
7799           size_t               uncompressed_buffer_size;
7800 
7801           unsigned int         initialized:1;
7802           unsigned int         header_passed:1;
7803 
7804           uint32_t   pz_offset;
7805           unsigned char       *block_pointers;
7806           size_t               block_pointers_size;
7807           size_t               block_pointers_avail;
7808           size_t               block_off;
7809           uint32_t   block_avail;
7810 
7811           z_stream   stream;
7812           int                  stream_valid;
7813 };
7814 
7815 static ssize_t
zisofs_extract_init(struct archive_write * a,struct zisofs_extract * zisofs,const unsigned char * p,size_t bytes)7816 zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
7817     const unsigned char *p, size_t bytes)
7818 {
7819           size_t avail = bytes;
7820           size_t _ceil, xsize;
7821 
7822           /* Allocate block pointers buffer. */
7823           _ceil = (size_t)((zisofs->pz_uncompressed_size +
7824                     (((int64_t)1) << zisofs->pz_log2_bs) - 1)
7825                     >> zisofs->pz_log2_bs);
7826           xsize = (_ceil + 1) * 4;
7827           if (zisofs->block_pointers == NULL) {
7828                     size_t alloc = ((xsize >> 10) + 1) << 10;
7829                     zisofs->block_pointers = malloc(alloc);
7830                     if (zisofs->block_pointers == NULL) {
7831                               archive_set_error(&a->archive, ENOMEM,
7832                                   "No memory for zisofs decompression");
7833                               return (ARCHIVE_FATAL);
7834                     }
7835           }
7836           zisofs->block_pointers_size = xsize;
7837 
7838           /* Allocate uncompressed data buffer. */
7839           zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
7840 
7841           /*
7842            * Read the file header, and check the magic code of zisofs.
7843            */
7844           if (!zisofs->header_passed) {
7845                     int err = 0;
7846                     if (avail < 16) {
7847                               archive_set_error(&a->archive,
7848                                   ARCHIVE_ERRNO_FILE_FORMAT,
7849                                   "Illegal zisofs file body");
7850                               return (ARCHIVE_FATAL);
7851                     }
7852 
7853                     if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
7854                               err = 1;
7855                     else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)
7856                               err = 1;
7857                     else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)
7858                               err = 1;
7859                     if (err) {
7860                               archive_set_error(&a->archive,
7861                                   ARCHIVE_ERRNO_FILE_FORMAT,
7862                                   "Illegal zisofs file body");
7863                               return (ARCHIVE_FATAL);
7864                     }
7865                     avail -= 16;
7866                     p += 16;
7867                     zisofs->header_passed = 1;
7868           }
7869 
7870           /*
7871            * Read block pointers.
7872            */
7873           if (zisofs->header_passed &&
7874               zisofs->block_pointers_avail < zisofs->block_pointers_size) {
7875                     xsize = zisofs->block_pointers_size
7876                         - zisofs->block_pointers_avail;
7877                     if (avail < xsize)
7878                               xsize = avail;
7879                     memcpy(zisofs->block_pointers
7880                         + zisofs->block_pointers_avail, p, xsize);
7881                     zisofs->block_pointers_avail += xsize;
7882                     avail -= xsize;
7883                     if (zisofs->block_pointers_avail
7884                         == zisofs->block_pointers_size) {
7885                               /* We've got all block pointers and initialize
7886                                * related variables.         */
7887                               zisofs->block_off = 0;
7888                               zisofs->block_avail = 0;
7889                               /* Complete a initialization */
7890                               zisofs->initialized = 1;
7891                     }
7892           }
7893           return ((ssize_t)avail);
7894 }
7895 
7896 static ssize_t
zisofs_extract(struct archive_write * a,struct zisofs_extract * zisofs,const unsigned char * p,size_t bytes)7897 zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
7898     const unsigned char *p, size_t bytes)
7899 {
7900           size_t avail;
7901           int r;
7902 
7903           if (!zisofs->initialized) {
7904                     ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);
7905                     if (rs < 0)
7906                               return (rs);
7907                     if (!zisofs->initialized) {
7908                               /* We need more data. */
7909                               zisofs->pz_offset += (uint32_t)bytes;
7910                               return (bytes);
7911                     }
7912                     avail = rs;
7913                     p += bytes - avail;
7914           } else
7915                     avail = bytes;
7916 
7917           /*
7918            * Get block offsets from block pointers.
7919            */
7920           if (zisofs->block_avail == 0) {
7921                     uint32_t bst, bed;
7922 
7923                     if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
7924                               /* There isn't a pair of offsets. */
7925                               archive_set_error(&a->archive,
7926                                   ARCHIVE_ERRNO_FILE_FORMAT,
7927                                   "Illegal zisofs block pointers");
7928                               return (ARCHIVE_FATAL);
7929                     }
7930                     bst = archive_le32dec(
7931                         zisofs->block_pointers + zisofs->block_off);
7932                     if (bst != zisofs->pz_offset + (bytes - avail)) {
7933                               archive_set_error(&a->archive,
7934                                   ARCHIVE_ERRNO_FILE_FORMAT,
7935                                   "Illegal zisofs block pointers(cannot seek)");
7936                               return (ARCHIVE_FATAL);
7937                     }
7938                     bed = archive_le32dec(
7939                         zisofs->block_pointers + zisofs->block_off + 4);
7940                     if (bed < bst) {
7941                               archive_set_error(&a->archive,
7942                                   ARCHIVE_ERRNO_FILE_FORMAT,
7943                                   "Illegal zisofs block pointers");
7944                               return (ARCHIVE_FATAL);
7945                     }
7946                     zisofs->block_avail = bed - bst;
7947                     zisofs->block_off += 4;
7948 
7949                     /* Initialize compression library for new block. */
7950                     if (zisofs->stream_valid)
7951                               r = inflateReset(&zisofs->stream);
7952                     else
7953                               r = inflateInit(&zisofs->stream);
7954                     if (r != Z_OK) {
7955                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
7956                                   "Can't initialize zisofs decompression.");
7957                               return (ARCHIVE_FATAL);
7958                     }
7959                     zisofs->stream_valid = 1;
7960                     zisofs->stream.total_in = 0;
7961                     zisofs->stream.total_out = 0;
7962           }
7963 
7964           /*
7965            * Make uncompressed data.
7966            */
7967           if (zisofs->block_avail == 0) {
7968                     /*
7969                      * It's basically 32K bytes NUL data.
7970                      */
7971                     unsigned char *wb;
7972                     size_t size, wsize;
7973 
7974                     size = zisofs->uncompressed_buffer_size;
7975                     while (size) {
7976                               wb = wb_buffptr(a);
7977                               if (size > wb_remaining(a))
7978                                         wsize = wb_remaining(a);
7979                               else
7980                                         wsize = size;
7981                               memset(wb, 0, wsize);
7982                               r = wb_consume(a, wsize);
7983                               if (r < 0)
7984                                         return (r);
7985                               size -= wsize;
7986                     }
7987           } else {
7988                     zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
7989                     if (avail > zisofs->block_avail)
7990                               zisofs->stream.avail_in = zisofs->block_avail;
7991                     else
7992                               zisofs->stream.avail_in = (uInt)avail;
7993                     zisofs->stream.next_out = wb_buffptr(a);
7994                     zisofs->stream.avail_out = (uInt)wb_remaining(a);
7995 
7996                     r = inflate(&zisofs->stream, 0);
7997                     switch (r) {
7998                     case Z_OK: /* Decompressor made some progress.*/
7999                     case Z_STREAM_END: /* Found end of stream. */
8000                               break;
8001                     default:
8002                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8003                                   "zisofs decompression failed (%d)", r);
8004                               return (ARCHIVE_FATAL);
8005                     }
8006                     avail -= zisofs->stream.next_in - p;
8007                     zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
8008                     r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
8009                     if (r < 0)
8010                               return (r);
8011           }
8012           zisofs->pz_offset += (uint32_t)bytes;
8013           return (bytes - avail);
8014 }
8015 
8016 static int
zisofs_rewind_boot_file(struct archive_write * a)8017 zisofs_rewind_boot_file(struct archive_write *a)
8018 {
8019           struct iso9660 *iso9660 = a->format_data;
8020           struct isofile *file;
8021           unsigned char *rbuff;
8022           ssize_t r;
8023           size_t remaining, rbuff_size;
8024           struct zisofs_extract zext;
8025           int64_t read_offset, write_offset, new_offset;
8026           int fd, ret = ARCHIVE_OK;
8027 
8028           file = iso9660->el_torito.boot->file;
8029           /*
8030            * There is nothing to do if this boot file does not have
8031            * zisofs header.
8032            */
8033           if (file->zisofs.header_size == 0)
8034                     return (ARCHIVE_OK);
8035 
8036           /*
8037            * Uncompress the zisofs'ed file contents.
8038            */
8039           memset(&zext, 0, sizeof(zext));
8040           zext.pz_uncompressed_size = file->zisofs.uncompressed_size;
8041           zext.pz_log2_bs = file->zisofs.log2_bs;
8042 
8043           fd = iso9660->temp_fd;
8044           new_offset = wb_offset(a);
8045           read_offset = file->content.offset_of_temp;
8046           remaining = (size_t)file->content.size;
8047           if (remaining > 1024 * 32)
8048                     rbuff_size = 1024 * 32;
8049           else
8050                     rbuff_size = remaining;
8051 
8052           rbuff = malloc(rbuff_size);
8053           if (rbuff == NULL) {
8054                     archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
8055                     return (ARCHIVE_FATAL);
8056           }
8057           while (remaining) {
8058                     size_t rsize;
8059                     ssize_t rs;
8060 
8061                     /* Get the current file pointer. */
8062                     write_offset = lseek(fd, 0, SEEK_CUR);
8063 
8064                     /* Change the file pointer to read. */
8065                     lseek(fd, read_offset, SEEK_SET);
8066 
8067                     rsize = rbuff_size;
8068                     if (rsize > remaining)
8069                               rsize = remaining;
8070                     rs = read(iso9660->temp_fd, rbuff, rsize);
8071                     if (rs <= 0) {
8072                               archive_set_error(&a->archive, errno,
8073                                   "Can't read temporary file(%jd)", (intmax_t)rs);
8074                               ret = ARCHIVE_FATAL;
8075                               break;
8076                     }
8077                     remaining -= rs;
8078                     read_offset += rs;
8079 
8080                     /* Put the file pointer back to write. */
8081                     lseek(fd, write_offset, SEEK_SET);
8082 
8083                     r = zisofs_extract(a, &zext, rbuff, rs);
8084                     if (r < 0) {
8085                               ret = (int)r;
8086                               break;
8087                     }
8088           }
8089 
8090           if (ret == ARCHIVE_OK) {
8091                     /*
8092                      * Change the boot file content from zisofs'ed data
8093                      * to plain data.
8094                      */
8095                     file->content.offset_of_temp = new_offset;
8096                     file->content.size = file->zisofs.uncompressed_size;
8097                     archive_entry_set_size(file->entry, file->content.size);
8098                     /* Set to be no zisofs. */
8099                     file->zisofs.header_size = 0;
8100                     file->zisofs.log2_bs = 0;
8101                     file->zisofs.uncompressed_size = 0;
8102                     r = wb_write_padding_to_temp(a, file->content.size);
8103                     if (r < 0)
8104                               ret = ARCHIVE_FATAL;
8105           }
8106 
8107           /*
8108            * Free the resource we used in this function only.
8109            */
8110           free(rbuff);
8111           free(zext.block_pointers);
8112           if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {
8113           archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8114                         "Failed to clean up compressor");
8115                     ret = ARCHIVE_FATAL;
8116           }
8117 
8118           return (ret);
8119 }
8120 
8121 #else
8122 
8123 static int
zisofs_write_to_temp(struct archive_write * a,const void * buff,size_t s)8124 zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
8125 {
8126           (void)buff; /* UNUSED */
8127           (void)s; /* UNUSED */
8128           archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programming error");
8129           return (ARCHIVE_FATAL);
8130 }
8131 
8132 static int
zisofs_rewind_boot_file(struct archive_write * a)8133 zisofs_rewind_boot_file(struct archive_write *a)
8134 {
8135           struct iso9660 *iso9660 = a->format_data;
8136 
8137           if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {
8138                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
8139                         "We cannot extract the zisofs imaged boot file;"
8140                         " this may not boot in being zisofs imaged");
8141                     return (ARCHIVE_FAILED);
8142           }
8143           return (ARCHIVE_OK);
8144 }
8145 
8146 static int
zisofs_finish_entry(struct archive_write * a)8147 zisofs_finish_entry(struct archive_write *a)
8148 {
8149           (void)a; /* UNUSED */
8150           return (ARCHIVE_OK);
8151 }
8152 
8153 static int
zisofs_free(struct archive_write * a)8154 zisofs_free(struct archive_write *a)
8155 {
8156           (void)a; /* UNUSED */
8157           return (ARCHIVE_OK);
8158 }
8159 
8160 #endif /* HAVE_ZLIB_H */
8161 
8162