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