1 /* 2 * Program mkisofs.c - generate iso9660 filesystem based upon directory 3 * tree on hard disk. 4 5 Written by Eric Youngdale (1993). 6 7 Copyright 1993 Yggdrasil Computing, Incorporated 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 22 23 /* APPLE_HYB James Pearson j.pearson (at) ge.ucl.ac.uk 12/3/99 */ 24 25 #include <errno.h> 26 #include "config.h" 27 #include "mkisofs.h" 28 #include "match.h" 29 #include "apple_proto.h" 30 31 #include "getopt.h" /* Always include local (nonstandard) getopt.h */ 32 33 #include "iso9660.h" 34 #include <ctype.h> 35 36 #ifndef VMS 37 #include <time.h> 38 #else 39 #include <sys/time.h> 40 #include "vms.h" 41 #endif 42 43 #include <stdlib.h> 44 #include <sys/stat.h> 45 46 #ifndef VMS 47 #ifdef HAVE_UNISTD_H 48 #include <unistd.h> 49 #endif 50 #endif 51 #include <fctldefs.h> 52 53 struct directory * root = NULL; 54 55 #ifdef APPLE_HYB 56 static char version_string[] = "mkhybrid 1.12b5.1"; 57 #else 58 static char version_string[] = "mkisofs 1.12b5"; 59 #endif /* APPLE_HYB */ 60 61 char * outfile; 62 FILE * discimage; 63 unsigned int next_extent = 0; 64 unsigned int last_extent = 0; 65 unsigned int session_start = 0; 66 unsigned int path_table_size = 0; 67 unsigned int path_table[4] = {0,}; 68 unsigned int path_blocks = 0; 69 70 71 unsigned int jpath_table_size = 0; 72 unsigned int jpath_table[4] = {0,}; 73 unsigned int jpath_blocks = 0; 74 75 struct iso_directory_record root_record; 76 struct iso_directory_record jroot_record; 77 78 char * extension_record = NULL; 79 int extension_record_extent = 0; 80 int extension_record_size = 0; 81 82 /* These variables are associated with command line options */ 83 int use_eltorito = 0; 84 int use_RockRidge = 0; 85 int use_Joliet = 0; 86 int verbose = 1; 87 int all_files = 0; 88 int follow_links = 0; 89 int rationalize = 0; 90 int generate_tables = 0; 91 int print_size = 0; 92 int split_output = 0; 93 char * preparer = PREPARER_DEFAULT; 94 char * publisher = PUBLISHER_DEFAULT; 95 char * appid = APPID_DEFAULT; 96 char * copyright = COPYRIGHT_DEFAULT; 97 char * biblio = BIBLIO_DEFAULT; 98 char * abstract = ABSTRACT_DEFAULT; 99 char * volset_id = VOLSET_ID_DEFAULT; 100 char * volume_id = VOLUME_ID_DEFAULT; 101 char * system_id = SYSTEM_ID_DEFAULT; 102 char * boot_catalog = BOOT_CATALOG_DEFAULT; 103 char * boot_image = BOOT_IMAGE_DEFAULT; 104 int volume_set_size = 1; 105 int volume_sequence_number = 1; 106 107 int use_graft_ptrs = 0; /* Use graft points */ 108 int jhide_trans_tbl; /* Hide TRANS.TBL from Joliet tree */ 109 int hide_rr_moved; /* Name RR_MOVED .rr_moved in Rock Ridge tree */ 110 int omit_period = 0; /* Violates iso9660, but these are a pain */ 111 int transparent_compression = 0; /* So far only works with linux */ 112 int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/ 113 int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ 114 int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with 115 DOS */ 116 int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ 117 int split_SL_component = 1; /* circumvent a bug in the SunOS driver */ 118 int split_SL_field = 1; /* circumvent a bug in the SunOS */ 119 120 #ifdef APPLE_HYB 121 int apple_hyb = 0; /* create HFS hybrid flag */ 122 int apple_ext = 0; /* create HFS extensions flag */ 123 int apple_both = 0; /* common flag (for above) */ 124 int hfs_extra = 0; /* extra HFS blocks added to end of ISO vol */ 125 int mac_name = 0; /* use Mac name for ISO/Joliet/RR flag */ 126 hce_mem *hce; /* libhfs/mkisofs extras */ 127 char *hfs_boot_file = 0; /* name of HFS boot file */ 128 int gen_pt = 0; /* generate HFS partition table */ 129 char *autoname = 0; /* AutoStart filename */ 130 char *magic_file = 0; /* name of magic file */ 131 int probe = 0; /* search files for HFS/Unix type */ 132 int nomacfiles = 0; /* don't look for Mac/Unix files */ 133 int hfs_select = 0; /* Mac/Unix types to select */ 134 int create_dt = 1; /* create the Desktp files */ 135 int afe_size = 0; /* Apple File Exchange block size */ 136 int hfs_last = MAG_LAST; /* process magic file after map file */ 137 char *deftype = DEFTYPE; /* default Apple TYPE */ 138 char *defcreator = DEFCREATOR; /* default Apple CREATOR */ 139 char *trans_tbl = "TRANS.TBL"; /* default name for translation table */ 140 char *hfs_volume_id = NULL; /* HFS volume ID */ 141 char *hfs_bless = NULL; /* name of folder to 'bless' (System Folder) */ 142 143 #endif /* APPLE_HYB */ 144 145 struct rcopts{ 146 char * tag; 147 char ** variable; 148 }; 149 150 struct rcopts rcopt[] = { 151 {"PREP", &preparer}, 152 {"PUBL", &publisher}, 153 {"APPI", &appid}, 154 {"COPY", ©right}, 155 {"BIBL", &biblio}, 156 {"ABST", &abstract}, 157 {"VOLS", &volset_id}, 158 {"VOLI", &volume_id}, 159 {"SYSI", &system_id}, 160 #ifdef APPLE_HYB 161 {"TYPE", &deftype}, 162 {"CREATOR", &defcreator}, 163 #endif /* APPLE_HYB */ 164 {NULL, NULL} 165 }; 166 167 /* 168 * In case it isn't obvious, the option handling code was ripped off from GNU-ld. 169 */ 170 struct ld_option 171 { 172 /* The long option information. */ 173 struct option opt; 174 /* The short option with the same meaning ('\0' if none). */ 175 char shortopt; 176 /* The name of the argument (NULL if none). */ 177 const char *arg; 178 /* The documentation string. If this is NULL, this is a synonym for 179 the previous option. */ 180 const char *doc; 181 enum 182 { 183 /* Use one dash before long option name. */ 184 ONE_DASH, 185 /* Use two dashes before long option name. */ 186 TWO_DASHES, 187 /* Don't mention this option in --help output. */ 188 NO_HELP 189 } control; 190 }; 191 192 /* Codes used for the long options with no short synonyms. 150 isn't 193 special; it's just an arbitrary non-ASCII char value. */ 194 #define OPTION_HELP 150 195 #define OPTION_QUIET 151 196 #define OPTION_NOSPLIT_SL_COMPONENT 152 197 #define OPTION_NOSPLIT_SL_FIELD 153 198 #define OPTION_PRINT_SIZE 154 199 #define OPTION_SPLIT_OUTPUT 155 200 #define OPTION_ABSTRACT 156 201 #define OPTION_BIBLIO 157 202 #define OPTION_COPYRIGHT 158 203 #define OPTION_SYSID 159 204 #define OPTION_VOLSET 160 205 #define OPTION_VOLSET_SIZE 161 206 #define OPTION_VOLSET_SEQ_NUM 162 207 #define OPTION_I_HIDE 163 208 #define OPTION_J_HIDE 164 209 #define OPTION_LOG_FILE 165 210 #if 0 211 #define OPTION_PVERSION 166 212 #define OPTION_NOBAK 167 213 #define OPTION_SPARCLABEL 168 214 #define OPTION_HARD_DISK_BOOT 169 215 #define OPTION_NO_EMUL_BOOT 170 216 #define OPTION_NO_BOOT 171 217 #define OPTION_BOOT_LOAD_ADDR 172 218 #define OPTION_BOOT_LOAD_SIZE 173 219 #define OPTION_BOOT_INFO_TABLE 174 220 #endif 221 #define OPTION_HIDE_TRANS_TBL 175 222 #define OPTION_HIDE_RR_MOVED 176 223 #if 0 224 #define OPTION_GUI 177 225 #endif 226 #define OPTION_TRANS_TBL 178 227 #define OPTION_P_LIST 179 228 #define OPTION_I_LIST 180 229 #define OPTION_J_LIST 181 230 #define OPTION_X_LIST 182 231 #if 0 232 #define OPTION_NO_RR 183 233 #define OPTION_JCHARSET 184 234 #define OPTION_PAD 185 235 #define OPTION_H_HIDE 186 236 #define OPTION_H_LIST 187 237 #define OPTION_CHECK_OLDNAMES 188 238 239 #ifdef SORTING 240 #define OPTION_SORT 189 241 #endif /* SORTING */ 242 #define OPTION_UCS_LEVEL 190 243 #define OPTION_ISO_TRANSLATE 191 244 #define OPTION_ISO_LEVEL 192 245 #define OPTION_RELAXED_FILENAMES 193 246 #define OPTION_ALLOW_LOWERCASE 194 247 #define OPTION_ALLOW_MULTIDOT 195 248 #define OPTION_USE_FILEVERSION 196 249 #define OPTION_MAX_FILENAMES 197 250 #define OPTION_ALT_BOOT 198 251 #endif 252 #define OPTION_USE_GRAFT 199 253 254 #ifdef APPLE_HYB 255 #define OPTION_CAP 200 256 #define OPTION_NETA 201 257 #define OPTION_DBL 202 258 #define OPTION_ESH 203 259 #define OPTION_FE 204 260 #define OPTION_SGI 205 261 #define OPTION_MBIN 206 262 #define OPTION_SGL 207 263 /* aliases */ 264 #define OPTION_USH 208 265 #define OPTION_XIN 209 266 267 #if 0 268 #define OPTION_DAVE 210 269 #define OPTION_SFM 211 270 #endif 271 272 #define OPTION_PROBE 220 273 #define OPTION_MACNAME 221 274 #define OPTION_NOMACFILES 222 275 #define OPTION_BOOT_HFS_FILE 223 276 #define OPTION_MAGIC_FILE 224 277 278 #define OPTION_HFS_LIST 225 279 280 #define OPTION_GEN_PT 226 281 282 #define OPTION_CREATE_DT 227 283 #define OPTION_HFS_HIDE 228 284 285 #define OPTION_AUTOSTART 229 286 #define OPTION_BSIZE 230 287 #define OPTION_HFS_VOLID 231 288 289 #define OPTION_HFS_BLESS 245 290 #endif /* APPLE_HYB */ 291 292 static int save_pname = 0; 293 294 static const struct ld_option ld_options[] = 295 { 296 { {"all-files", no_argument, NULL, 'a'}, 297 'a', NULL, "Process all files (don't skip backup files)", ONE_DASH }, 298 { {"abstract", required_argument, NULL, OPTION_ABSTRACT}, 299 '\0', "FILE", "Set Abstract filename" , ONE_DASH }, 300 { {"appid", required_argument, NULL, 'A'}, 301 'A', "ID", "Set Application ID" , ONE_DASH }, 302 { {"biblio", required_argument, NULL, OPTION_BIBLIO}, 303 '\0', "FILE", "Set Bibliographic filename" , ONE_DASH }, 304 { {"copyright", required_argument, NULL, OPTION_COPYRIGHT}, 305 '\0', "FILE", "Set Copyright filename" , ONE_DASH }, 306 { {"eltorito-boot", required_argument, NULL, 'b'}, 307 'b', "FILE", "Set El Torito boot image name" , ONE_DASH }, 308 { {"eltorito-catalog", required_argument, NULL, 'c'}, 309 'c', "FILE", "Set El Torito boot catalog name" , ONE_DASH }, 310 { {"cdwrite-params", required_argument, NULL, 'C'}, 311 'C', "PARAMS", "Magic paramters from cdrecord" , ONE_DASH }, 312 { {"omit-period", no_argument, NULL, 'd'}, 313 'd', NULL, "Omit trailing periods from filenames", ONE_DASH }, 314 { {"disable-deep-relocation", no_argument, NULL, 'D'}, 315 'D', NULL, "Disable deep directory relocation", ONE_DASH }, 316 { {"follow-links", no_argument, NULL, 'f'}, 317 'f', NULL, "Follow symbolic links", ONE_DASH }, 318 {{"graft-points", no_argument, NULL, OPTION_USE_GRAFT}, 319 '\0', NULL, "Allow to use graft points for filenames", ONE_DASH}, 320 { {"help", no_argument, NULL, OPTION_HELP}, 321 '\0', NULL, "Print option help", ONE_DASH }, 322 { {"hide", required_argument, NULL, OPTION_I_HIDE}, 323 '\0', "GLOBFILE", "Hide ISO9660/RR file" , ONE_DASH }, 324 { {"hide-list", required_argument, NULL, OPTION_I_LIST}, 325 '\0', "FILE", "list of ISO9660/RR files to hide" , ONE_DASH }, 326 { {"hide-joliet", required_argument, NULL, OPTION_J_HIDE}, 327 '\0', "GLOBFILE", "Hide Joliet file" , ONE_DASH }, 328 { {"hide-joliet-list", required_argument, NULL, OPTION_J_LIST}, 329 '\0', "FILE", "List of Joliet files to hide" , ONE_DASH }, 330 {{"hide-joliet-trans-tbl", no_argument, NULL, OPTION_HIDE_TRANS_TBL}, 331 '\0', NULL, "Hide TRANS.TBL from Joliet tree", ONE_DASH}, 332 {{"hide-rr-moved", no_argument, NULL, OPTION_HIDE_RR_MOVED}, 333 '\0', NULL, "Rename RR_MOVED to .rr_moved in Rock Ridge tree", ONE_DASH}, 334 { {NULL, required_argument, NULL, 'i'}, 335 'i', "ADD_FILES", "No longer supported" , TWO_DASHES }, 336 { {"joliet", no_argument, NULL, 'J'}, 337 'J', NULL, "Generate Joliet directory information", ONE_DASH }, 338 { {"full-iso9660-filenames", no_argument, NULL, 'l'}, 339 'l', NULL, "Allow full 32 character filenames for iso9660 names", ONE_DASH }, 340 { {"allow-leading-dots", no_argument, NULL, 'L'}, 341 'L', NULL, "Allow iso9660 filenames to start with '.'", ONE_DASH }, 342 { {"log-file", required_argument, NULL, OPTION_LOG_FILE}, 343 '\0', "LOG_FILE", "Re-direct messages to LOG_FILE", ONE_DASH }, 344 { {"exclude", required_argument, NULL, 'm'}, 345 'm', "GLOBFILE", "Exclude file name" , ONE_DASH }, 346 { {"exclude-list", required_argument, NULL, OPTION_X_LIST}, 347 'm', "FILE", "List of file names to exclude" , ONE_DASH }, 348 { {"prev-session", required_argument, NULL, 'M'}, 349 'M', "FILE", "Set path to previous session to merge" , ONE_DASH }, 350 { {"omit-version-number", no_argument, NULL, 'N'}, 351 'N', NULL, "Omit version number from iso9660 filename", ONE_DASH }, 352 { {"no-split-symlink-components", no_argument, NULL, 0}, 353 0, NULL, "Inhibit splitting symlink components" , ONE_DASH }, 354 { {"no-split-symlink-fields", no_argument, NULL, 0}, 355 0, NULL, "Inhibit splitting symlink fields" , ONE_DASH }, 356 { {"output", required_argument, NULL, 'o'}, 357 'o', "FILE", "Set output file name" , ONE_DASH }, 358 { {"path-list", required_argument, NULL, OPTION_P_LIST}, 359 '\0', "FILE", "list of pathnames to process" , ONE_DASH }, 360 { {"preparer", required_argument, NULL, 'p'}, 361 'p', "PREP", "Set Volume preparer" , ONE_DASH }, 362 { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE}, 363 '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH }, 364 { {"publisher", required_argument, NULL, 'P'}, 365 'P', "PUB", "Set Volume publisher" , ONE_DASH }, 366 { {"quiet", no_argument, NULL, OPTION_QUIET}, 367 '\0', NULL, "Run quietly", ONE_DASH }, 368 { {"rational-rock", no_argument, NULL, 'r'}, 369 'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH }, 370 { {"rock", no_argument, NULL, 'R'}, 371 'R', NULL, "Generate Rock Ridge directory information", ONE_DASH }, 372 { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT}, 373 '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH }, 374 { {"sysid", required_argument, NULL, OPTION_SYSID}, 375 '\0', "ID", "Set System ID" , ONE_DASH }, 376 { {"translation-table", no_argument, NULL, 'T'}, 377 'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH }, 378 { {"verbose", no_argument, NULL, 'v'}, 379 'v', NULL, "Verbose", ONE_DASH }, 380 { {"volid", required_argument, NULL, 'V'}, 381 'V', "ID", "Set Volume ID" , ONE_DASH }, 382 { {"volset", required_argument, NULL, OPTION_VOLSET}, 383 '\0', "ID", "Set Volume set ID" , ONE_DASH }, 384 { {"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE}, 385 '\0', "#", "Set Volume set size" , ONE_DASH }, 386 { {"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM}, 387 '\0', "#", "Set Volume set sequence number" , ONE_DASH }, 388 { {"old-exclude", required_argument, NULL, 'x'}, 389 'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH }, 390 #ifdef ERIC_neverdef 391 { {"transparent-compression", no_argument, NULL, 'z'}, 392 'z', NULL, "Enable transparent compression of files", ONE_DASH }, 393 #endif 394 #ifdef APPLE_HYB 395 { {"apple", no_argument, NULL, 'g'}, 396 'g', NULL, "Add Apple ISO9660 extensions", ONE_DASH }, 397 { {"hfs", no_argument, NULL, 'h'}, 398 'h', NULL, "Create ISO9660/HFS hybrid", ONE_DASH }, 399 { {"map", required_argument, NULL, 'H'}, 400 'H', "MAPPING_FILE", "Map file extensions to HFS TYPE/CREATOR", ONE_DASH}, 401 { {"magic", required_argument, NULL, OPTION_MAGIC_FILE}, 402 '\0', "FILE", "Magic file for HFS TYPE/CREATOR", ONE_DASH}, 403 { {"probe", no_argument, NULL, OPTION_PROBE}, 404 '\0', NULL, "Probe all files for Unix/HFS file type", ONE_DASH }, 405 { {"mac-name", no_argument, NULL, OPTION_MACNAME}, 406 '\0', NULL, "Use Macintosh name for ISO9660/Joliet/RockRidge file name", 407 ONE_DASH }, 408 { {"no-mac-files", no_argument, NULL, OPTION_NOMACFILES}, 409 '\0', NULL, "Do not look for Unix/Mac files", ONE_DASH }, 410 { {"boot-hfs-file", required_argument, NULL, OPTION_BOOT_HFS_FILE}, 411 '\0', "FILE", "Set HFS boot image name", ONE_DASH}, 412 { {"part", no_argument, NULL, OPTION_GEN_PT}, 413 '\0', NULL, "Generate HFS partition table", ONE_DASH }, 414 { {"cluster-size", required_argument, NULL, OPTION_BSIZE}, 415 '\0', "SIZE", "Cluster size for PC Exchange Macintosh files", ONE_DASH}, 416 { {"auto", required_argument, NULL, OPTION_AUTOSTART}, 417 '\0', "FILE", "Set HFS AutoStart file name", ONE_DASH}, 418 { {"no-desktop", no_argument, NULL, OPTION_CREATE_DT}, 419 '\0', NULL, "Do not create the HFS (empty) Desktop files", ONE_DASH }, 420 { {"hide-hfs", required_argument, NULL, OPTION_HFS_HIDE}, 421 '\0', "GLOBFILE", "Hide HFS file" , ONE_DASH }, 422 { {"hide-hfs-list", required_argument, NULL, OPTION_HFS_LIST}, 423 '\0', "GLOBFILE", "List of HFS files to hide" , ONE_DASH }, 424 { {"table-name", required_argument, NULL, OPTION_TRANS_TBL}, 425 '\0', "TABLE_NAME", "translation table file name", ONE_DASH }, 426 { {"hfs-volid", required_argument, NULL, OPTION_HFS_VOLID}, 427 '\0', "HFS_VOLID", "Volume name for the HFS partition", ONE_DASH }, 428 {{"hfs-bless", required_argument, NULL, OPTION_HFS_BLESS}, 429 '\0', "FOLDER_NAME", "Name of Folder to be blessed", ONE_DASH}, 430 { {"cap", no_argument, NULL, OPTION_CAP}, 431 '\0', NULL, "Look for AUFS CAP Macintosh files", TWO_DASHES }, 432 { {"netatalk", no_argument, NULL, OPTION_NETA}, 433 '\0', NULL, "Look for NETATALK Macintosh files", TWO_DASHES }, 434 { {"double", no_argument, NULL, OPTION_DBL}, 435 '\0', NULL, "Look for AppleDouble Macintosh files", TWO_DASHES }, 436 { {"ethershare", no_argument, NULL, OPTION_ESH}, 437 '\0', NULL, "Look for Helios EtherShare Macintosh files", TWO_DASHES }, 438 { {"exchange", no_argument, NULL, OPTION_FE}, 439 '\0', NULL, "Look for PC Exchange Macintosh files", TWO_DASHES }, 440 { {"sgi", no_argument, NULL, OPTION_SGI}, 441 '\0', NULL, "Look for SGI Macintosh files", TWO_DASHES }, 442 { {"macbin", no_argument, NULL, OPTION_MBIN}, 443 '\0', NULL, "Look for MacBinary Macintosh files", TWO_DASHES }, 444 { {"single", no_argument, NULL, OPTION_SGL}, 445 '\0', NULL, "Look for AppleSingle Macintosh files", TWO_DASHES }, 446 { {"ushare", no_argument, NULL, OPTION_USH}, 447 '\0', NULL, "Look for IPT UShare Macintosh files", TWO_DASHES }, 448 { {"xinet", no_argument, NULL, OPTION_XIN}, 449 '\0', NULL, "Look for XINET Macintosh files", TWO_DASHES }, 450 #endif /* APPLE_HYB */ 451 }; 452 453 #define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0]) 454 455 #if defined(ultrix) || defined(_AUX_SOURCE) 456 char *strdup(s) 457 char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} 458 #endif 459 460 void read_rcfile __PR((char * appname)); 461 void usage __PR((void)); 462 static void hide_reloc_dir __PR((void)); 463 static char * get_pnames __PR((int argc, char **argv, int opt, 464 char *pname, int pnsize, FILE * fp)); 465 466 int main __PR((int argc, char **argv)); 467 char * findequal __PR((char *s)); 468 char * escstrcpy __PR((char *to, char *from)); 469 470 void FDECL1(read_rcfile, char *, appname) 471 { 472 FILE * rcfile; 473 struct rcopts * rco; 474 char * pnt, *pnt1; 475 char linebuffer[256]; 476 static char rcfn[] = ".mkisofsrc"; 477 char filename[1000]; 478 int linum; 479 480 strcpy(filename, rcfn); 481 rcfile = fopen(filename, "r"); 482 if (!rcfile && errno != ENOENT) 483 perror(filename); 484 485 if (!rcfile) 486 { 487 pnt = getenv("MKISOFSRC"); 488 if (pnt && strlen(pnt) <= sizeof(filename)) 489 { 490 strcpy(filename, pnt); 491 rcfile = fopen(filename, "r"); 492 if (!rcfile && errno != ENOENT) 493 perror(filename); 494 } 495 } 496 497 if (!rcfile) 498 { 499 pnt = getenv("HOME"); 500 if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename)) 501 { 502 strcpy(filename, pnt); 503 strcat(filename, "/"); 504 strcat(filename, rcfn); 505 rcfile = fopen(filename, "r"); 506 if (!rcfile && errno != ENOENT) 507 perror(filename); 508 } 509 } 510 if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename)) 511 { 512 strcpy(filename, appname); 513 pnt = strrchr(filename, '/'); 514 if (pnt) 515 { 516 strcpy(pnt + 1, rcfn); 517 rcfile = fopen(filename, "r"); 518 if (!rcfile && errno != ENOENT) 519 perror(filename); 520 } 521 } 522 if (!rcfile) 523 return; 524 if ( verbose > 0 ) 525 { 526 fprintf(stderr, "Using \"%s\"\n", filename); 527 } 528 529 /* OK, we got it. Now read in the lines and parse them */ 530 linum = 0; 531 while (fgets(linebuffer, sizeof(linebuffer), rcfile)) 532 { 533 char *name; 534 char *name_end; 535 ++linum; 536 /* skip any leading white space */ 537 pnt = linebuffer; 538 while (*pnt == ' ' || *pnt == '\t') 539 ++pnt; 540 /* If we are looking at a # character, this line is a comment. */ 541 if (*pnt == '#') 542 continue; 543 /* The name should begin in the left margin. Make sure it is in 544 upper case. Stop when we see white space or a comment. */ 545 name = pnt; 546 while (*pnt && isalpha((unsigned char)*pnt)) 547 { 548 if(islower((unsigned char)*pnt)) 549 *pnt = toupper((unsigned char)*pnt); 550 pnt++; 551 } 552 if (name == pnt) 553 { 554 fprintf(stderr, "%s:%d: name required\n", filename, linum); 555 continue; 556 } 557 name_end = pnt; 558 /* Skip past white space after the name */ 559 while (*pnt == ' ' || *pnt == '\t') 560 pnt++; 561 /* silently ignore errors in the rc file. */ 562 if (*pnt != '=') 563 { 564 fprintf(stderr, "%s:%d: equals sign required\n", filename, linum); 565 continue; 566 } 567 /* Skip pas the = sign, and any white space following it */ 568 pnt++; /* Skip past '=' sign */ 569 while (*pnt == ' ' || *pnt == '\t') 570 pnt++; 571 572 /* now it is safe to NUL terminate the name */ 573 574 *name_end = 0; 575 576 /* Now get rid of trailing newline */ 577 578 pnt1 = pnt; 579 while (*pnt1) 580 { 581 if (*pnt1 == '\n') 582 { 583 *pnt1 = 0; 584 break; 585 } 586 pnt1++; 587 }; 588 /* OK, now figure out which option we have */ 589 for(rco = rcopt; rco->tag; rco++) { 590 if(strcmp(rco->tag, name) == 0) 591 { 592 *rco->variable = strdup(pnt); 593 break; 594 }; 595 } 596 if (rco->tag == NULL) 597 { 598 fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum, 599 name); 600 } 601 } 602 if (ferror(rcfile)) 603 perror(filename); 604 fclose(rcfile); 605 } 606 607 char * path_table_l = NULL; 608 char * path_table_m = NULL; 609 610 char * jpath_table_l = NULL; 611 char * jpath_table_m = NULL; 612 613 int goof = 0; 614 615 #ifndef TRUE 616 #define TRUE 1 617 #endif 618 619 #ifndef FALSE 620 #define FALSE 0 621 #endif 622 623 void usage(){ 624 #ifdef APPLE_HYB 625 const char * program_name = "mkhybrid"; 626 #else 627 const char * program_name = "mkisofs"; 628 #endif /* APPLE_HYB */ 629 630 #if 0 631 fprintf(stderr,"Usage:\n"); 632 fprintf(stderr, 633 "mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \ 634 [-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]" 635 "[-P publisher] [ -A app_id ] [-z] \n \ 636 [-b boot_image_name] [-c boot_catalog-name] \ 637 [-x path -x path ...] path\n"); 638 #endif 639 640 int i; 641 /* const char **targets, **pp;*/ 642 643 fprintf (stderr, "Usage: %s [options] file...\n", program_name); 644 645 fprintf (stderr, "Options:\n"); 646 for (i = 0; i < OPTION_COUNT; i++) 647 { 648 if (ld_options[i].doc != NULL) 649 { 650 int comma; 651 int len; 652 int j; 653 654 fprintf (stderr, " "); 655 656 comma = FALSE; 657 len = 2; 658 659 j = i; 660 do 661 { 662 if (ld_options[j].shortopt != '\0' 663 && ld_options[j].control != NO_HELP) 664 { 665 fprintf (stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt); 666 len += (comma ? 2 : 0) + 2; 667 if (ld_options[j].arg != NULL) 668 { 669 if (ld_options[j].opt.has_arg != optional_argument) 670 { 671 fprintf (stderr, " "); 672 ++len; 673 } 674 fprintf (stderr, "%s", ld_options[j].arg); 675 len += strlen (ld_options[j].arg); 676 } 677 comma = TRUE; 678 } 679 ++j; 680 } 681 while (j < OPTION_COUNT && ld_options[j].doc == NULL); 682 683 j = i; 684 do 685 { 686 if (ld_options[j].opt.name != NULL 687 && ld_options[j].control != NO_HELP) 688 { 689 fprintf (stderr, "%s-%s%s", 690 comma ? ", " : "", 691 ld_options[j].control == TWO_DASHES ? "-" : "", 692 ld_options[j].opt.name); 693 len += ((comma ? 2 : 0) 694 + 1 695 + (ld_options[j].control == TWO_DASHES ? 1 : 0) 696 + strlen (ld_options[j].opt.name)); 697 if (ld_options[j].arg != NULL) 698 { 699 fprintf (stderr, " %s", ld_options[j].arg); 700 len += 1 + strlen (ld_options[j].arg); 701 } 702 comma = TRUE; 703 } 704 ++j; 705 } 706 while (j < OPTION_COUNT && ld_options[j].doc == NULL); 707 708 if (len >= 30) 709 { 710 fprintf (stderr, "\n"); 711 len = 0; 712 } 713 714 for (; len < 30; len++) 715 fputc (' ', stderr); 716 717 fprintf (stderr, "%s\n", ld_options[i].doc); 718 } 719 } 720 exit(1); 721 } 722 723 724 /* 725 * Fill in date in the iso9660 format 726 * 727 * The standards state that the timezone offset is in multiples of 15 728 * minutes, and is what you add to GMT to get the localtime. The U.S. 729 * is always at a negative offset, from -5h to -8h (can vary a little 730 * with DST, I guess). The Linux iso9660 filesystem has had the sign 731 * of this wrong for ages (mkisofs had it wrong too for the longest time). 732 */ 733 int FDECL2(iso9660_date,char *, result, time_t, crtime){ 734 struct tm *local; 735 local = localtime(&crtime); 736 result[0] = local->tm_year; 737 result[1] = local->tm_mon + 1; 738 result[2] = local->tm_mday; 739 result[3] = local->tm_hour; 740 result[4] = local->tm_min; 741 result[5] = local->tm_sec; 742 743 /* 744 * Must recalculate proper timezone offset each time, 745 * as some files use daylight savings time and some don't... 746 */ 747 result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ 748 local = gmtime(&crtime); 749 local->tm_year -= result[0]; 750 local->tm_yday -= result[6]; 751 local->tm_hour -= result[3]; 752 local->tm_min -= result[4]; 753 if (local->tm_year < 0) 754 { 755 local->tm_yday = -1; 756 } 757 else 758 { 759 if (local->tm_year > 0) local->tm_yday = 1; 760 } 761 762 result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15; 763 764 return 0; 765 } 766 767 /* hide "./rr_moved" if all its contents are hidden */ 768 static void 769 hide_reloc_dir() 770 { 771 struct directory_entry * s_entry; 772 773 for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) { 774 if(strcmp(s_entry->name,".")==0 || strcmp(s_entry->name,"..")==0) 775 continue; 776 777 if((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0) 778 return; 779 } 780 781 /* all entries are hidden, so hide this directory */ 782 reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; 783 reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY; 784 } 785 786 /* get pathnames from the command line, and then from given file */ 787 static char * 788 get_pnames(int argc, char **argv, int opt, char *pname, int pnsize, FILE * fp) 789 { 790 int len; 791 792 /* we may of already read the first line from the pathnames file */ 793 if (save_pname) { 794 save_pname = 0; 795 return (pname); 796 } 797 798 if (opt < argc) 799 return (argv[opt]); 800 801 if (fp == NULL) 802 return ((char *)0); 803 804 if (fgets(pname, pnsize, fp)) { 805 /* Discard newline */ 806 len = strlen(pname); 807 if (pname[len - 1] == '\n') { 808 pname[len - 1] = '\0'; 809 } 810 return (pname); 811 } 812 813 return ((char *)0); 814 } 815 816 extern char * cdwrite_data; 817 818 int FDECL2(main, int, argc, char **, argv){ 819 struct directory_entry de; 820 #ifdef HAVE_SBRK 821 unsigned long mem_start; 822 #endif 823 struct stat statbuf; 824 char * merge_image = NULL; 825 struct iso_directory_record * mrootp = NULL; 826 struct output_fragment * opnt; 827 int longind; 828 char shortopts[OPTION_COUNT * 3 + 2]; 829 struct option longopts[OPTION_COUNT + 1]; 830 int c; 831 char *log_file = 0; 832 char *node = NULL; 833 char *pathnames = 0; 834 FILE *pfp = NULL; 835 char pname[2*PATH_MAX + 1 + 1]; /* may be too short */ 836 char *arg; /* if '\\' present */ 837 char nodename[PATH_MAX + 1]; 838 int no_path_names = 1; 839 int have_cmd_line_pathspec = 0; 840 #ifdef APPLE_HYB 841 char *afpfile = ""; /* mapping file for TYPE/CREATOR */ 842 #endif /* APPLE_HYB */ 843 844 if (argc < 2) 845 usage(); 846 847 /* Get the defaults from the .mkisofsrc file */ 848 read_rcfile(argv[0]); 849 850 outfile = NULL; 851 852 /* 853 * Copy long option initialization from GNU-ld. 854 */ 855 /* Starting the short option string with '-' is for programs that 856 expect options and other ARGV-elements in any order and that care about 857 the ordering of the two. We describe each non-option ARGV-element 858 as if it were the argument of an option with character code 1. */ 859 { 860 int i, is, il; 861 shortopts[0] = '-'; 862 is = 1; 863 il = 0; 864 for (i = 0; i < OPTION_COUNT; i++) 865 { 866 if (ld_options[i].shortopt != '\0') 867 { 868 shortopts[is] = ld_options[i].shortopt; 869 ++is; 870 if (ld_options[i].opt.has_arg == required_argument 871 || ld_options[i].opt.has_arg == optional_argument) 872 { 873 shortopts[is] = ':'; 874 ++is; 875 if (ld_options[i].opt.has_arg == optional_argument) 876 { 877 shortopts[is] = ':'; 878 ++is; 879 } 880 } 881 } 882 if (ld_options[i].opt.name != NULL) 883 { 884 longopts[il] = ld_options[i].opt; 885 ++il; 886 } 887 } 888 shortopts[is] = '\0'; 889 longopts[il].name = NULL; 890 } 891 892 while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF) 893 switch (c) 894 { 895 case 1: 896 /* 897 * A filename that we take as input. 898 */ 899 optind--; 900 have_cmd_line_pathspec = 1; 901 goto parse_input_files; 902 903 case OPTION_USE_GRAFT: 904 use_graft_ptrs = 1; 905 break; 906 case 'C': 907 /* 908 * This is a temporary hack until cdwrite gets the proper hooks in 909 * it. 910 */ 911 cdwrite_data = optarg; 912 break; 913 case 'i': 914 fprintf(stderr, "-i option no longer supported.\n"); 915 exit(1); 916 break; 917 case 'J': 918 use_Joliet++; 919 break; 920 case 'a': 921 all_files++; 922 break; 923 case 'b': 924 use_eltorito++; 925 boot_image = optarg; /* pathname of the boot image on cd */ 926 if (boot_image == NULL) { 927 fprintf(stderr,"Required boot image pathname missing\n"); 928 exit(1); 929 } 930 break; 931 case 'c': 932 use_eltorito++; 933 boot_catalog = optarg; /* pathname of the boot image on cd */ 934 if (boot_catalog == NULL) { 935 fprintf(stderr,"Required boot catalog pathname missing\n"); 936 exit(1); 937 } 938 break; 939 case OPTION_ABSTRACT: 940 abstract = optarg; 941 if(strlen(abstract) > 37) { 942 fprintf(stderr,"Abstract filename string too long\n"); 943 exit(1); 944 }; 945 break; 946 case 'A': 947 appid = optarg; 948 if(strlen(appid) > 128) { 949 fprintf(stderr,"Application-id string too long\n"); 950 exit(1); 951 }; 952 break; 953 case OPTION_BIBLIO: 954 biblio = optarg; 955 if(strlen(biblio) > 37) { 956 fprintf(stderr,"Bibliographic filename string too long\n"); 957 exit(1); 958 }; 959 break; 960 case OPTION_COPYRIGHT: 961 copyright = optarg; 962 if(strlen(copyright) > 37) { 963 fprintf(stderr,"Copyright filename string too long\n"); 964 exit(1); 965 }; 966 break; 967 case 'd': 968 omit_period++; 969 break; 970 case 'D': 971 RR_relocation_depth = 32767; 972 break; 973 case 'f': 974 follow_links++; 975 break; 976 case 'l': 977 full_iso9660_filenames++; 978 break; 979 case 'L': 980 allow_leading_dots++; 981 break; 982 case OPTION_LOG_FILE: 983 log_file = optarg; 984 break; 985 case 'M': 986 merge_image = optarg; 987 break; 988 case 'N': 989 omit_version_number++; 990 break; 991 case 'o': 992 outfile = optarg; 993 break; 994 case 'p': 995 preparer = optarg; 996 if(strlen(preparer) > 128) { 997 fprintf(stderr,"Preparer string too long\n"); 998 exit(1); 999 }; 1000 break; 1001 case OPTION_PRINT_SIZE: 1002 print_size++; 1003 break; 1004 case 'P': 1005 publisher = optarg; 1006 if(strlen(publisher) > 128) { 1007 fprintf(stderr,"Publisher string too long\n"); 1008 exit(1); 1009 }; 1010 break; 1011 case OPTION_QUIET: 1012 verbose = 0; 1013 break; 1014 case 'R': 1015 use_RockRidge++; 1016 break; 1017 case 'r': 1018 rationalize++; 1019 use_RockRidge++; 1020 break; 1021 case OPTION_SPLIT_OUTPUT: 1022 split_output++; 1023 break; 1024 case OPTION_SYSID: 1025 system_id = optarg; 1026 if(strlen(system_id) > 32) { 1027 fprintf(stderr,"System ID string too long\n"); 1028 exit(1); 1029 }; 1030 break; 1031 #ifdef APPLE_HYB 1032 case OPTION_TRANS_TBL: 1033 trans_tbl = optarg; 1034 /* fall through */ 1035 #endif /* APPLE_HYB */ 1036 case 'T': 1037 generate_tables++; 1038 break; 1039 case 'V': 1040 volume_id = optarg; 1041 if(strlen(volume_id) > 32) { 1042 fprintf(stderr,"Volume ID string too long\n"); 1043 exit(1); 1044 }; 1045 break; 1046 case OPTION_VOLSET: 1047 volset_id = optarg; 1048 if(strlen(volset_id) > 128) { 1049 fprintf(stderr,"Volume set ID string too long\n"); 1050 exit(1); 1051 }; 1052 break; 1053 case OPTION_VOLSET_SIZE: 1054 volume_set_size = atoi(optarg); 1055 break; 1056 case OPTION_VOLSET_SEQ_NUM: 1057 volume_sequence_number = atoi(optarg); 1058 if (volume_sequence_number > volume_set_size) { 1059 fprintf(stderr,"Volume set sequence number too big\n"); 1060 exit(1); 1061 } 1062 break; 1063 case 'v': 1064 verbose++; 1065 break; 1066 case 'z': 1067 #ifdef VMS 1068 fprintf(stderr,"Transparent compression not supported with VMS\n"); 1069 exit(1); 1070 #else 1071 transparent_compression++; 1072 #endif 1073 break; 1074 case 'x': 1075 case 'm': 1076 /* 1077 * Somehow two options to do basically the same thing got added somewhere along 1078 * the way. The 'match' code supports limited globbing, so this is the one 1079 * that got selected. Unfortunately the 'x' switch is probably more intuitive. 1080 */ 1081 add_match(optarg); 1082 break; 1083 case OPTION_I_HIDE: 1084 i_add_match(optarg); 1085 break; 1086 case OPTION_J_HIDE: 1087 j_add_match(optarg); 1088 break; 1089 case OPTION_HIDE_TRANS_TBL: 1090 jhide_trans_tbl++; 1091 break; 1092 case OPTION_HIDE_RR_MOVED: 1093 hide_rr_moved++; 1094 break; 1095 case OPTION_HELP: 1096 usage (); 1097 exit (0); 1098 break; 1099 case OPTION_NOSPLIT_SL_COMPONENT: 1100 split_SL_component = 0; 1101 break; 1102 case OPTION_NOSPLIT_SL_FIELD: 1103 split_SL_field = 0; 1104 break; 1105 #ifdef APPLE_HYB 1106 case 'H': 1107 afpfile = optarg; 1108 hfs_last = MAP_LAST; 1109 break; 1110 case 'h': 1111 apple_hyb = 1; 1112 break; 1113 case 'g': 1114 apple_ext = 1; 1115 break; 1116 case OPTION_PROBE: 1117 probe = 1; 1118 break; 1119 case OPTION_MACNAME: 1120 mac_name = 1; 1121 break; 1122 case OPTION_NOMACFILES: 1123 nomacfiles = 1; 1124 break; 1125 case OPTION_BOOT_HFS_FILE: 1126 hfs_boot_file = optarg; 1127 /* fall through */ 1128 case OPTION_GEN_PT: 1129 gen_pt = 1; 1130 break; 1131 case OPTION_MAGIC_FILE: 1132 magic_file = optarg; 1133 hfs_last = MAG_LAST; 1134 break; 1135 case OPTION_AUTOSTART: 1136 autoname = optarg; 1137 /* gen_pt = 1; */ 1138 break; 1139 case OPTION_BSIZE: 1140 afe_size = atoi(optarg); 1141 hfs_select |= DO_FEU; 1142 hfs_select |= DO_FEL; 1143 break; 1144 case OPTION_HFS_VOLID: 1145 hfs_volume_id = optarg; 1146 break; 1147 case OPTION_HFS_BLESS: 1148 hfs_bless = optarg; 1149 break; 1150 /* Mac/Unix types to include */ 1151 case OPTION_CAP: 1152 hfs_select |= DO_CAP; 1153 break; 1154 case OPTION_NETA: 1155 hfs_select |= DO_NETA; 1156 break; 1157 case OPTION_DBL: 1158 hfs_select |= DO_DBL; 1159 break; 1160 case OPTION_ESH: 1161 case OPTION_USH: 1162 hfs_select |= DO_ESH; 1163 break; 1164 case OPTION_FE: 1165 hfs_select |= DO_FEU; 1166 hfs_select |= DO_FEL; 1167 break; 1168 case OPTION_SGI: 1169 case OPTION_XIN: 1170 hfs_select |= DO_SGI; 1171 break; 1172 case OPTION_MBIN: 1173 hfs_select |= DO_MBIN; 1174 break; 1175 case OPTION_SGL: 1176 hfs_select |= DO_SGL; 1177 break; 1178 case OPTION_CREATE_DT: 1179 create_dt = 0; 1180 break; 1181 case OPTION_HFS_HIDE: 1182 hfs_add_match(optarg); 1183 break; 1184 case OPTION_HFS_LIST: 1185 hfs_add_list(optarg); 1186 break; 1187 #endif /* APPLE_HYB */ 1188 case OPTION_P_LIST: 1189 pathnames = optarg; 1190 break; 1191 case OPTION_X_LIST: 1192 add_list(optarg); 1193 break; 1194 case OPTION_I_LIST: 1195 i_add_list(optarg); 1196 break; 1197 case OPTION_J_LIST: 1198 j_add_list(optarg); 1199 break; 1200 default: 1201 usage(); 1202 exit(1); 1203 } 1204 1205 parse_input_files: 1206 1207 #ifdef HAVE_SBRK 1208 mem_start = (unsigned long) sbrk(0); 1209 #endif 1210 1211 /* if the -hide-joliet option has been given, set the Joliet option */ 1212 if (!use_Joliet && j_ishidden()) 1213 use_Joliet++; 1214 1215 #ifdef APPLE_HYB 1216 if (apple_hyb && apple_ext) { 1217 fprintf(stderr,"can't have both -apple and -hfs options"); 1218 exit (1); 1219 } 1220 1221 /* if -probe, -macname, any hfs selection and/or mapping file is given, 1222 but no HFS option, then select apple_hyb */ 1223 if (!apple_hyb && !apple_ext) { 1224 if (*afpfile || probe || mac_name || nomacfiles || hfs_select || hfs_boot_file || magic_file || hfs_ishidden() || gen_pt || autoname || afe_size) 1225 apple_hyb = 1; 1226 } 1227 1228 if (apple_ext && hfs_boot_file) { 1229 fprintf(stderr,"can't have -hfs-boot-file with -apple\n"); 1230 exit (1); 1231 } 1232 1233 if (hfs_select) 1234 /* if we have selected certain types of Mac/Unix files, then turn off 1235 probe and nomacfiles */ 1236 probe = nomacfiles = 0; 1237 1238 if (apple_hyb || apple_ext) 1239 apple_both = 1; 1240 1241 if (apple_both && verbose && !afe_size && 1242 (hfs_select & (DO_FEU | DO_FEL))) { 1243 fprintf(stderr, 1244 "Warning: assuming PC Exchange cluster size of 512 bytes\n"); 1245 afe_size = 512; 1246 } 1247 if (apple_both) { 1248 /* set up the TYPE/CREATOR mappings */ 1249 hfs_init(afpfile, 0, probe, nomacfiles, hfs_select); 1250 } 1251 1252 if (apple_ext && !use_RockRidge) { 1253 /* use RockRidge to set the SystemUse field ... */ 1254 use_RockRidge++; 1255 rationalize++; 1256 } 1257 1258 #endif /* APPLE_HYB */ 1259 1260 if(verbose > 1) fprintf(stderr,"%s\n", version_string); 1261 1262 if(cdwrite_data == NULL && merge_image != NULL) 1263 { 1264 fprintf(stderr,"Multisession usage bug: Must specify -C if -M is used.\n"); 1265 exit(0); 1266 } 1267 1268 if(cdwrite_data != NULL && merge_image == NULL) 1269 { 1270 fprintf(stderr,"Warning: -C specified without -M: old session data will not be merged.\n"); 1271 } 1272 1273 /* 1274 * see if we have a list of pathnames to process 1275 */ 1276 if (pathnames) { 1277 /* "-" means take list from the standard input */ 1278 if (strcmp(pathnames, "-")) { 1279 if ((pfp = fopen(pathnames, "r")) == NULL) { 1280 fprintf(stderr, 1281 "Unable to open pathname list %s.\n", pathnames); 1282 exit(1); 1283 } 1284 } else 1285 pfp = stdin; 1286 } 1287 1288 /* The first step is to scan the directory tree, and take some notes */ 1289 1290 if ((arg = get_pnames(argc, argv, optind, pname, 1291 sizeof(pname), pfp)) == NULL) { 1292 usage(); 1293 exit(1); 1294 }; 1295 1296 /* 1297 * if we don't have a pathspec, then save the pathspec found 1298 * in the pathnames file (stored in pname) - we don't want 1299 * to skip this pathspec when we read the pathnames file again 1300 */ 1301 if (!have_cmd_line_pathspec) { 1302 save_pname = 1; 1303 } 1304 1305 if(use_RockRidge){ 1306 #if 1 1307 extension_record = generate_rr_extension_record("RRIP_1991A", 1308 "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", 1309 "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size); 1310 #else 1311 extension_record = generate_rr_extension_record("IEEE_P1282", 1312 "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", 1313 "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size); 1314 #endif 1315 } 1316 1317 if (log_file) { 1318 FILE *lfp; 1319 int i; 1320 1321 /* open log file - test that we can open OK */ 1322 if ((lfp = fopen(log_file, "w")) == NULL) { 1323 fprintf(stderr,"can't open logfile: %s\n", log_file); 1324 exit (1); 1325 } 1326 fclose(lfp); 1327 1328 /* redirect all stderr message to log_file */ 1329 fprintf(stderr, "re-directing all messages to %s\n", log_file); 1330 fflush(stderr); 1331 1332 /* associate stderr with the log file */ 1333 if (freopen(log_file, "w", stderr) == NULL) { 1334 fprintf(stderr,"can't open logfile: %s\n", log_file); 1335 exit (1); 1336 } 1337 if(verbose > 1) { 1338 for (i=0;i<argc;i++) 1339 fprintf(stderr,"%s ", argv[i]); 1340 1341 fprintf(stderr,"\n%s\n", version_string); 1342 } 1343 } 1344 /* Find name of root directory. */ 1345 if (arg != NULL) 1346 node = findequal(arg); 1347 if (!use_graft_ptrs) 1348 node = NULL; 1349 if (node == NULL) { 1350 if (use_graft_ptrs && arg != NULL) 1351 node = escstrcpy(nodename, arg); 1352 else 1353 node = arg; 1354 } else { 1355 /* 1356 * Remove '\\' escape chars which are located 1357 * before '\\' and '=' chars 1358 */ 1359 node = escstrcpy(nodename, ++node); 1360 } 1361 /* 1362 * See if boot catalog file exists in root directory, if not 1363 * we will create it. 1364 */ 1365 if (use_eltorito) 1366 init_boot_catalog(argv[optind]); 1367 1368 /* 1369 * Find the device and inode number of the root directory. 1370 * Record this in the hash table so we don't scan it more than 1371 * once. 1372 */ 1373 stat_filter(argv[optind], &statbuf); 1374 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); 1375 1376 memset(&de, 0, sizeof(de)); 1377 1378 de.filedir = root; /* We need this to bootstrap */ 1379 1380 if (cdwrite_data != NULL && merge_image == NULL) { 1381 /* in case we want to add a new session, but don't want to merge old one */ 1382 get_session_start(NULL); 1383 } 1384 1385 if( merge_image != NULL ) 1386 { 1387 mrootp = merge_isofs(merge_image); 1388 if( mrootp == NULL ) 1389 { 1390 /* 1391 * Complain and die. 1392 */ 1393 fprintf(stderr,"Unable to open previous session image %s\n", 1394 merge_image); 1395 exit(1); 1396 } 1397 1398 memcpy(&de.isorec.extent, mrootp->extent, 8); 1399 } 1400 1401 /* 1402 * Create an empty root directory. If we ever scan it for real, we will fill in the 1403 * contents. 1404 */ 1405 find_or_create_directory(NULL, "", &de, TRUE); 1406 1407 /* 1408 * Scan the actual directory (and any we find below it) 1409 * for files to write out to the output image. Note - we 1410 * take multiple source directories and keep merging them 1411 * onto the image. 1412 */ 1413 while((arg = get_pnames(argc, argv, optind, pname, 1414 sizeof(pname), pfp)) != NULL) 1415 { 1416 struct directory * graft_dir; 1417 struct stat st; 1418 char * short_name; 1419 int status; 1420 char graft_point[PATH_MAX + 1]; 1421 1422 /* 1423 * We would like a syntax like: 1424 * 1425 * /tmp=/usr/tmp/xxx 1426 * 1427 * where the user can specify a place to graft each 1428 * component of the tree. To do this, we may have to create 1429 * directories along the way, of course. 1430 * Secondly, I would like to allow the user to do something 1431 * like: 1432 * 1433 * /home/baz/RMAIL=/u3/users/baz/RMAIL 1434 * 1435 * so that normal files could also be injected into the tree 1436 * at an arbitrary point. 1437 * 1438 * The idea is that the last component of whatever is being 1439 * entered would take the name from the last component of 1440 * whatever the user specifies. 1441 * 1442 * The default will be that the file is injected at the 1443 * root of the image tree. 1444 */ 1445 node = findequal(arg); 1446 if (!use_graft_ptrs) 1447 node = NULL; 1448 /* 1449 * Remove '\\' escape chars which are located 1450 * before '\\' and '=' chars ---> below in escstrcpy() 1451 */ 1452 1453 short_name = NULL; 1454 1455 if( node != NULL ) 1456 { 1457 char * pnt; 1458 char * xpnt; 1459 size_t len; 1460 1461 if (node) { 1462 *node = '\0'; 1463 escstrcpy(graft_point, arg); 1464 *node = '='; 1465 } 1466 1467 /* 1468 * Remove unwanted "./" & "/" sequences from start... 1469 */ 1470 do { 1471 xpnt = graft_point; 1472 while (xpnt[0] == '.' && xpnt[1] == '/') 1473 xpnt += 2; 1474 while (*xpnt == PATH_SEPARATOR) { 1475 xpnt++; 1476 } 1477 strcpy(graft_point, xpnt); 1478 } while (xpnt > graft_point); 1479 1480 if (node) { 1481 node = escstrcpy(nodename, ++node); 1482 } else { 1483 node = arg; 1484 } 1485 1486 graft_dir = root; 1487 xpnt = graft_point; 1488 /* 1489 * If "node" points to a directory, then graft_point 1490 * needs to point to a directory too. 1491 */ 1492 if (follow_links) 1493 status = stat_filter(node, &st); 1494 else 1495 status = lstat_filter(node, &st); 1496 if (status == 0 && S_ISDIR(st.st_mode)) { 1497 len = strlen(graft_point); 1498 1499 if ((len <= (sizeof (graft_point) -1)) && 1500 graft_point[len-1] != '/') { 1501 graft_point[len++] = '/'; 1502 graft_point[len] = '\0'; 1503 } 1504 } 1505 1506 /* 1507 * Loop down deeper and deeper until we 1508 * find the correct insertion spot. 1509 * Canonicalize the filename while parsing it. 1510 */ 1511 while(1==1) 1512 { 1513 do { 1514 while (xpnt[0] == '.' && xpnt[1] == '/') 1515 xpnt += 2; 1516 while (xpnt[0] == '/') 1517 xpnt += 1; 1518 if (xpnt[0] == '.' && xpnt[1] == '.' && xpnt[2] == '/') { 1519 if (graft_dir && graft_dir != root) { 1520 graft_dir = graft_dir->parent; 1521 xpnt += 2; 1522 } 1523 } 1524 } while ((xpnt[0] == '/') || (xpnt[0] == '.' && xpnt[1] == '/')); 1525 pnt = strchr(xpnt, PATH_SEPARATOR); 1526 if( pnt == NULL ) 1527 { 1528 if( *xpnt != '\0' ) 1529 { 1530 short_name = xpnt; 1531 } 1532 break; 1533 } 1534 *pnt = '\0'; 1535 graft_dir = find_or_create_directory(graft_dir, 1536 graft_point, 1537 NULL, TRUE); 1538 *pnt = PATH_SEPARATOR; 1539 xpnt = pnt + 1; 1540 } 1541 } 1542 else 1543 { 1544 graft_dir = root; 1545 if (use_graft_ptrs) 1546 node = escstrcpy(nodename, arg); 1547 else 1548 node = arg; 1549 } 1550 1551 /* 1552 * Now see whether the user wants to add a regular file, 1553 * or a directory at this point. 1554 */ 1555 if (follow_links) 1556 status = stat_filter(node, &st); 1557 else 1558 status = lstat_filter(node, &st); 1559 if( status != 0 ) 1560 { 1561 /* 1562 * This is a fatal error - the user won't be getting what 1563 * they want if we were to proceed. 1564 */ 1565 fprintf(stderr, "Invalid node - %s\n", node); 1566 exit(1); 1567 } 1568 else 1569 { 1570 if( S_ISDIR(st.st_mode) ) 1571 { 1572 if (!scan_directory_tree(graft_dir, node, &de)) 1573 { 1574 exit(1); 1575 } 1576 } 1577 else 1578 { 1579 if( short_name == NULL ) 1580 { 1581 short_name = strrchr(node, PATH_SEPARATOR); 1582 if( short_name == NULL || short_name < node ) 1583 { 1584 short_name = node; 1585 } 1586 else 1587 { 1588 short_name++; 1589 } 1590 } 1591 #ifdef APPLE_HYB 1592 if( !insert_file_entry(graft_dir, node, short_name, 0) ) 1593 #else 1594 if( !insert_file_entry(graft_dir, node, short_name) ) 1595 #endif /* APPLE_HYB */ 1596 { 1597 exit(1); 1598 } 1599 } 1600 } 1601 1602 optind++; 1603 no_path_names = 0; 1604 } 1605 1606 if (pfp && pfp != stdin) 1607 fclose(pfp); 1608 1609 /* exit if we don't have any pathnames to process - not going to happen 1610 at the moment as we have to have at least one path on the command line */ 1611 if(no_path_names){ 1612 usage(); 1613 exit(1); 1614 }; 1615 1616 /* 1617 * Now merge in any previous sessions. This is driven on the source 1618 * side, since we may need to create some additional directories. 1619 */ 1620 if( merge_image != NULL ) 1621 { 1622 merge_previous_session(root, mrootp); 1623 } 1624 #ifdef APPLE_HYB 1625 /* free up any HFS filename mapping memory */ 1626 if (apple_both) 1627 clean_hfs(); 1628 #endif /* APPLE_HYB */ 1629 1630 /* hide "./rr_moved" if all its contents have been hidden */ 1631 if (reloc_dir && i_ishidden()) 1632 hide_reloc_dir(); 1633 1634 /* 1635 * Sort the directories in the required order (by ISO9660). Also, 1636 * choose the names for the 8.3 filesystem if required, and do 1637 * any other post-scan work. 1638 */ 1639 goof += sort_tree(root); 1640 1641 if( use_Joliet ) 1642 { 1643 goof += joliet_sort_tree(root); 1644 } 1645 1646 if (goof) 1647 { 1648 fprintf(stderr, "Joliet tree sort failed.\n"); 1649 exit(1); 1650 } 1651 1652 /* 1653 * Fix a couple of things in the root directory so that everything 1654 * is self consistent. 1655 */ 1656 root->self = root->contents; /* Fix this up so that the path 1657 tables get done right */ 1658 1659 /* 1660 * OK, ready to write the file. Open it up, and generate the thing. 1661 */ 1662 if (print_size){ 1663 discimage = fopen("/dev/null", "wb"); 1664 if (!discimage){ 1665 fprintf(stderr,"Unable to open /dev/null\n"); 1666 exit(1); 1667 } 1668 } else if (outfile){ 1669 discimage = fopen(outfile, "wb"); 1670 if (!discimage){ 1671 fprintf(stderr,"Unable to open disc image file\n"); 1672 exit(1); 1673 1674 }; 1675 } else { 1676 discimage = stdout; 1677 1678 #if defined(__CYGWIN32__) 1679 setmode(fileno(stdout), O_BINARY); 1680 #endif 1681 } 1682 1683 /* Now assign addresses on the disc for the path table. */ 1684 1685 path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; 1686 if (path_blocks & 1) path_blocks++; 1687 1688 jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11; 1689 if (jpath_blocks & 1) jpath_blocks++; 1690 1691 /* 1692 * Start to set up the linked list that we use to track the 1693 * contents of the disc. 1694 */ 1695 outputlist_insert(&padblock_desc); 1696 1697 /* 1698 * PVD for disc. 1699 */ 1700 outputlist_insert(&voldesc_desc); 1701 1702 /* 1703 * SVD for El Torito. MUST be immediately after the PVD! 1704 */ 1705 if( use_eltorito) 1706 { 1707 outputlist_insert(&torito_desc); 1708 } 1709 1710 /* 1711 * SVD for Joliet. 1712 */ 1713 if( use_Joliet) 1714 { 1715 outputlist_insert(&joliet_desc); 1716 } 1717 1718 /* 1719 * Finally the last volume desctiptor. 1720 */ 1721 outputlist_insert(&end_vol); 1722 1723 1724 outputlist_insert(&pathtable_desc); 1725 if( use_Joliet) 1726 { 1727 outputlist_insert(&jpathtable_desc); 1728 } 1729 1730 outputlist_insert(&dirtree_desc); 1731 if( use_Joliet) 1732 { 1733 outputlist_insert(&jdirtree_desc); 1734 } 1735 1736 outputlist_insert(&dirtree_clean); 1737 1738 if(extension_record) 1739 { 1740 outputlist_insert(&extension_desc); 1741 } 1742 1743 outputlist_insert(&files_desc); 1744 1745 /* 1746 * Allow room for the various headers we will be writing. There 1747 * will always be a primary and an end volume descriptor. 1748 */ 1749 last_extent = session_start; 1750 1751 /* 1752 * Calculate the size of all of the components of the disc, and assign 1753 * extent numbers. 1754 */ 1755 for(opnt = out_list; opnt; opnt = opnt->of_next ) 1756 { 1757 if( opnt->of_size != NULL ) 1758 { 1759 (*opnt->of_size)(last_extent); 1760 } 1761 } 1762 1763 /* 1764 * Generate the contents of any of the sections that we want to generate. 1765 * Not all of the fragments will do anything here - most will generate the 1766 * data on the fly when we get to the write pass. 1767 */ 1768 for(opnt = out_list; opnt; opnt = opnt->of_next ) 1769 { 1770 if( opnt->of_generate != NULL ) 1771 { 1772 (*opnt->of_generate)(); 1773 } 1774 } 1775 1776 if( in_image != NULL ) 1777 { 1778 fclose(in_image); 1779 } 1780 1781 /* 1782 * Now go through the list of fragments and write the data that corresponds to 1783 * each one. 1784 */ 1785 for(opnt = out_list; opnt; opnt = opnt->of_next ) 1786 { 1787 if( opnt->of_write != NULL ) 1788 { 1789 (*opnt->of_write)(discimage); 1790 } 1791 } 1792 1793 if( verbose > 0 ) 1794 { 1795 #ifdef HAVE_SBRK 1796 fprintf(stderr,"Max brk space used %x\n", 1797 (unsigned int)(((unsigned long)sbrk(0)) - mem_start)); 1798 #endif 1799 fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9); 1800 } 1801 #ifdef APPLE_HYB 1802 last_extent += hfs_extra; 1803 #endif /* APPLE_HYB */ 1804 1805 #ifdef VMS 1806 return 1; 1807 #else 1808 return 0; 1809 #endif 1810 } 1811 1812 /* 1813 * Find unescaped equal sign in string. 1814 */ 1815 char * 1816 findequal(char *s) 1817 { 1818 char *p = s; 1819 1820 while ((p = strchr(p, '=')) != NULL) { 1821 if (p > s && p[-1] != '\\') 1822 return (p); 1823 p++; 1824 } 1825 return (NULL); 1826 } 1827 1828 /* 1829 * Find unescaped equal sign in string. 1830 */ 1831 char * 1832 escstrcpy(char *to, char *from) 1833 { 1834 char *p = to; 1835 1836 while ((*p = *from++) != '\0') { 1837 if (*p == '\\' || *p == '=') { 1838 if (p[-1] == '\\') { 1839 --p; 1840 p[0] = p[1]; 1841 } 1842 1843 } 1844 p++; 1845 } 1846 return (to); 1847 } 1848 1849 1850 void * 1851 FDECL1(e_malloc, size_t, size) 1852 { 1853 void* pt = 0; 1854 if( (size > 0) && ((pt=malloc(size))==NULL) ) { 1855 fprintf(stderr, "Not enough memory\n"); 1856 exit (1); 1857 } 1858 return pt; 1859 } 1860