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