]>
Commit | Line | Data |
---|---|---|
4b4c4f64 RM |
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 | ||
fa8b1c51 RM |
9 | Copyright (C) 2009 Free Software Foundation, Inc. |
10 | ||
4b4c4f64 RM |
11 | This program is free software; you can redistribute it and/or modify |
12 | it under the terms of the GNU General Public License as published by | |
fa8b1c51 | 13 | the Free Software Foundation; either version 3, or (at your option) |
4b4c4f64 RM |
14 | any later version. |
15 | ||
16 | This program is distributed in the hope that it will be useful, | |
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | GNU General Public License for more details. | |
20 | ||
21 | You should have received a copy of the GNU General Public License | |
fa8b1c51 | 22 | along with this program; if not, see <http://www.gnu.org/licenses/>. |
4b4c4f64 RM |
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
24 | ||
11e9a115 | 25 | static char rcsid[] ="$Id: mkisofs.c,v 1.32 1999/03/07 21:48:49 eric Exp $"; |
4b4c4f64 RM |
26 | |
27 | #include <errno.h> | |
4b4c4f64 | 28 | #include "config.h" |
63eb2d63 | 29 | #include "mkisofs.h" |
11e9a115 | 30 | #include "match.h" |
4b4c4f64 RM |
31 | |
32 | #ifdef linux | |
33 | #include <getopt.h> | |
63eb2d63 RM |
34 | #else |
35 | #include "getopt.h" | |
4b4c4f64 RM |
36 | #endif |
37 | ||
38 | #include "iso9660.h" | |
39 | #include <ctype.h> | |
40 | ||
41 | #ifndef VMS | |
42 | #include <time.h> | |
43 | #else | |
44 | #include <sys/time.h> | |
45 | #include "vms.h" | |
46 | #endif | |
47 | ||
48 | #include <stdlib.h> | |
49 | #include <sys/stat.h> | |
50 | ||
51 | #ifndef VMS | |
52 | #ifdef HAVE_UNISTD_H | |
53 | #include <unistd.h> | |
54 | #endif | |
55 | #endif | |
11e9a115 | 56 | #include <fctldefs.h> |
4b4c4f64 RM |
57 | |
58 | #include "exclude.h" | |
59 | ||
60 | #ifdef __NetBSD__ | |
61 | #include <sys/time.h> | |
62 | #include <sys/resource.h> | |
63 | #endif | |
64 | ||
65 | struct directory * root = NULL; | |
66 | ||
11e9a115 | 67 | static char version_string[] = "mkisofs 1.12b5"; |
4b4c4f64 | 68 | |
11e9a115 | 69 | char * outfile; |
4b4c4f64 | 70 | FILE * discimage; |
2c55dbc0 RM |
71 | uint64_t next_extent = 0; |
72 | uint64_t last_extent = 0; | |
73 | uint64_t session_start = 0; | |
4b4c4f64 RM |
74 | unsigned int path_table_size = 0; |
75 | unsigned int path_table[4] = {0,}; | |
76 | unsigned int path_blocks = 0; | |
63eb2d63 RM |
77 | |
78 | ||
79 | unsigned int jpath_table_size = 0; | |
80 | unsigned int jpath_table[4] = {0,}; | |
81 | unsigned int jpath_blocks = 0; | |
82 | ||
4b4c4f64 | 83 | struct iso_directory_record root_record; |
63eb2d63 RM |
84 | struct iso_directory_record jroot_record; |
85 | ||
4b4c4f64 RM |
86 | char * extension_record = NULL; |
87 | int extension_record_extent = 0; | |
63eb2d63 | 88 | int extension_record_size = 0; |
4b4c4f64 RM |
89 | |
90 | /* These variables are associated with command line options */ | |
91 | int use_eltorito = 0; | |
e1f240ff RM |
92 | int use_eltorito_emul_floppy = 0; |
93 | int use_boot_info_table = 0; | |
4b4c4f64 | 94 | int use_RockRidge = 0; |
63eb2d63 RM |
95 | int use_Joliet = 0; |
96 | int verbose = 1; | |
4b4c4f64 RM |
97 | int all_files = 0; |
98 | int follow_links = 0; | |
99 | int rationalize = 0; | |
100 | int generate_tables = 0; | |
63eb2d63 RM |
101 | int print_size = 0; |
102 | int split_output = 0; | |
4b4c4f64 RM |
103 | char * preparer = PREPARER_DEFAULT; |
104 | char * publisher = PUBLISHER_DEFAULT; | |
105 | char * appid = APPID_DEFAULT; | |
106 | char * copyright = COPYRIGHT_DEFAULT; | |
107 | char * biblio = BIBLIO_DEFAULT; | |
108 | char * abstract = ABSTRACT_DEFAULT; | |
109 | char * volset_id = VOLSET_ID_DEFAULT; | |
110 | char * volume_id = VOLUME_ID_DEFAULT; | |
111 | char * system_id = SYSTEM_ID_DEFAULT; | |
112 | char * boot_catalog = BOOT_CATALOG_DEFAULT; | |
113 | char * boot_image = BOOT_IMAGE_DEFAULT; | |
11e9a115 RM |
114 | int volume_set_size = 1; |
115 | int volume_sequence_number = 1; | |
4b4c4f64 RM |
116 | |
117 | int omit_period = 0; /* Violates iso9660, but these are a pain */ | |
118 | int transparent_compression = 0; /* So far only works with linux */ | |
119 | int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/ | |
dc83dd64 | 120 | unsigned int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ |
4b4c4f64 RM |
121 | int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with |
122 | DOS */ | |
123 | int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ | |
63eb2d63 RM |
124 | int split_SL_component = 1; /* circumvent a bug in the SunOS driver */ |
125 | int split_SL_field = 1; /* circumvent a bug in the SunOS */ | |
4b4c4f64 RM |
126 | |
127 | struct rcopts{ | |
128 | char * tag; | |
129 | char ** variable; | |
130 | }; | |
131 | ||
132 | struct rcopts rcopt[] = { | |
133 | {"PREP", &preparer}, | |
134 | {"PUBL", &publisher}, | |
135 | {"APPI", &appid}, | |
136 | {"COPY", ©right}, | |
137 | {"BIBL", &biblio}, | |
138 | {"ABST", &abstract}, | |
139 | {"VOLS", &volset_id}, | |
140 | {"VOLI", &volume_id}, | |
141 | {"SYSI", &system_id}, | |
142 | {NULL, NULL} | |
143 | }; | |
144 | ||
63eb2d63 RM |
145 | /* |
146 | * In case it isn't obvious, the option handling code was ripped off from GNU-ld. | |
147 | */ | |
148 | struct ld_option | |
149 | { | |
150 | /* The long option information. */ | |
151 | struct option opt; | |
152 | /* The short option with the same meaning ('\0' if none). */ | |
153 | char shortopt; | |
154 | /* The name of the argument (NULL if none). */ | |
155 | const char *arg; | |
156 | /* The documentation string. If this is NULL, this is a synonym for | |
157 | the previous option. */ | |
158 | const char *doc; | |
159 | enum | |
160 | { | |
161 | /* Use one dash before long option name. */ | |
162 | ONE_DASH, | |
163 | /* Use two dashes before long option name. */ | |
164 | TWO_DASHES, | |
165 | /* Don't mention this option in --help output. */ | |
166 | NO_HELP | |
167 | } control; | |
168 | }; | |
169 | ||
170 | /* Codes used for the long options with no short synonyms. 150 isn't | |
171 | special; it's just an arbitrary non-ASCII char value. */ | |
172 | #define OPTION_HELP 150 | |
173 | #define OPTION_QUIET 151 | |
174 | #define OPTION_NOSPLIT_SL_COMPONENT 152 | |
175 | #define OPTION_NOSPLIT_SL_FIELD 153 | |
176 | #define OPTION_PRINT_SIZE 154 | |
177 | #define OPTION_SPLIT_OUTPUT 155 | |
11e9a115 RM |
178 | #define OPTION_ABSTRACT 156 |
179 | #define OPTION_BIBLIO 157 | |
180 | #define OPTION_COPYRIGHT 158 | |
181 | #define OPTION_SYSID 159 | |
182 | #define OPTION_VOLSET 160 | |
183 | #define OPTION_VOLSET_SIZE 161 | |
184 | #define OPTION_VOLSET_SEQ_NUM 162 | |
185 | #define OPTION_I_HIDE 163 | |
186 | #define OPTION_J_HIDE 164 | |
187 | #define OPTION_LOG_FILE 165 | |
63eb2d63 | 188 | |
fa8b1c51 RM |
189 | #define OPTION_CREAT_DATE 166 |
190 | #define OPTION_MODIF_DATE 167 | |
191 | #define OPTION_EXPIR_DATE 168 | |
192 | #define OPTION_EFFEC_DATE 169 | |
193 | ||
e1f240ff RM |
194 | #define OPTION_BOOT_INFO_TABLE 170 |
195 | #define OPTION_NO_EMUL_BOOT 171 | |
196 | #define OPTION_ELTORITO_EMUL_FLOPPY 172 | |
197 | ||
63eb2d63 RM |
198 | static const struct ld_option ld_options[] = |
199 | { | |
200 | { {"all-files", no_argument, NULL, 'a'}, | |
201 | 'a', NULL, "Process all files (don't skip backup files)", ONE_DASH }, | |
11e9a115 RM |
202 | { {"abstract", required_argument, NULL, OPTION_ABSTRACT}, |
203 | '\0', "FILE", "Set Abstract filename" , ONE_DASH }, | |
63eb2d63 RM |
204 | { {"appid", required_argument, NULL, 'A'}, |
205 | 'A', "ID", "Set Application ID" , ONE_DASH }, | |
11e9a115 RM |
206 | { {"biblio", required_argument, NULL, OPTION_BIBLIO}, |
207 | '\0', "FILE", "Set Bibliographic filename" , ONE_DASH }, | |
208 | { {"copyright", required_argument, NULL, OPTION_COPYRIGHT}, | |
209 | '\0', "FILE", "Set Copyright filename" , ONE_DASH }, | |
63eb2d63 RM |
210 | { {"eltorito-boot", required_argument, NULL, 'b'}, |
211 | 'b', "FILE", "Set El Torito boot image name" , ONE_DASH }, | |
212 | { {"eltorito-catalog", required_argument, NULL, 'c'}, | |
213 | 'c', "FILE", "Set El Torito boot catalog name" , ONE_DASH }, | |
e1f240ff RM |
214 | { {"boot-info-table", no_argument, NULL, OPTION_BOOT_INFO_TABLE }, |
215 | '\0', NULL, "Patch Boot Info Table in El Torito boot image" , ONE_DASH }, | |
216 | { {"no-emul-boot", no_argument, NULL, OPTION_NO_EMUL_BOOT }, | |
217 | '\0', NULL, "Dummy option for backward compatibility" , ONE_DASH }, | |
218 | { {"eltorito-emul-floppy", no_argument, NULL, OPTION_ELTORITO_EMUL_FLOPPY }, | |
219 | '\0', NULL, "Enable floppy drive emulation for El Torito" , TWO_DASHES }, | |
63eb2d63 | 220 | { {"cdwrite-params", required_argument, NULL, 'C'}, |
6a9cead5 | 221 | 'C', "PARAMS", "Magic parameters from cdrecord" , ONE_DASH }, |
63eb2d63 RM |
222 | { {"omit-period", no_argument, NULL, 'd'}, |
223 | 'd', NULL, "Omit trailing periods from filenames", ONE_DASH }, | |
224 | { {"disable-deep-relocation", no_argument, NULL, 'D'}, | |
225 | 'D', NULL, "Disable deep directory relocation", ONE_DASH }, | |
226 | { {"follow-links", no_argument, NULL, 'f'}, | |
227 | 'f', NULL, "Follow symbolic links", ONE_DASH }, | |
228 | { {"help", no_argument, NULL, OPTION_HELP}, | |
229 | '\0', NULL, "Print option help", ONE_DASH }, | |
11e9a115 RM |
230 | { {"hide", required_argument, NULL, OPTION_I_HIDE}, |
231 | '\0', "GLOBFILE", "Hide ISO9660/RR file" , ONE_DASH }, | |
232 | { {"hide-joliet", required_argument, NULL, OPTION_J_HIDE}, | |
233 | '\0', "GLOBFILE", "Hide Joliet file" , ONE_DASH }, | |
63eb2d63 RM |
234 | { {NULL, required_argument, NULL, 'i'}, |
235 | 'i', "ADD_FILES", "No longer supported" , TWO_DASHES }, | |
236 | { {"joliet", no_argument, NULL, 'J'}, | |
237 | 'J', NULL, "Generate Joliet directory information", ONE_DASH }, | |
238 | { {"full-iso9660-filenames", no_argument, NULL, 'l'}, | |
239 | 'l', NULL, "Allow full 32 character filenames for iso9660 names", ONE_DASH }, | |
240 | { {"allow-leading-dots", no_argument, NULL, 'L'}, | |
241 | 'L', NULL, "Allow iso9660 filenames to start with '.'", ONE_DASH }, | |
11e9a115 RM |
242 | { {"log-file", required_argument, NULL, OPTION_LOG_FILE}, |
243 | '\0', "LOG_FILE", "Re-direct messages to LOG_FILE", ONE_DASH }, | |
63eb2d63 RM |
244 | { {"exclude", required_argument, NULL, 'm'}, |
245 | 'm', "GLOBFILE", "Exclude file name" , ONE_DASH }, | |
246 | { {"prev-session", required_argument, NULL, 'M'}, | |
247 | 'M', "FILE", "Set path to previous session to merge" , ONE_DASH }, | |
248 | { {"omit-version-number", no_argument, NULL, 'N'}, | |
249 | 'N', NULL, "Omit version number from iso9660 filename", ONE_DASH }, | |
250 | { {"no-split-symlink-components", no_argument, NULL, 0}, | |
251 | 0, NULL, "Inhibit splitting symlink components" , ONE_DASH }, | |
252 | { {"no-split-symlink-fields", no_argument, NULL, 0}, | |
253 | 0, NULL, "Inhibit splitting symlink fields" , ONE_DASH }, | |
254 | { {"output", required_argument, NULL, 'o'}, | |
255 | 'o', "FILE", "Set output file name" , ONE_DASH }, | |
256 | { {"preparer", required_argument, NULL, 'p'}, | |
257 | 'p', "PREP", "Set Volume preparer" , ONE_DASH }, | |
258 | { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE}, | |
259 | '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH }, | |
260 | { {"publisher", required_argument, NULL, 'P'}, | |
261 | 'P', "PUB", "Set Volume publisher" , ONE_DASH }, | |
262 | { {"quiet", no_argument, NULL, OPTION_QUIET}, | |
263 | '\0', NULL, "Run quietly", ONE_DASH }, | |
264 | { {"rational-rock", no_argument, NULL, 'r'}, | |
265 | 'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH }, | |
266 | { {"rock", no_argument, NULL, 'R'}, | |
267 | 'R', NULL, "Generate Rock Ridge directory information", ONE_DASH }, | |
268 | { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT}, | |
269 | '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH }, | |
11e9a115 RM |
270 | { {"sysid", required_argument, NULL, OPTION_SYSID}, |
271 | '\0', "ID", "Set System ID" , ONE_DASH }, | |
63eb2d63 RM |
272 | { {"translation-table", no_argument, NULL, 'T'}, |
273 | 'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH }, | |
274 | { {"verbose", no_argument, NULL, 'v'}, | |
275 | 'v', NULL, "Verbose", ONE_DASH }, | |
276 | { {"volid", required_argument, NULL, 'V'}, | |
277 | 'V', "ID", "Set Volume ID" , ONE_DASH }, | |
11e9a115 RM |
278 | { {"volset", required_argument, NULL, OPTION_VOLSET}, |
279 | '\0', "ID", "Set Volume set ID" , ONE_DASH }, | |
280 | { {"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE}, | |
281 | '\0', "#", "Set Volume set size" , ONE_DASH }, | |
282 | { {"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM}, | |
283 | '\0', "#", "Set Volume set sequence number" , ONE_DASH }, | |
63eb2d63 | 284 | { {"old-exclude", required_argument, NULL, 'x'}, |
fa8b1c51 | 285 | 'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH }, |
63eb2d63 RM |
286 | #ifdef ERIC_neverdef |
287 | { {"transparent-compression", no_argument, NULL, 'z'}, | |
288 | 'z', NULL, "Enable transparent compression of files", ONE_DASH }, | |
289 | #endif | |
fa8b1c51 RM |
290 | { {"creation-date", required_argument, NULL, OPTION_CREAT_DATE }, |
291 | '\0', NULL, "Override creation date", TWO_DASHES }, | |
292 | { {"modification-date", required_argument, NULL, OPTION_MODIF_DATE }, | |
293 | '\0', NULL, "Override modification date", TWO_DASHES }, | |
294 | { {"expiration-date", required_argument, NULL, OPTION_EXPIR_DATE }, | |
295 | '\0', NULL, "Override expiration date", TWO_DASHES }, | |
296 | { {"effective-date", required_argument, NULL, OPTION_EFFEC_DATE }, | |
297 | '\0', NULL, "Override effective date", TWO_DASHES }, | |
63eb2d63 RM |
298 | }; |
299 | ||
300 | #define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0]) | |
301 | ||
4b4c4f64 RM |
302 | #if defined(ultrix) || defined(_AUX_SOURCE) |
303 | char *strdup(s) | |
304 | char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} | |
305 | #endif | |
306 | ||
11e9a115 RM |
307 | void read_rcfile __PR((char * appname)); |
308 | void usage __PR((void)); | |
309 | static void hide_reloc_dir __PR((void)); | |
310 | ||
4b4c4f64 RM |
311 | void FDECL1(read_rcfile, char *, appname) |
312 | { | |
313 | FILE * rcfile; | |
314 | struct rcopts * rco; | |
315 | char * pnt, *pnt1; | |
316 | char linebuffer[256]; | |
317 | static char rcfn[] = ".mkisofsrc"; | |
318 | char filename[1000]; | |
319 | int linum; | |
320 | ||
321 | strcpy(filename, rcfn); | |
322 | rcfile = fopen(filename, "r"); | |
323 | if (!rcfile && errno != ENOENT) | |
324 | perror(filename); | |
325 | ||
326 | if (!rcfile) | |
327 | { | |
328 | pnt = getenv("MKISOFSRC"); | |
329 | if (pnt && strlen(pnt) <= sizeof(filename)) | |
330 | { | |
331 | strcpy(filename, pnt); | |
332 | rcfile = fopen(filename, "r"); | |
333 | if (!rcfile && errno != ENOENT) | |
334 | perror(filename); | |
335 | } | |
336 | } | |
337 | ||
338 | if (!rcfile) | |
339 | { | |
340 | pnt = getenv("HOME"); | |
341 | if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename)) | |
342 | { | |
343 | strcpy(filename, pnt); | |
344 | strcat(filename, "/"); | |
345 | strcat(filename, rcfn); | |
346 | rcfile = fopen(filename, "r"); | |
347 | if (!rcfile && errno != ENOENT) | |
348 | perror(filename); | |
349 | } | |
350 | } | |
351 | if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename)) | |
352 | { | |
353 | strcpy(filename, appname); | |
354 | pnt = strrchr(filename, '/'); | |
355 | if (pnt) | |
356 | { | |
357 | strcpy(pnt + 1, rcfn); | |
358 | rcfile = fopen(filename, "r"); | |
359 | if (!rcfile && errno != ENOENT) | |
360 | perror(filename); | |
361 | } | |
362 | } | |
363 | if (!rcfile) | |
364 | return; | |
63eb2d63 RM |
365 | if ( verbose > 0 ) |
366 | { | |
367 | fprintf(stderr, "Using \"%s\"\n", filename); | |
368 | } | |
369 | ||
4b4c4f64 RM |
370 | /* OK, we got it. Now read in the lines and parse them */ |
371 | linum = 0; | |
372 | while (fgets(linebuffer, sizeof(linebuffer), rcfile)) | |
373 | { | |
374 | char *name; | |
375 | char *name_end; | |
376 | ++linum; | |
377 | /* skip any leading white space */ | |
378 | pnt = linebuffer; | |
379 | while (*pnt == ' ' || *pnt == '\t') | |
380 | ++pnt; | |
381 | /* If we are looking at a # character, this line is a comment. */ | |
382 | if (*pnt == '#') | |
383 | continue; | |
384 | /* The name should begin in the left margin. Make sure it is in | |
385 | upper case. Stop when we see white space or a comment. */ | |
386 | name = pnt; | |
11e9a115 | 387 | while (*pnt && isalpha((unsigned char)*pnt)) |
4b4c4f64 | 388 | { |
11e9a115 RM |
389 | if(islower((unsigned char)*pnt)) |
390 | *pnt = toupper((unsigned char)*pnt); | |
4b4c4f64 RM |
391 | pnt++; |
392 | } | |
393 | if (name == pnt) | |
394 | { | |
395 | fprintf(stderr, "%s:%d: name required\n", filename, linum); | |
396 | continue; | |
397 | } | |
398 | name_end = pnt; | |
399 | /* Skip past white space after the name */ | |
400 | while (*pnt == ' ' || *pnt == '\t') | |
401 | pnt++; | |
402 | /* silently ignore errors in the rc file. */ | |
403 | if (*pnt != '=') | |
404 | { | |
405 | fprintf(stderr, "%s:%d: equals sign required\n", filename, linum); | |
406 | continue; | |
407 | } | |
408 | /* Skip pas the = sign, and any white space following it */ | |
409 | pnt++; /* Skip past '=' sign */ | |
410 | while (*pnt == ' ' || *pnt == '\t') | |
411 | pnt++; | |
412 | ||
413 | /* now it is safe to NUL terminate the name */ | |
414 | ||
415 | *name_end = 0; | |
416 | ||
417 | /* Now get rid of trailing newline */ | |
418 | ||
419 | pnt1 = pnt; | |
420 | while (*pnt1) | |
421 | { | |
422 | if (*pnt1 == '\n') | |
423 | { | |
424 | *pnt1 = 0; | |
425 | break; | |
426 | } | |
427 | pnt1++; | |
428 | }; | |
429 | /* OK, now figure out which option we have */ | |
430 | for(rco = rcopt; rco->tag; rco++) { | |
431 | if(strcmp(rco->tag, name) == 0) | |
432 | { | |
433 | *rco->variable = strdup(pnt); | |
434 | break; | |
435 | }; | |
436 | } | |
437 | if (rco->tag == NULL) | |
438 | { | |
439 | fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum, | |
440 | name); | |
441 | } | |
442 | } | |
443 | if (ferror(rcfile)) | |
444 | perror(filename); | |
445 | fclose(rcfile); | |
446 | } | |
447 | ||
448 | char * path_table_l = NULL; | |
449 | char * path_table_m = NULL; | |
63eb2d63 RM |
450 | |
451 | char * jpath_table_l = NULL; | |
452 | char * jpath_table_m = NULL; | |
453 | ||
4b4c4f64 RM |
454 | int goof = 0; |
455 | ||
63eb2d63 RM |
456 | #ifndef TRUE |
457 | #define TRUE 1 | |
458 | #endif | |
459 | ||
460 | #ifndef FALSE | |
461 | #define FALSE 0 | |
462 | #endif | |
463 | ||
4b4c4f64 | 464 | void usage(){ |
63eb2d63 RM |
465 | const char * program_name = "mkisofs"; |
466 | #if 0 | |
4b4c4f64 RM |
467 | fprintf(stderr,"Usage:\n"); |
468 | fprintf(stderr, | |
469 | "mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \ | |
470 | [-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]" | |
4b4c4f64 RM |
471 | "[-P publisher] [ -A app_id ] [-z] \n \ |
472 | [-b boot_image_name] [-c boot_catalog-name] \ | |
473 | [-x path -x path ...] path\n"); | |
63eb2d63 RM |
474 | #endif |
475 | ||
dc83dd64 | 476 | unsigned int i; |
11e9a115 | 477 | /* const char **targets, **pp;*/ |
63eb2d63 RM |
478 | |
479 | fprintf (stderr, "Usage: %s [options] file...\n", program_name); | |
480 | ||
481 | fprintf (stderr, "Options:\n"); | |
482 | for (i = 0; i < OPTION_COUNT; i++) | |
483 | { | |
484 | if (ld_options[i].doc != NULL) | |
485 | { | |
486 | int comma; | |
487 | int len; | |
dc83dd64 | 488 | unsigned int j; |
63eb2d63 RM |
489 | |
490 | fprintf (stderr, " "); | |
491 | ||
492 | comma = FALSE; | |
493 | len = 2; | |
494 | ||
495 | j = i; | |
496 | do | |
497 | { | |
498 | if (ld_options[j].shortopt != '\0' | |
499 | && ld_options[j].control != NO_HELP) | |
500 | { | |
501 | fprintf (stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt); | |
502 | len += (comma ? 2 : 0) + 2; | |
503 | if (ld_options[j].arg != NULL) | |
504 | { | |
505 | if (ld_options[j].opt.has_arg != optional_argument) | |
506 | { | |
507 | fprintf (stderr, " "); | |
508 | ++len; | |
509 | } | |
510 | fprintf (stderr, "%s", ld_options[j].arg); | |
511 | len += strlen (ld_options[j].arg); | |
512 | } | |
513 | comma = TRUE; | |
514 | } | |
515 | ++j; | |
516 | } | |
517 | while (j < OPTION_COUNT && ld_options[j].doc == NULL); | |
518 | ||
519 | j = i; | |
520 | do | |
521 | { | |
522 | if (ld_options[j].opt.name != NULL | |
523 | && ld_options[j].control != NO_HELP) | |
524 | { | |
525 | fprintf (stderr, "%s-%s%s", | |
526 | comma ? ", " : "", | |
527 | ld_options[j].control == TWO_DASHES ? "-" : "", | |
528 | ld_options[j].opt.name); | |
529 | len += ((comma ? 2 : 0) | |
530 | + 1 | |
531 | + (ld_options[j].control == TWO_DASHES ? 1 : 0) | |
532 | + strlen (ld_options[j].opt.name)); | |
533 | if (ld_options[j].arg != NULL) | |
534 | { | |
535 | fprintf (stderr, " %s", ld_options[j].arg); | |
536 | len += 1 + strlen (ld_options[j].arg); | |
537 | } | |
538 | comma = TRUE; | |
539 | } | |
540 | ++j; | |
541 | } | |
542 | while (j < OPTION_COUNT && ld_options[j].doc == NULL); | |
543 | ||
544 | if (len >= 30) | |
545 | { | |
546 | fprintf (stderr, "\n"); | |
547 | len = 0; | |
548 | } | |
549 | ||
550 | for (; len < 30; len++) | |
551 | fputc (' ', stderr); | |
552 | ||
553 | fprintf (stderr, "%s\n", ld_options[i].doc); | |
554 | } | |
555 | } | |
556 | exit(1); | |
4b4c4f64 RM |
557 | } |
558 | ||
559 | ||
560 | /* | |
561 | * Fill in date in the iso9660 format | |
562 | * | |
563 | * The standards state that the timezone offset is in multiples of 15 | |
564 | * minutes, and is what you add to GMT to get the localtime. The U.S. | |
565 | * is always at a negative offset, from -5h to -8h (can vary a little | |
566 | * with DST, I guess). The Linux iso9660 filesystem has had the sign | |
567 | * of this wrong for ages (mkisofs had it wrong too for the longest time). | |
568 | */ | |
11e9a115 | 569 | int FDECL2(iso9660_date,char *, result, time_t, crtime){ |
4b4c4f64 | 570 | struct tm *local; |
11e9a115 | 571 | local = localtime(&crtime); |
4b4c4f64 RM |
572 | result[0] = local->tm_year; |
573 | result[1] = local->tm_mon + 1; | |
574 | result[2] = local->tm_mday; | |
575 | result[3] = local->tm_hour; | |
576 | result[4] = local->tm_min; | |
577 | result[5] = local->tm_sec; | |
578 | ||
579 | /* | |
580 | * Must recalculate proper timezone offset each time, | |
581 | * as some files use daylight savings time and some don't... | |
582 | */ | |
583 | result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ | |
11e9a115 | 584 | local = gmtime(&crtime); |
4b4c4f64 RM |
585 | local->tm_year -= result[0]; |
586 | local->tm_yday -= result[6]; | |
587 | local->tm_hour -= result[3]; | |
588 | local->tm_min -= result[4]; | |
589 | if (local->tm_year < 0) | |
590 | { | |
591 | local->tm_yday = -1; | |
592 | } | |
593 | else | |
594 | { | |
595 | if (local->tm_year > 0) local->tm_yday = 1; | |
596 | } | |
597 | ||
598 | result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15; | |
599 | ||
600 | return 0; | |
601 | } | |
602 | ||
11e9a115 RM |
603 | /* hide "./rr_moved" if all its contents are hidden */ |
604 | static void | |
605 | hide_reloc_dir() | |
606 | { | |
607 | struct directory_entry * s_entry; | |
608 | ||
609 | for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) { | |
610 | if(strcmp(s_entry->name,".")==0 || strcmp(s_entry->name,"..")==0) | |
611 | continue; | |
612 | ||
613 | if((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0) | |
614 | return; | |
615 | } | |
616 | ||
617 | /* all entries are hidden, so hide this directory */ | |
618 | reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; | |
619 | reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY; | |
620 | } | |
4b4c4f64 RM |
621 | |
622 | extern char * cdwrite_data; | |
623 | ||
624 | int FDECL2(main, int, argc, char **, argv){ | |
4b4c4f64 | 625 | struct directory_entry de; |
63eb2d63 | 626 | #ifdef HAVE_SBRK |
4b4c4f64 | 627 | unsigned long mem_start; |
63eb2d63 | 628 | #endif |
4b4c4f64 RM |
629 | struct stat statbuf; |
630 | char * scan_tree; | |
631 | char * merge_image = NULL; | |
632 | struct iso_directory_record * mrootp = NULL; | |
63eb2d63 RM |
633 | struct output_fragment * opnt; |
634 | int longind; | |
635 | char shortopts[OPTION_COUNT * 3 + 2]; | |
636 | struct option longopts[OPTION_COUNT + 1]; | |
4b4c4f64 | 637 | int c; |
11e9a115 | 638 | char *log_file = 0; |
4b4c4f64 RM |
639 | |
640 | if (argc < 2) | |
641 | usage(); | |
642 | ||
643 | /* Get the defaults from the .mkisofsrc file */ | |
644 | read_rcfile(argv[0]); | |
645 | ||
646 | outfile = NULL; | |
63eb2d63 RM |
647 | |
648 | /* | |
649 | * Copy long option initialization from GNU-ld. | |
650 | */ | |
651 | /* Starting the short option string with '-' is for programs that | |
652 | expect options and other ARGV-elements in any order and that care about | |
653 | the ordering of the two. We describe each non-option ARGV-element | |
654 | as if it were the argument of an option with character code 1. */ | |
655 | { | |
dc83dd64 RM |
656 | unsigned int i; |
657 | int is, il; | |
63eb2d63 RM |
658 | shortopts[0] = '-'; |
659 | is = 1; | |
660 | il = 0; | |
661 | for (i = 0; i < OPTION_COUNT; i++) | |
662 | { | |
663 | if (ld_options[i].shortopt != '\0') | |
664 | { | |
665 | shortopts[is] = ld_options[i].shortopt; | |
666 | ++is; | |
667 | if (ld_options[i].opt.has_arg == required_argument | |
668 | || ld_options[i].opt.has_arg == optional_argument) | |
669 | { | |
670 | shortopts[is] = ':'; | |
671 | ++is; | |
672 | if (ld_options[i].opt.has_arg == optional_argument) | |
673 | { | |
674 | shortopts[is] = ':'; | |
675 | ++is; | |
676 | } | |
677 | } | |
678 | } | |
679 | if (ld_options[i].opt.name != NULL) | |
680 | { | |
681 | longopts[il] = ld_options[i].opt; | |
682 | ++il; | |
683 | } | |
684 | } | |
685 | shortopts[is] = '\0'; | |
686 | longopts[il].name = NULL; | |
687 | } | |
688 | ||
689 | while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF) | |
4b4c4f64 RM |
690 | switch (c) |
691 | { | |
63eb2d63 RM |
692 | case 1: |
693 | /* | |
694 | * A filename that we take as input. | |
695 | */ | |
696 | optind--; | |
697 | goto parse_input_files; | |
4b4c4f64 RM |
698 | case 'C': |
699 | /* | |
700 | * This is a temporary hack until cdwrite gets the proper hooks in | |
701 | * it. | |
702 | */ | |
703 | cdwrite_data = optarg; | |
704 | break; | |
63eb2d63 RM |
705 | case 'i': |
706 | fprintf(stderr, "-i option no longer supported.\n"); | |
707 | exit(1); | |
708 | break; | |
709 | case 'J': | |
710 | use_Joliet++; | |
711 | break; | |
4b4c4f64 RM |
712 | case 'a': |
713 | all_files++; | |
714 | break; | |
715 | case 'b': | |
716 | use_eltorito++; | |
717 | boot_image = optarg; /* pathname of the boot image on cd */ | |
718 | if (boot_image == NULL) { | |
719 | fprintf(stderr,"Required boot image pathname missing\n"); | |
720 | exit(1); | |
721 | } | |
722 | break; | |
723 | case 'c': | |
724 | use_eltorito++; | |
725 | boot_catalog = optarg; /* pathname of the boot image on cd */ | |
726 | if (boot_catalog == NULL) { | |
727 | fprintf(stderr,"Required boot catalog pathname missing\n"); | |
728 | exit(1); | |
729 | } | |
730 | break; | |
e1f240ff RM |
731 | case OPTION_BOOT_INFO_TABLE: |
732 | use_boot_info_table = 1; | |
733 | break; | |
734 | case OPTION_NO_EMUL_BOOT: | |
735 | fprintf (stderr, "Ignoring -no-emul-boot (no-emulation is the default behaviour)\n"); | |
736 | break; | |
737 | case OPTION_ELTORITO_EMUL_FLOPPY: | |
738 | use_eltorito_emul_floppy = 1; | |
739 | break; | |
11e9a115 RM |
740 | case OPTION_ABSTRACT: |
741 | abstract = optarg; | |
742 | if(strlen(abstract) > 37) { | |
743 | fprintf(stderr,"Abstract filename string too long\n"); | |
744 | exit(1); | |
745 | }; | |
746 | break; | |
4b4c4f64 RM |
747 | case 'A': |
748 | appid = optarg; | |
749 | if(strlen(appid) > 128) { | |
750 | fprintf(stderr,"Application-id string too long\n"); | |
751 | exit(1); | |
752 | }; | |
753 | break; | |
11e9a115 RM |
754 | case OPTION_BIBLIO: |
755 | biblio = optarg; | |
756 | if(strlen(biblio) > 37) { | |
757 | fprintf(stderr,"Bibliographic filename string too long\n"); | |
758 | exit(1); | |
759 | }; | |
760 | break; | |
761 | case OPTION_COPYRIGHT: | |
762 | copyright = optarg; | |
763 | if(strlen(copyright) > 37) { | |
764 | fprintf(stderr,"Copyright filename string too long\n"); | |
765 | exit(1); | |
766 | }; | |
767 | break; | |
4b4c4f64 RM |
768 | case 'd': |
769 | omit_period++; | |
770 | break; | |
771 | case 'D': | |
772 | RR_relocation_depth = 32767; | |
773 | break; | |
774 | case 'f': | |
775 | follow_links++; | |
776 | break; | |
4b4c4f64 RM |
777 | case 'l': |
778 | full_iso9660_filenames++; | |
779 | break; | |
780 | case 'L': | |
781 | allow_leading_dots++; | |
782 | break; | |
11e9a115 RM |
783 | case OPTION_LOG_FILE: |
784 | log_file = optarg; | |
785 | break; | |
4b4c4f64 RM |
786 | case 'M': |
787 | merge_image = optarg; | |
788 | break; | |
789 | case 'N': | |
790 | omit_version_number++; | |
791 | break; | |
792 | case 'o': | |
793 | outfile = optarg; | |
794 | break; | |
795 | case 'p': | |
796 | preparer = optarg; | |
797 | if(strlen(preparer) > 128) { | |
798 | fprintf(stderr,"Preparer string too long\n"); | |
799 | exit(1); | |
800 | }; | |
801 | break; | |
63eb2d63 RM |
802 | case OPTION_PRINT_SIZE: |
803 | print_size++; | |
804 | break; | |
4b4c4f64 RM |
805 | case 'P': |
806 | publisher = optarg; | |
807 | if(strlen(publisher) > 128) { | |
808 | fprintf(stderr,"Publisher string too long\n"); | |
809 | exit(1); | |
810 | }; | |
811 | break; | |
63eb2d63 RM |
812 | case OPTION_QUIET: |
813 | verbose = 0; | |
814 | break; | |
4b4c4f64 RM |
815 | case 'R': |
816 | use_RockRidge++; | |
817 | break; | |
818 | case 'r': | |
819 | rationalize++; | |
820 | use_RockRidge++; | |
821 | break; | |
63eb2d63 RM |
822 | case OPTION_SPLIT_OUTPUT: |
823 | split_output++; | |
824 | break; | |
11e9a115 RM |
825 | case OPTION_SYSID: |
826 | system_id = optarg; | |
827 | if(strlen(system_id) > 32) { | |
828 | fprintf(stderr,"System ID string too long\n"); | |
829 | exit(1); | |
830 | }; | |
831 | break; | |
4b4c4f64 RM |
832 | case 'T': |
833 | generate_tables++; | |
834 | break; | |
835 | case 'V': | |
836 | volume_id = optarg; | |
11e9a115 RM |
837 | if(strlen(volume_id) > 32) { |
838 | fprintf(stderr,"Volume ID string too long\n"); | |
839 | exit(1); | |
840 | }; | |
841 | break; | |
842 | case OPTION_VOLSET: | |
843 | volset_id = optarg; | |
844 | if(strlen(volset_id) > 128) { | |
845 | fprintf(stderr,"Volume set ID string too long\n"); | |
846 | exit(1); | |
847 | }; | |
848 | break; | |
849 | case OPTION_VOLSET_SIZE: | |
850 | volume_set_size = atoi(optarg); | |
851 | break; | |
852 | case OPTION_VOLSET_SEQ_NUM: | |
853 | volume_sequence_number = atoi(optarg); | |
854 | if (volume_sequence_number > volume_set_size) { | |
855 | fprintf(stderr,"Volume set sequence number too big\n"); | |
856 | exit(1); | |
857 | } | |
4b4c4f64 RM |
858 | break; |
859 | case 'v': | |
860 | verbose++; | |
861 | break; | |
862 | case 'z': | |
863 | #ifdef VMS | |
864 | fprintf(stderr,"Transparent compression not supported with VMS\n"); | |
865 | exit(1); | |
866 | #else | |
867 | transparent_compression++; | |
868 | #endif | |
869 | break; | |
63eb2d63 | 870 | case 'x': |
4b4c4f64 | 871 | case 'm': |
63eb2d63 RM |
872 | /* |
873 | * Somehow two options to do basically the same thing got added somewhere along | |
874 | * the way. The 'match' code supports limited globbing, so this is the one | |
875 | * that got selected. Unfortunately the 'x' switch is probably more intuitive. | |
876 | */ | |
4b4c4f64 RM |
877 | add_match(optarg); |
878 | break; | |
11e9a115 RM |
879 | case OPTION_I_HIDE: |
880 | i_add_match(optarg); | |
881 | break; | |
882 | case OPTION_J_HIDE: | |
883 | j_add_match(optarg); | |
884 | break; | |
63eb2d63 RM |
885 | case OPTION_HELP: |
886 | usage (); | |
887 | exit (0); | |
888 | break; | |
889 | case OPTION_NOSPLIT_SL_COMPONENT: | |
890 | split_SL_component = 0; | |
891 | break; | |
892 | case OPTION_NOSPLIT_SL_FIELD: | |
893 | split_SL_field = 0; | |
4b4c4f64 | 894 | break; |
fa8b1c51 | 895 | case OPTION_CREAT_DATE: |
d70d3907 RM |
896 | if (strlen (optarg) != 16) { |
897 | fprintf (stderr, "date string must be 16 characters.\n"); | |
898 | exit (1); | |
899 | } | |
fa8b1c51 RM |
900 | if (creation_date) |
901 | free(creation_date); | |
902 | creation_date = strdup(optarg); | |
903 | break; | |
904 | case OPTION_MODIF_DATE: | |
d70d3907 RM |
905 | if (strlen (optarg) != 16) { |
906 | fprintf (stderr, "date string must be 16 characters.\n"); | |
907 | exit (1); | |
908 | } | |
fa8b1c51 RM |
909 | if (modification_date) |
910 | free(modification_date); | |
911 | modification_date = strdup(optarg); | |
912 | break; | |
913 | case OPTION_EXPIR_DATE: | |
d70d3907 RM |
914 | if (strlen (optarg) != 16) { |
915 | fprintf (stderr, "date string must be 16 characters.\n"); | |
916 | exit (1); | |
917 | } | |
fa8b1c51 RM |
918 | if (expiration_date) |
919 | free(expiration_date); | |
920 | expiration_date = strdup(optarg); | |
921 | break; | |
922 | case OPTION_EFFEC_DATE: | |
d70d3907 RM |
923 | if (strlen (optarg) != 16) { |
924 | fprintf (stderr, "date string must be 16 characters.\n"); | |
925 | exit (1); | |
926 | } | |
fa8b1c51 RM |
927 | if (effective_date) |
928 | free(effective_date); | |
929 | effective_date = strdup(optarg); | |
930 | break; | |
4b4c4f64 RM |
931 | default: |
932 | usage(); | |
933 | exit(1); | |
934 | } | |
63eb2d63 RM |
935 | |
936 | parse_input_files: | |
937 | ||
4b4c4f64 RM |
938 | #ifdef __NetBSD__ |
939 | { | |
940 | int resource; | |
941 | struct rlimit rlp; | |
942 | if (getrlimit(RLIMIT_DATA,&rlp) == -1) | |
943 | perror("Warning: getrlimit"); | |
944 | else { | |
945 | rlp.rlim_cur=33554432; | |
946 | if (setrlimit(RLIMIT_DATA,&rlp) == -1) | |
947 | perror("Warning: setrlimit"); | |
948 | } | |
949 | } | |
950 | #endif | |
951 | #ifdef HAVE_SBRK | |
952 | mem_start = (unsigned long) sbrk(0); | |
953 | #endif | |
954 | ||
11e9a115 RM |
955 | /* if the -hide-joliet option has been given, set the Joliet option */ |
956 | if (!use_Joliet && j_ishidden()) | |
957 | use_Joliet++; | |
958 | ||
63eb2d63 | 959 | if(verbose > 1) fprintf(stderr,"%s\n", version_string); |
4b4c4f64 | 960 | |
11e9a115 | 961 | if(cdwrite_data == NULL && merge_image != NULL) |
4b4c4f64 | 962 | { |
11e9a115 | 963 | fprintf(stderr,"Multisession usage bug: Must specify -C if -M is used.\n"); |
4b4c4f64 RM |
964 | exit(0); |
965 | } | |
966 | ||
11e9a115 RM |
967 | if(cdwrite_data != NULL && merge_image == NULL) |
968 | { | |
969 | fprintf(stderr,"Warning: -C specified without -M: old session data will not be merged.\n"); | |
970 | } | |
971 | ||
4b4c4f64 RM |
972 | /* The first step is to scan the directory tree, and take some notes */ |
973 | ||
974 | scan_tree = argv[optind]; | |
975 | ||
4b4c4f64 RM |
976 | |
977 | if(!scan_tree){ | |
978 | usage(); | |
979 | exit(1); | |
980 | }; | |
981 | ||
982 | #ifndef VMS | |
983 | if(scan_tree[strlen(scan_tree)-1] != '/') { | |
984 | scan_tree = (char *) e_malloc(strlen(argv[optind])+2); | |
985 | strcpy(scan_tree, argv[optind]); | |
986 | strcat(scan_tree, "/"); | |
987 | }; | |
988 | #endif | |
989 | ||
990 | if(use_RockRidge){ | |
991 | #if 1 | |
992 | extension_record = generate_rr_extension_record("RRIP_1991A", | |
993 | "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", | |
994 | "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size); | |
995 | #else | |
996 | extension_record = generate_rr_extension_record("IEEE_P1282", | |
997 | "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", | |
998 | "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size); | |
999 | #endif | |
1000 | } | |
1001 | ||
11e9a115 RM |
1002 | if (log_file) { |
1003 | FILE *lfp; | |
1004 | int i; | |
1005 | ||
1006 | /* open log file - test that we can open OK */ | |
1007 | if ((lfp = fopen(log_file, "w")) == NULL) { | |
1008 | fprintf(stderr,"can't open logfile: %s\n", log_file); | |
1009 | exit (1); | |
1010 | } | |
1011 | fclose(lfp); | |
1012 | ||
1013 | /* redirect all stderr message to log_file */ | |
1014 | fprintf(stderr, "re-directing all messages to %s\n", log_file); | |
1015 | fflush(stderr); | |
1016 | ||
1017 | /* associate stderr with the log file */ | |
1018 | if (freopen(log_file, "w", stderr) == NULL) { | |
1019 | fprintf(stderr,"can't open logfile: %s\n", log_file); | |
1020 | exit (1); | |
1021 | } | |
1022 | if(verbose > 1) { | |
1023 | for (i=0;i<argc;i++) | |
1024 | fprintf(stderr,"%s ", argv[i]); | |
1025 | ||
1026 | fprintf(stderr,"\n%s\n", version_string); | |
1027 | } | |
1028 | } | |
1029 | ||
4b4c4f64 RM |
1030 | /* |
1031 | * See if boot catalog file exists in root directory, if not | |
1032 | * we will create it. | |
1033 | */ | |
1034 | if (use_eltorito) | |
1035 | init_boot_catalog(argv[optind]); | |
1036 | ||
1037 | /* | |
1038 | * Find the device and inode number of the root directory. | |
1039 | * Record this in the hash table so we don't scan it more than | |
1040 | * once. | |
1041 | */ | |
1042 | stat_filter(argv[optind], &statbuf); | |
1043 | add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); | |
1044 | ||
1045 | memset(&de, 0, sizeof(de)); | |
1046 | ||
1047 | de.filedir = root; /* We need this to bootstrap */ | |
1048 | ||
11e9a115 RM |
1049 | if (cdwrite_data != NULL && merge_image == NULL) { |
1050 | /* in case we want to add a new session, but don't want to merge old one */ | |
1051 | get_session_start(NULL); | |
1052 | } | |
1053 | ||
4b4c4f64 RM |
1054 | if( merge_image != NULL ) |
1055 | { | |
1056 | mrootp = merge_isofs(merge_image); | |
1057 | if( mrootp == NULL ) | |
1058 | { | |
1059 | /* | |
1060 | * Complain and die. | |
1061 | */ | |
1062 | fprintf(stderr,"Unable to open previous session image %s\n", | |
1063 | merge_image); | |
1064 | exit(1); | |
1065 | } | |
1066 | ||
1067 | memcpy(&de.isorec.extent, mrootp->extent, 8); | |
1068 | } | |
1069 | ||
63eb2d63 RM |
1070 | /* |
1071 | * Create an empty root directory. If we ever scan it for real, we will fill in the | |
1072 | * contents. | |
1073 | */ | |
1074 | find_or_create_directory(NULL, "", &de, TRUE); | |
1075 | ||
4b4c4f64 RM |
1076 | /* |
1077 | * Scan the actual directory (and any we find below it) | |
63eb2d63 RM |
1078 | * for files to write out to the output image. Note - we |
1079 | * take multiple source directories and keep merging them | |
1080 | * onto the image. | |
1081 | */ | |
1082 | while(optind < argc) | |
1083 | { | |
1084 | char * node; | |
1085 | struct directory * graft_dir; | |
1086 | struct stat st; | |
1087 | char * short_name; | |
1088 | int status; | |
1089 | char graft_point[1024]; | |
1090 | ||
1091 | /* | |
1092 | * We would like a syntax like: | |
1093 | * | |
1094 | * /tmp=/usr/tmp/xxx | |
1095 | * | |
1096 | * where the user can specify a place to graft each | |
1097 | * component of the tree. To do this, we may have to create | |
1098 | * directories along the way, of course. | |
1099 | * Secondly, I would like to allow the user to do something | |
1100 | * like: | |
1101 | * | |
1102 | * /home/baz/RMAIL=/u3/users/baz/RMAIL | |
1103 | * | |
1104 | * so that normal files could also be injected into the tree | |
1105 | * at an arbitrary point. | |
1106 | * | |
1107 | * The idea is that the last component of whatever is being | |
1108 | * entered would take the name from the last component of | |
1109 | * whatever the user specifies. | |
1110 | * | |
1111 | * The default will be that the file is injected at the | |
1112 | * root of the image tree. | |
1113 | */ | |
1114 | node = strchr(argv[optind], '='); | |
1115 | short_name = NULL; | |
1116 | ||
1117 | if( node != NULL ) | |
1118 | { | |
1119 | char * pnt; | |
1120 | char * xpnt; | |
1121 | ||
1122 | *node = '\0'; | |
1123 | strcpy(graft_point, argv[optind]); | |
1124 | *node = '='; | |
1125 | node++; | |
1126 | ||
1127 | graft_dir = root; | |
1128 | xpnt = graft_point; | |
1129 | if( *xpnt == PATH_SEPARATOR ) | |
1130 | { | |
1131 | xpnt++; | |
1132 | } | |
1133 | ||
1134 | /* | |
1135 | * Loop down deeper and deeper until we | |
1136 | * find the correct insertion spot. | |
1137 | */ | |
1138 | while(1==1) | |
1139 | { | |
1140 | pnt = strchr(xpnt, PATH_SEPARATOR); | |
1141 | if( pnt == NULL ) | |
1142 | { | |
1143 | if( *xpnt != '\0' ) | |
1144 | { | |
1145 | short_name = xpnt; | |
1146 | } | |
1147 | break; | |
1148 | } | |
1149 | *pnt = '\0'; | |
1150 | graft_dir = find_or_create_directory(graft_dir, | |
1151 | graft_point, | |
1152 | NULL, TRUE); | |
1153 | *pnt = PATH_SEPARATOR; | |
1154 | xpnt = pnt + 1; | |
1155 | } | |
1156 | } | |
1157 | else | |
1158 | { | |
1159 | graft_dir = root; | |
1160 | node = argv[optind]; | |
1161 | } | |
1162 | ||
1163 | /* | |
1164 | * Now see whether the user wants to add a regular file, | |
1165 | * or a directory at this point. | |
1166 | */ | |
1167 | status = stat_filter(node, &st); | |
1168 | if( status != 0 ) | |
1169 | { | |
1170 | /* | |
1171 | * This is a fatal error - the user won't be getting what | |
1172 | * they want if we were to proceed. | |
1173 | */ | |
1174 | fprintf(stderr, "Invalid node - %s\n", node); | |
1175 | exit(1); | |
1176 | } | |
1177 | else | |
1178 | { | |
1179 | if( S_ISDIR(st.st_mode) ) | |
1180 | { | |
1181 | if (!scan_directory_tree(graft_dir, node, &de)) | |
1182 | { | |
1183 | exit(1); | |
1184 | } | |
1185 | } | |
1186 | else | |
1187 | { | |
1188 | if( short_name == NULL ) | |
1189 | { | |
1190 | short_name = strrchr(node, PATH_SEPARATOR); | |
1191 | if( short_name == NULL || short_name < node ) | |
1192 | { | |
1193 | short_name = node; | |
1194 | } | |
1195 | else | |
1196 | { | |
1197 | short_name++; | |
1198 | } | |
1199 | } | |
1200 | if( !insert_file_entry(graft_dir, node, short_name) ) | |
1201 | { | |
1202 | exit(1); | |
1203 | } | |
1204 | } | |
1205 | } | |
1206 | ||
1207 | optind++; | |
1208 | } | |
1209 | ||
1210 | ||
1211 | /* | |
1212 | * Now merge in any previous sessions. This is driven on the source | |
1213 | * side, since we may need to create some additional directories. | |
4b4c4f64 | 1214 | */ |
63eb2d63 | 1215 | if( merge_image != NULL ) |
4b4c4f64 | 1216 | { |
63eb2d63 | 1217 | merge_previous_session(root, mrootp); |
4b4c4f64 RM |
1218 | } |
1219 | ||
11e9a115 RM |
1220 | /* hide "./rr_moved" if all its contents have been hidden */ |
1221 | if (reloc_dir && i_ishidden()) | |
1222 | hide_reloc_dir(); | |
1223 | ||
4b4c4f64 | 1224 | /* |
63eb2d63 RM |
1225 | * Sort the directories in the required order (by ISO9660). Also, |
1226 | * choose the names for the 8.3 filesystem if required, and do | |
1227 | * any other post-scan work. | |
4b4c4f64 | 1228 | */ |
63eb2d63 | 1229 | goof += sort_tree(root); |
4b4c4f64 | 1230 | |
63eb2d63 RM |
1231 | if( use_Joliet ) |
1232 | { | |
1233 | goof += joliet_sort_tree(root); | |
1234 | } | |
4b4c4f64 | 1235 | |
11e9a115 RM |
1236 | if (goof) |
1237 | { | |
1238 | fprintf(stderr, "Joliet tree sort failed.\n"); | |
1239 | exit(1); | |
1240 | } | |
4b4c4f64 | 1241 | |
63eb2d63 RM |
1242 | /* |
1243 | * Fix a couple of things in the root directory so that everything | |
1244 | * is self consistent. | |
1245 | */ | |
1246 | root->self = root->contents; /* Fix this up so that the path | |
1247 | tables get done right */ | |
1248 | ||
4b4c4f64 RM |
1249 | /* |
1250 | * OK, ready to write the file. Open it up, and generate the thing. | |
1251 | */ | |
63eb2d63 | 1252 | if (print_size){ |
11e9a115 | 1253 | discimage = fopen("/dev/null", "wb"); |
63eb2d63 RM |
1254 | if (!discimage){ |
1255 | fprintf(stderr,"Unable to open /dev/null\n"); | |
1256 | exit(1); | |
1257 | } | |
1258 | } else if (outfile){ | |
11e9a115 | 1259 | discimage = fopen(outfile, "wb"); |
4b4c4f64 RM |
1260 | if (!discimage){ |
1261 | fprintf(stderr,"Unable to open disc image file\n"); | |
1262 | exit(1); | |
1263 | ||
1264 | }; | |
11e9a115 | 1265 | } else { |
4b4c4f64 RM |
1266 | discimage = stdout; |
1267 | ||
11e9a115 RM |
1268 | #if defined(__CYGWIN32__) |
1269 | setmode(fileno(stdout), O_BINARY); | |
1270 | #endif | |
1271 | } | |
1272 | ||
4b4c4f64 RM |
1273 | /* Now assign addresses on the disc for the path table. */ |
1274 | ||
1275 | path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; | |
1276 | if (path_blocks & 1) path_blocks++; | |
1277 | ||
63eb2d63 RM |
1278 | jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11; |
1279 | if (jpath_blocks & 1) jpath_blocks++; | |
1280 | ||
1281 | /* | |
1282 | * Start to set up the linked list that we use to track the | |
1283 | * contents of the disc. | |
1284 | */ | |
1285 | outputlist_insert(&padblock_desc); | |
1286 | ||
1287 | /* | |
1288 | * PVD for disc. | |
1289 | */ | |
1290 | outputlist_insert(&voldesc_desc); | |
1291 | ||
1292 | /* | |
1293 | * SVD for El Torito. MUST be immediately after the PVD! | |
1294 | */ | |
1295 | if( use_eltorito) | |
1296 | { | |
1297 | outputlist_insert(&torito_desc); | |
1298 | } | |
1299 | ||
1300 | /* | |
1301 | * SVD for Joliet. | |
1302 | */ | |
1303 | if( use_Joliet) | |
1304 | { | |
1305 | outputlist_insert(&joliet_desc); | |
1306 | } | |
1307 | ||
1308 | /* | |
1309 | * Finally the last volume desctiptor. | |
1310 | */ | |
1311 | outputlist_insert(&end_vol); | |
4b4c4f64 | 1312 | |
4b4c4f64 | 1313 | |
63eb2d63 RM |
1314 | outputlist_insert(&pathtable_desc); |
1315 | if( use_Joliet) | |
1316 | { | |
1317 | outputlist_insert(&jpathtable_desc); | |
1318 | } | |
4b4c4f64 | 1319 | |
63eb2d63 RM |
1320 | outputlist_insert(&dirtree_desc); |
1321 | if( use_Joliet) | |
1322 | { | |
1323 | outputlist_insert(&jdirtree_desc); | |
1324 | } | |
4b4c4f64 | 1325 | |
63eb2d63 | 1326 | outputlist_insert(&dirtree_clean); |
4b4c4f64 | 1327 | |
63eb2d63 RM |
1328 | if(extension_record) |
1329 | { | |
1330 | outputlist_insert(&extension_desc); | |
1331 | } | |
4b4c4f64 | 1332 | |
63eb2d63 | 1333 | outputlist_insert(&files_desc); |
4b4c4f64 | 1334 | |
63eb2d63 RM |
1335 | /* |
1336 | * Allow room for the various headers we will be writing. There | |
1337 | * will always be a primary and an end volume descriptor. | |
1338 | */ | |
1339 | last_extent = session_start; | |
1340 | ||
1341 | /* | |
1342 | * Calculate the size of all of the components of the disc, and assign | |
1343 | * extent numbers. | |
1344 | */ | |
1345 | for(opnt = out_list; opnt; opnt = opnt->of_next ) | |
1346 | { | |
1347 | if( opnt->of_size != NULL ) | |
1348 | { | |
1349 | (*opnt->of_size)(last_extent); | |
1350 | } | |
1351 | } | |
4b4c4f64 | 1352 | |
63eb2d63 RM |
1353 | /* |
1354 | * Generate the contents of any of the sections that we want to generate. | |
1355 | * Not all of the fragments will do anything here - most will generate the | |
1356 | * data on the fly when we get to the write pass. | |
1357 | */ | |
1358 | for(opnt = out_list; opnt; opnt = opnt->of_next ) | |
1359 | { | |
1360 | if( opnt->of_generate != NULL ) | |
1361 | { | |
1362 | (*opnt->of_generate)(); | |
1363 | } | |
1364 | } | |
4b4c4f64 RM |
1365 | |
1366 | if( in_image != NULL ) | |
1367 | { | |
1368 | fclose(in_image); | |
1369 | } | |
1370 | ||
63eb2d63 RM |
1371 | /* |
1372 | * Now go through the list of fragments and write the data that corresponds to | |
1373 | * each one. | |
1374 | */ | |
1375 | for(opnt = out_list; opnt; opnt = opnt->of_next ) | |
1376 | { | |
1377 | if( opnt->of_write != NULL ) | |
1378 | { | |
1379 | (*opnt->of_write)(discimage); | |
1380 | } | |
1381 | } | |
4b4c4f64 | 1382 | |
63eb2d63 RM |
1383 | if( verbose > 0 ) |
1384 | { | |
4b4c4f64 | 1385 | #ifdef HAVE_SBRK |
63eb2d63 RM |
1386 | fprintf(stderr,"Max brk space used %x\n", |
1387 | (unsigned int)(((unsigned long)sbrk(0)) - mem_start)); | |
4b4c4f64 | 1388 | #endif |
2c55dbc0 | 1389 | fprintf (stderr, "%llu extents written (%llu MiB)\n", last_extent, last_extent >> 9); |
63eb2d63 RM |
1390 | } |
1391 | ||
4b4c4f64 RM |
1392 | #ifdef VMS |
1393 | return 1; | |
1394 | #else | |
1395 | return 0; | |
1396 | #endif | |
1397 | } | |
1398 | ||
1399 | void * | |
1400 | FDECL1(e_malloc, size_t, size) | |
1401 | { | |
1402 | void* pt = 0; | |
1403 | if( (size > 0) && ((pt=malloc(size))==NULL) ) { | |
1404 | fprintf(stderr, "Not enough memory\n"); | |
1405 | exit (1); | |
1406 | } | |
1407 | return pt; | |
1408 | } |