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@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)
strdup(s)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
FDECL1(read_rcfile,char *,appname)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
usage()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 */
FDECL2(iso9660_date,char *,result,time_t,crtime)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
hide_reloc_dir()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 *
get_pnames(int argc,char ** argv,int opt,char * pname,int pnsize,FILE * fp)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
FDECL2(main,int,argc,char **,argv)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 *
findequal(char * s)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 *
escstrcpy(char * to,char * from)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 *
FDECL1(e_malloc,size_t,size)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