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