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