1 /* @(#)write.c 1.149 20/10/09 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)write.c 1.149 20/10/09 joerg";
6 #endif
7 /*
8 * Program write.c - dump memory structures to file for iso9660 filesystem.
9 *
10 * Written by Eric Youngdale (1993).
11 *
12 * Copyright 1993 Yggdrasil Computing, Incorporated
13 * Copyright (c) 1999-2020 J. Schilling
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2, or (at your option)
18 * any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
31
32 /* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
33
34 #include "mkisofs.h"
35 #include <schily/time.h>
36 #include <schily/fcntl.h>
37 #ifdef SORTING
38 #include "match.h"
39 #endif /* SORTING */
40 #include <schily/errno.h>
41 #include <schily/schily.h>
42 #include <schily/checkerr.h>
43 #ifdef DVD_AUD_VID
44 #include "dvd_reader.h"
45 #include "dvd_file.h"
46 #include "ifo_read.h"
47 #endif
48 #ifdef APPLE_HYB
49 #include <schily/ctype.h>
50 #endif
51
52 #ifdef VMS
53 #include "vms.h"
54 #endif
55
56 #define SIZEOF_UDF_EXT_ATTRIBUTE_COMMON 50
57
58 /* Max number of sectors we will write at one time */
59 #define NSECT 32
60
61 #define INSERTMACRESFORK 1
62
63 /* Counters for statistics */
64
65 LOCAL int table_size = 0;
66 LOCAL int total_dir_size = 0;
67 LOCAL int rockridge_size = 0;
68 LOCAL struct directory **pathlist;
69 LOCAL int next_path_index = 1;
70 LOCAL int sort_goof;
71
72 LOCAL int is_rr_dir = 0;
73
74 struct output_fragment *out_tail;
75 struct output_fragment *out_list;
76
77 EXPORT struct iso_primary_descriptor vol_desc;
78 LOCAL int vol_desc_sum;
79
80 #ifndef APPLE_HFS_HYB
81 #undef __
82 #define __(s) s
83 char *hfs_error = __("no error");
84 #endif
85
86 LOCAL int xawrite __PR((void *buffer, int size, int count,
87 FILE *file, int submode, BOOL islast));
88 EXPORT void xfwrite __PR((void *buffer, int size, int count,
89 FILE *file, int submode, BOOL islast));
90 LOCAL int assign_directory_addresses __PR((struct directory *node));
91 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
92 LOCAL void write_one_file __PR((char *filename, off_t size,
93 FILE *outfile, off_t off,
94 int isrfile, unsigned rba));
95 #else
96 LOCAL void write_one_file __PR((char *filename, off_t size,
97 FILE *outfile));
98 #endif
99 #ifdef UDF
100 LOCAL void write_udf_symlink __PR((char *filename, off_t size,
101 FILE *outfile));
102 #endif
103 LOCAL void write_files __PR((FILE *outfile));
104 #if 0
105 LOCAL void dump_filelist __PR((void));
106 #endif
107 LOCAL int compare_dirs __PR((const void *rr, const void *ll));
108 EXPORT int sort_directory __PR((struct directory_entry **sort_dir,
109 int rr));
110 LOCAL int root_gen __PR((void));
111 LOCAL BOOL assign_file_addresses __PR((struct directory *dpnt, BOOL isnest));
112 LOCAL void free_one_directory __PR((struct directory *dpnt));
113 LOCAL void free_directories __PR((struct directory *dpnt));
114 EXPORT void generate_one_directory __PR((struct directory *dpnt,
115 FILE *outfile));
116 LOCAL void build_pathlist __PR((struct directory *node));
117 LOCAL int compare_paths __PR((void const *r, void const *l));
118 LOCAL int generate_path_tables __PR((void));
119 EXPORT void memcpy_max __PR((char *to, char *from, int max));
120 EXPORT void outputlist_insert __PR((struct output_fragment *frag));
121 LOCAL int file_write __PR((FILE *outfile));
122 LOCAL int pvd_write __PR((FILE *outfile));
123 LOCAL int xpvd_write __PR((FILE *outfile));
124 LOCAL int evd_write __PR((FILE *outfile));
125 LOCAL int vers_write __PR((FILE *outfile));
126 LOCAL int graftcp __PR((char *to, char *from, char *ep));
127 LOCAL int pathcp __PR((char *to, char *from, char *ep));
128 LOCAL int pathtab_write __PR((FILE *outfile));
129 LOCAL int exten_write __PR((FILE *outfile));
130 EXPORT int oneblock_size __PR((UInt32_t starting_extent));
131 LOCAL int pathtab_size __PR((UInt32_t starting_extent));
132 LOCAL int startpad_size __PR((UInt32_t starting_extent));
133 LOCAL int interpad_size __PR((UInt32_t starting_extent));
134 LOCAL int endpad_size __PR((UInt32_t starting_extent));
135 LOCAL int file_gen __PR((void));
136 LOCAL int dirtree_dump __PR((void));
137 LOCAL int dirtree_fixup __PR((UInt32_t starting_extent));
138 LOCAL int dirtree_size __PR((UInt32_t starting_extent));
139 LOCAL int ext_size __PR((UInt32_t starting_extent));
140 LOCAL int dirtree_write __PR((FILE *outfile));
141 LOCAL int dirtree_cleanup __PR((FILE *outfile));
142 LOCAL int startpad_write __PR((FILE *outfile));
143 LOCAL int interpad_write __PR((FILE *outfile));
144 LOCAL int endpad_write __PR((FILE *outfile));
145 #ifdef APPLE_HYB
146 LOCAL int hfs_pad;
147 LOCAL int hfs_get_parms __PR((char *key));
148 LOCAL void hfs_file_gen __PR((UInt32_t start_extent));
149 LOCAL void gen_prepboot __PR((void));
150 EXPORT Ulong get_adj_size __PR((int Csize));
151 EXPORT int adj_size __PR((int Csize, UInt32_t start_extent, int extra));
152 EXPORT void adj_size_other __PR((struct directory *dpnt));
153 LOCAL int hfs_hce_write __PR((FILE *outfile));
154 EXPORT int insert_padding_file __PR((int size));
155 #endif /* APPLE_HYB */
156
157 #ifdef SORTING
158 LOCAL int compare_sort __PR((const void *rr, const void *ll));
159 LOCAL void reassign_link_addresses __PR((struct directory *dpnt));
160 LOCAL int sort_file_addresses __PR((void));
161 #endif /* SORTING */
162
163 /*
164 * Routines to actually write the disc. We write sequentially so that
165 * we could write a tape, or write the disc directly
166 */
167 #define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof (vol_desc.X))
168
169 EXPORT void
xfwrite(buffer,size,count,file,submode,islast)170 xfwrite(buffer, size, count, file, submode, islast)
171 void *buffer;
172 int size;
173 int count;
174 FILE *file;
175 int submode;
176 BOOL islast;
177 {
178 /*
179 * This is a hack that could be made better.
180 * XXXIs this the only place?
181 * It is definitely needed on Operating Systems that do not allow to
182 * write files that are > 2GB. If the system is fast enough to be able
183 * to feed 1400 KB/s writing speed of a DVD-R drive, use stdout.
184 * If the system cannot do this reliable, you need to use this hacky
185 * option.
186 */
187 static int idx = 0;
188
189 #ifdef XFWRITE_DEBUG
190 if (count != 1 || (size % 2048) != 0)
191 error(_("Count: %d, size: %d\n"), count, size);
192 #endif
193 if (count == 0 || size == 0) {
194 errmsgno(EX_BAD,
195 _("Implementation botch, write 0 bytes (size %d count %d).\n"),
196 size, count);
197 abort();
198 }
199
200 if (split_output != 0 &&
201 (idx == 0 || ftell(file) >= ((off_t)1024 * 1024 * 1024))) {
202 char nbuf[512];
203 extern char *outfile;
204
205 if (idx == 0)
206 unlink(outfile);
207 sprintf(nbuf, "%s_%02d", outfile, idx++);
208 file = freopen(nbuf, "wb", file);
209 if (file == NULL) {
210 comerr(_("Cannot open '%s'.\n"), nbuf);
211 }
212 }
213 while (count) {
214 int got;
215
216 seterrno(0);
217 if (osecsize != 0)
218 got = xawrite(buffer, size, count, file, submode, islast);
219 else
220 got = fwrite(buffer, size, count, file);
221
222 if (got <= 0) {
223 comerr(_("cannot fwrite %d*%d\n"), size, count);
224 }
225 /*
226 * This comment is in hope to prevent silly people from
227 * e.g. SuSE (who did not yet learn C but believe that
228 * they need to patch other peoples code) from changing the
229 * next cast into an illegal lhs cast expression.
230 * The cast below is the correct way to handle the problem.
231 * The (void *) cast is to avoid a GCC warning like:
232 * "warning: dereferencing type-punned pointer will break \
233 * strict-aliasing rules"
234 * which is wrong this code. (void *) introduces a compatible
235 * intermediate type in the cast list.
236 */
237 count -= got, *(char **)(void *)&buffer += size * got;
238 }
239 }
240
241 LOCAL int
xawrite(buffer,size,count,file,submode,islast)242 xawrite(buffer, size, count, file, submode, islast)
243 void *buffer;
244 int size;
245 int count;
246 FILE *file;
247 int submode;
248 BOOL islast;
249 {
250 register char *p = buffer;
251 register int amt = size * count;
252 register int n;
253 struct xa_subhdr subhdr[2];
254
255 if (osecsize == 2048)
256 return (fwrite(buffer, size, count, file));
257
258 if (amt % 2048)
259 comerrno(EX_BAD,
260 _("Trying to write %d bytes (not a multiple of 2048).\n"),
261 amt);
262
263 subhdr[0].file_number = subhdr[1].file_number = 0;
264 subhdr[0].channel_number = subhdr[1].channel_number = 0;
265 subhdr[0].coding = subhdr[1].coding = 0;
266
267 while (amt > 0) {
268 #ifdef LATER
269 if (submode < 0)
270 subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
271 else
272 subhdr[0].sub_mode = subhdr[1].sub_mode = submode;
273 #else
274 subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
275 #endif
276
277 if ((amt <= 2048) && islast) {
278 subhdr[0].sub_mode = subhdr[1].sub_mode
279 |= (XA_SUBH_EOR|XA_SUBH_EOF);
280 }
281 n = fwrite(subhdr, sizeof (subhdr), 1, file);
282 if (n <= 0)
283 return (n);
284
285 n = fwrite(p, 2048, 1, file);
286 if (n <= 0)
287 return (n);
288
289 p += 2048;
290 amt -= 2048;
291 }
292 return (1);
293 }
294
295 #ifdef APPLE_HYB
296 /*
297 * use the deferred_write struct to store info about the hfs_boot_file
298 */
299 LOCAL struct deferred_write mac_boot;
300
301 #endif /* APPLE_HYB */
302 LOCAL struct deferred_write *dw_head = NULL,
303 *dw_tail = NULL;
304
305 UInt32_t last_extent_written = 0;
306 LOCAL Uint path_table_index;
307 EXPORT time_t begun;
308 EXPORT struct timeval tv_begun;
309
310 /*
311 * We recursively walk through all of the directories and assign extent
312 * numbers to them. We have already assigned extent numbers to everything that
313 * goes in front of them
314 */
315 LOCAL int
assign_directory_addresses(node)316 assign_directory_addresses(node)
317 struct directory *node;
318 {
319 int dir_size;
320 struct directory *dpnt;
321
322 dpnt = node;
323
324 while (dpnt) {
325 /* skip if it's hidden */
326 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
327 dpnt = dpnt->next;
328 continue;
329 }
330 /*
331 * If we already have an extent for this (i.e. it came from a
332 * multisession disc), then don't reassign a new extent.
333 */
334 dpnt->path_index = next_path_index++;
335 if (dpnt->extent == 0) {
336 dpnt->extent = last_extent;
337 dir_size = ISO_BLOCKS(dpnt->size);
338
339 last_extent += dir_size;
340
341 /*
342 * Leave room for the CE entries for this directory.
343 * Keep them close to the reference directory so that
344 * access will be quick.
345 */
346 if (dpnt->ce_bytes) {
347 last_extent += ISO_BLOCKS(dpnt->ce_bytes);
348 }
349 }
350 if (dpnt->subdir) {
351 assign_directory_addresses(dpnt->subdir);
352 }
353 dpnt = dpnt->next;
354 }
355 return (0);
356 }
357
358 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
359 LOCAL void
write_one_file(filename,size,outfile,off,isrfile,rba)360 write_one_file(filename, size, outfile, off, isrfile, rba)
361 char *filename;
362 off_t size;
363 FILE *outfile;
364 off_t off;
365 int isrfile;
366 unsigned rba;
367 #else
368 LOCAL void
369 write_one_file(filename, size, outfile)
370 char *filename;
371 off_t size;
372 FILE *outfile;
373 #endif /* APPLE_HYB || USE_LARGEFILES */
374 {
375 /*
376 * It seems that there are still stone age C-compilers
377 * around.
378 * The Metrowerks C found on BeOS/PPC does not allow
379 * more than 32kB of local vars.
380 * As we do not need to call write_one_file() recursively
381 * we make buffer static.
382 */
383 #ifdef __BEOS__
384 static char buffer[SECTOR_SIZE * NSECT];
385 #else
386 char buffer[SECTOR_SIZE * NSECT];
387 #endif
388 FILE *infile;
389 off_t remain;
390 int use;
391 int unroundeduse;
392 int bytestowrite = 0; /* Dummy init. to serve GCC bug */
393 int correctedsize = 0;
394
395
396 if ((infile = fopen(filename, "rb")) == NULL) {
397 if (!errhidden(E_OPEN, filename)) {
398 if (!errwarnonly(E_OPEN, filename))
399 ;
400 errmsg(_("Cannot open '%s'.\n"), filename);
401 (void) errabort(E_OPEN, filename, TRUE);
402 }
403 }
404 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
405 if (infile)
406 fseek(infile, off, SEEK_SET);
407 #if defined(INSERTMACRESFORK) && defined(UDF)
408 if (isrfile && use_udf) {
409 memset(buffer, 0, sizeof (buffer));
410 udf_set_extattr_freespace((Uchar *)buffer, size, rba);
411 xfwrite(buffer, SECTOR_SIZE, 1, outfile, XA_SUBH_DATA, 1);
412 last_extent_written++;
413
414 memset(buffer, 0, sizeof (buffer));
415 udf_set_extattr_macresfork((Uchar *)buffer, size, rba);
416 xfwrite(buffer, SIZEOF_UDF_EXT_ATTRIBUTE_COMMON, 1, outfile, XA_SUBH_DATA, 1);
417 correctedsize = SIZEOF_UDF_EXT_ATTRIBUTE_COMMON;
418 }
419 #endif
420 #endif /* APPLE_HYB || USE_LARGEFILES */
421 remain = size;
422
423 while (remain > 0) {
424 int amt;
425
426 unroundeduse = use = (remain > SECTOR_SIZE * NSECT - 1 ?
427 NSECT * SECTOR_SIZE : remain);
428 use = ISO_ROUND_UP(use); /* Round up to nearest sector */
429 /* boundary */
430 memset(buffer, 0, use);
431 seterrno(0);
432 if (infile) {
433 #ifdef VMS
434 amt = fread(buffer, 1, use, infile);
435 #else
436 amt = ffileread(infile, buffer, use);
437 #endif
438 } else {
439 amt = use;
440 }
441 if (amt < use && amt != remain) {
442 /*
443 * Note that mkisofs is not star and no 100% archiver.
444 * We only detect file growth if the new size does not
445 * match 'use' at the last read.
446 */
447 if (geterrno() == 0) {
448 if (!errhidden(amt > remain ? E_GROW:E_SHRINK, filename)) {
449 if (!errwarnonly(amt < remain ? E_SHRINK:E_GROW, filename)) {
450 errmsgno(EX_BAD,
451 _("Try to use the option -data-change-warn\n"));
452 errmsgno(EX_BAD,
453 _("Files should not change while mkisofs is running.\n"));
454 }
455 errmsgno(EX_BAD,
456 _("File '%s' did %s.\n"),
457 filename,
458 amt < remain ?
459 _("shrink"):_("grow"));
460 (void) errabort(amt < remain ?
461 E_SHRINK:E_GROW,
462 filename, TRUE);
463 }
464 } else if (!errhidden(E_READ, filename)) {
465 if (!errwarnonly(E_READ, filename))
466 ;
467 errmsg(_("Cannot read from '%s'\n"), filename);
468 (void) errabort(E_READ, filename, TRUE);
469 }
470 amt = remain; /* Fake success */
471 if (infile) {
472 fclose(infile); /* Prevent furthe failure */
473 infile = NULL;
474 }
475 }
476 #if defined(APPLE_HYB) && defined(INSERTMACRESFORK) && defined(UDF)
477 if (unroundeduse == remain && isrfile && use_udf && correctedsize) {
478 /* adjust the last block to write according to correctedsize */
479 if (use - unroundeduse == correctedsize) {
480 bytestowrite = use;
481 correctedsize = 0;
482 } else if (use - unroundeduse > correctedsize) {
483 bytestowrite = use - correctedsize;
484 correctedsize = 0;
485 } else if (use - unroundeduse < correctedsize) {
486 bytestowrite = unroundeduse;
487 correctedsize -= use - unroundeduse;
488 }
489 } else {
490 bytestowrite = use;
491 }
492 #else
493 bytestowrite = use;
494 #endif
495
496 xfwrite(buffer, bytestowrite, 1, outfile,
497 XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
498 last_extent_written += use / SECTOR_SIZE;
499 #if 0
500 if ((last_extent_written % 1000) < use / SECTOR_SIZE) {
501 fprintf(stderr, "%d..", last_extent_written);
502 }
503 #else
504 if (verbose > 0 &&
505 (int)(last_extent_written % (gui ? 500 : 5000)) <
506 use / SECTOR_SIZE) {
507 time_t now;
508 time_t the_end;
509 double frac;
510
511 time(&now);
512 frac = last_extent_written / (1.0 * last_extent);
513 the_end = begun + (now - begun) / frac;
514 #ifndef NO_FLOATINGPOINT
515 fprintf(stderr, _("%6.2f%% done, estimate finish %s"),
516 frac * 100., ctime(&the_end));
517 #else
518 fprintf(stderr, _("%3d.%-02d%% done, estimate finish %s"),
519 (int)(frac * 100.),
520 (int)((frac+.00005) * 10000.)%100,
521 ctime(&the_end));
522 #endif
523 fflush(stderr);
524 }
525 #endif
526 remain -= use;
527 }
528 #ifdef APPLE_HYB
529 #if defined(INSERTMACRESFORK) && defined(UDF)
530 if (isrfile && use_udf && correctedsize) {
531 if (ISO_ROUND_UP(size) < ISO_ROUND_UP(size + SIZEOF_UDF_EXT_ATTRIBUTE_COMMON)) {
532 memset(buffer, 0, sizeof (buffer));
533 xfwrite(buffer, SECTOR_SIZE - correctedsize, 1, outfile, XA_SUBH_DATA, 1);
534 last_extent_written++;
535 }
536 }
537 #endif
538 #endif
539 if (infile)
540 fclose(infile);
541 } /* write_one_file(... */
542
543 #ifdef UDF
544 LOCAL void
write_udf_symlink(filename,size,outfile)545 write_udf_symlink(filename, size, outfile)
546 char *filename;
547 off_t size;
548 FILE *outfile;
549 {
550 static char buffer[SECTOR_SIZE * NSECT];
551 off_t remain = sizeof (buffer);
552 int use;
553
554 if (udf_get_symlinkcontents(filename, buffer, &remain) < 0) {
555 comerr(_("Cannot open smylink '%s'\n"), filename);
556 }
557 if (remain != size) {
558 comerrno(EX_BAD, _("Symlink '%s' did %s.\n"),
559 filename,
560 size > remain ?
561 _("shrink"):_("grow"));
562 }
563 use = (remain > SECTOR_SIZE * NSECT - 1 ?
564 NSECT * SECTOR_SIZE : remain);
565 use = ISO_ROUND_UP(use);
566 xfwrite(buffer, use, 1, outfile,
567 XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
568 last_extent_written += use / SECTOR_SIZE;
569
570 } /* write_udf_symlink(... */
571 #endif
572
573 LOCAL void
write_files(outfile)574 write_files(outfile)
575 FILE *outfile;
576 {
577 struct deferred_write *dwpnt,
578 *dwnext;
579 unsigned rba = 0;
580
581 dwpnt = dw_head;
582 while (dwpnt) {
583 /*#define DEBUG*/
584 #ifdef DEBUG
585 fprintf(stderr,
586 _("The file name is %s and pad is %d, size is %lld and extent is %d\n"),
587 dwpnt->name, dwpnt->pad,
588 (Llong)dwpnt->size, dwpnt->extent);
589 #endif
590 if (dwpnt->table) {
591 xfwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
592 outfile,
593 XA_SUBH_DATA, TRUE);
594 last_extent_written += ISO_BLOCKS(dwpnt->size);
595 table_size += dwpnt->size;
596 /* fprintf(stderr, _("Size %lld "), (Llong)dwpnt->size); */
597 free(dwpnt->table);
598 dwpnt->table = NULL;
599 } else {
600
601 #ifdef VMS
602 vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
603 #else
604 #ifdef UDF
605 if ((dwpnt->dw_flags & IS_SYMLINK) && use_udf && create_udfsymlinks) {
606 write_udf_symlink(dwpnt->name, dwpnt->size, outfile);
607 } else {
608 #endif /* UDF */
609 #ifdef APPLE_HYB
610 #if defined(INSERTMACRESFORK) && defined(UDF)
611 if (file_is_resource(dwpnt->name, dwpnt->hfstype) && (dwpnt->size > 0) && use_udf) {
612 rba = dwpnt->extent;
613 } else {
614 rba = 0;
615 }
616 #endif /* INSERTMACRESFORK && UDF */
617 write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off,
618 file_is_resource(dwpnt->name, dwpnt->hfstype) && (dwpnt->size > 0), rba);
619 #else
620 #ifdef USE_LARGEFILES
621 write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off, 0, 0);
622 #else
623 write_one_file(dwpnt->name, dwpnt->size, outfile);
624 #endif
625 #endif /* APPLE_HYB */
626 #ifdef UDF
627 }
628 #endif
629 #endif /* VMS */
630 free(dwpnt->name);
631 dwpnt->name = NULL;
632 }
633
634
635 #ifndef DVD_AUD_VID
636 #define dvd_aud_vid_flag 0
637 #endif
638
639 #ifndef APPLE_HYB
640 #define apple_hyb 0
641 #endif
642
643 #if defined(APPLE_HYB) || defined(DVD_AUD_VID)
644
645 if ((apple_hyb && !donotwrite_macpart) || (dvd_aud_vid_flag & DVD_SPEC_VIDEO)) {
646 /*
647 * we may have to pad out ISO files to work with HFS
648 * clump sizes
649 */
650 char blk[SECTOR_SIZE];
651 Uint i;
652
653 for (i = 0; i < dwpnt->pad; i++)
654 xfwrite(blk, SECTOR_SIZE, 1, outfile, 0, FALSE);
655
656 last_extent_written += dwpnt->pad;
657 }
658 #endif /* APPLE_HYB || DVD_AUD_VID */
659
660
661 dwnext = dwpnt;
662 dwpnt = dwpnt->next;
663 free(dwnext);
664 dwnext = NULL;
665 }
666 } /* write_files(... */
667
668 #if 0
669 LOCAL void
670 dump_filelist()
671 {
672 struct deferred_write *dwpnt;
673
674 dwpnt = dw_head;
675 while (dwpnt) {
676 fprintf(stderr, _("File %s\n"), dwpnt->name);
677 dwpnt = dwpnt->next;
678 }
679 fprintf(stderr, "\n");
680 }
681
682 #endif
683
684 LOCAL int
compare_dirs(rr,ll)685 compare_dirs(rr, ll)
686 const void *rr;
687 const void *ll;
688 {
689 char *rpnt,
690 *lpnt;
691 struct directory_entry **r,
692 **l;
693
694 r = (struct directory_entry **)rr;
695 l = (struct directory_entry **)ll;
696 rpnt = (*r)->isorec.name;
697 lpnt = (*l)->isorec.name;
698
699 #ifdef APPLE_HYB
700 /*
701 * resource fork MUST (not sure if this is true for HFS volumes) be
702 * before the data fork - so force it here
703 */
704 if ((*r)->assoc && (*r)->assoc == (*l))
705 return (1);
706 if ((*l)->assoc && (*l)->assoc == (*r))
707 return (-1);
708 #endif /* APPLE_HYB */
709
710 /*
711 * If the names are the same, multiple extent sections of the same file
712 * are sorted by part number. If the part numbers do not differ, this
713 * is an error.
714 */
715 if (strcmp(rpnt, lpnt) == 0) {
716 #ifdef USE_LARGEFILES
717 if ((*r)->mxpart < (*l)->mxpart)
718 return (-1);
719 else if ((*r)->mxpart > (*l)->mxpart)
720 return (1);
721 #endif
722 errmsgno(EX_BAD,
723 _("Error: '%s' and '%s' have the same ISO9660 name '%s'.\n"),
724 (*r)->whole_name, (*l)->whole_name,
725 rpnt);
726 sort_goof++;
727 }
728 /* Check we don't have the same RR name */
729 if (use_RockRidge && !is_rr_dir) {
730 /*
731 * entries *can* have the same RR name in the "rr_moved"
732 * directory so skip checks if we're in reloc_dir
733 */
734 if (strcmp((*r)->name, (*l)->name) == 0) {
735 errmsgno(EX_BAD,
736 _("Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n"),
737 (*r)->whole_name, (*l)->whole_name,
738 (*r)->name);
739 sort_goof++;
740 }
741 }
742 /*
743 * Put the '.' and '..' entries on the head of the sorted list. For
744 * normal ASCII, this always happens to be the case, but out of band
745 * characters cause this not to be the case sometimes.
746 * FIXME(eric) - these tests seem redundant, in that the name is never
747 * assigned these values. It will instead be \000 or \001, and thus
748 * should always be sorted correctly. I need to figure out why I
749 * thought I needed this in the first place.
750 */
751 #if 0
752 if (strcmp(rpnt, ".") == 0)
753 return (-1);
754 if (strcmp(lpnt, ".") == 0)
755 return (1);
756
757 if (strcmp(rpnt, "..") == 0)
758 return (-1);
759 if (strcmp(lpnt, "..") == 0)
760 return (1);
761 #else
762 /*
763 * The code above is wrong (as explained in Eric's comment), leading to
764 * incorrect sort order iff the -L option ("allow leading dots") is in
765 * effect and a directory contains entries that start with a dot.
766 * (TF, Tue Dec 29 13:49:24 CET 1998)
767 */
768 if ((*r)->isorec.name_len[0] == 1 && *rpnt == 0)
769 return (-1); /* '.' */
770 if ((*l)->isorec.name_len[0] == 1 && *lpnt == 0)
771 return (1);
772
773 if ((*r)->isorec.name_len[0] == 1 && *rpnt == 1)
774 return (-1); /* '..' */
775 if ((*l)->isorec.name_len[0] == 1 && *lpnt == 1)
776 return (1);
777 #endif
778
779 while (*rpnt && *lpnt) {
780 if (*rpnt == ';' && *lpnt != ';')
781 return (-1);
782 if (*rpnt != ';' && *lpnt == ';')
783 return (1);
784
785 if (*rpnt == ';' && *lpnt == ';')
786 return (0);
787
788 if (*rpnt == '.' && *lpnt != '.')
789 return (-1);
790 if (*rpnt != '.' && *lpnt == '.')
791 return (1);
792
793 if ((unsigned char) *rpnt < (unsigned char) *lpnt)
794 return (-1);
795 if ((unsigned char) *rpnt > (unsigned char) *lpnt)
796 return (1);
797 rpnt++;
798 lpnt++;
799 }
800 if (*rpnt)
801 return (1);
802 if (*lpnt)
803 return (-1);
804 return (0);
805 }
806
807 /*
808 * Function: sort_directory
809 *
810 * Purpose: Sort the directory in the appropriate ISO9660
811 * order.
812 *
813 * Notes: Returns 0 if OK, returns > 0 if an error occurred.
814 */
815 EXPORT int
sort_directory(sort_dir,rr)816 sort_directory(sort_dir, rr)
817 struct directory_entry **sort_dir;
818 int rr;
819 {
820 int dcount = 0;
821 int xcount = 0;
822 int j;
823 int i,
824 len;
825 struct directory_entry *s_entry;
826 struct directory_entry **sortlist;
827
828 /* need to keep a count of how many entries are hidden */
829 s_entry = *sort_dir;
830 while (s_entry) {
831 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
832 xcount++;
833 dcount++;
834 s_entry = s_entry->next;
835 }
836
837 if (dcount == 0) {
838 return (0);
839 }
840 /* OK, now we know how many there are. Build a vector for sorting. */
841 sortlist = (struct directory_entry **)
842 e_malloc(sizeof (struct directory_entry *) * dcount);
843
844 j = dcount - xcount;
845 dcount = 0;
846 s_entry = *sort_dir;
847 while (s_entry) {
848 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
849 /* put any hidden entries at the end of the vector */
850 sortlist[j++] = s_entry;
851 } else {
852 sortlist[dcount] = s_entry;
853 dcount++;
854 }
855 len = s_entry->isorec.name_len[0];
856 s_entry->isorec.name[len] = 0;
857 s_entry = s_entry->next;
858 }
859
860 /* Each directory is required to contain at least . and .. */
861 if (dcount < 2) {
862 errmsgno(EX_BAD,
863 _("Directory size too small (. or .. may be missing)\n"));
864 sort_goof = 1;
865
866 } else {
867 /* only sort the non-hidden entries */
868 sort_goof = 0;
869 is_rr_dir = rr;
870 #ifdef PROTOTYPES
871 qsort(sortlist, dcount, sizeof (struct directory_entry *),
872 (int (*) (const void *, const void *)) compare_dirs);
873 #else
874 qsort(sortlist, dcount, sizeof (struct directory_entry *),
875 compare_dirs);
876 #endif
877
878 /*
879 * Now reassemble the linked list in the proper sorted order
880 * We still need the hidden entries, as they may be used in
881 * the Joliet tree.
882 */
883 for (i = 0; i < dcount + xcount - 1; i++) {
884 sortlist[i]->next = sortlist[i + 1];
885 }
886
887 sortlist[dcount + xcount - 1]->next = NULL;
888 *sort_dir = sortlist[0];
889 }
890
891 free(sortlist);
892 sortlist = NULL;
893 return (sort_goof);
894 }
895
896 LOCAL int
root_gen()897 root_gen()
898 {
899 init_fstatbuf();
900
901 root_record.length[0] = 1 +
902 offsetof(struct iso_directory_record, name[0]);
903 root_record.ext_attr_length[0] = 0;
904 set_733((char *)root_record.extent, root->extent);
905 set_733((char *)root_record.size, ISO_ROUND_UP(root->size));
906 iso9660_date(root_record.date, root_statbuf.st_mtime);
907 root_record.flags[0] = ISO_DIRECTORY;
908 root_record.file_unit_size[0] = 0;
909 root_record.interleave[0] = 0;
910 set_723(root_record.volume_sequence_number, volume_sequence_number);
911 root_record.name_len[0] = 1;
912 return (0);
913 }
914
915 #ifdef SORTING
916 /*
917 * sorts deferred_write entries based on the sort weight
918 */
919 LOCAL int
compare_sort(rr,ll)920 compare_sort(rr, ll)
921 const void *rr;
922 const void *ll;
923 {
924 struct deferred_write **r;
925 struct deferred_write **l;
926 int r_sort;
927 int l_sort;
928
929 r = (struct deferred_write **)rr;
930 l = (struct deferred_write **)ll;
931 r_sort = (*r)->s_entry->sort;
932 l_sort = (*l)->s_entry->sort;
933
934 if (r_sort != l_sort)
935 return (r_sort < l_sort ? 1 : -1);
936 else
937 return ((*r)->extent - (*l)->extent);
938 }
939
940 /*
941 * reassign start extents to files that are "hard links" to
942 * files that may have been sorted
943 */
944 LOCAL void
reassign_link_addresses(dpnt)945 reassign_link_addresses(dpnt)
946 struct directory *dpnt;
947 {
948 struct directory_entry *s_entry;
949 struct file_hash *s_hash;
950
951 while (dpnt) {
952 s_entry = dpnt->contents;
953 for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
954 /* link files have already been given the weight NOT_SORTED */
955 if (s_entry->sort != NOT_SORTED)
956 continue;
957
958 /* update the start extent */
959 s_hash = find_hash(s_entry);
960 if (s_hash) {
961 set_733((char *)s_entry->isorec.extent, s_hash->starting_block);
962 s_entry->starting_block = s_hash->starting_block;
963 }
964 }
965 if (dpnt->subdir) {
966 reassign_link_addresses(dpnt->subdir);
967 }
968
969 dpnt = dpnt->next;
970 }
971 }
972
973 /*
974 * sort files in order of the given sort weight
975 */
976 LOCAL int
sort_file_addresses()977 sort_file_addresses()
978 {
979 struct deferred_write *dwpnt;
980 struct deferred_write **sortlist;
981 struct directory_entry *s_entry;
982 UInt32_t start_extent;
983 int num = 0;
984 int i;
985
986 /* need to store start extents for linked files */
987 flush_hash();
988
989 /* find out how many files we have */
990 dwpnt = dw_head;
991 while (dwpnt) {
992 num++;
993 dwpnt = dwpnt->next;
994 }
995
996 /* return if we have none */
997 if (num == 0) {
998 return (1);
999 }
1000
1001 /* save the start extent of the first file */
1002 start_extent = dw_head->extent;
1003
1004 /* set up vector to store entries */
1005 sortlist = (struct deferred_write **)
1006 e_malloc(sizeof (struct deferred_write *) * num);
1007
1008 for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next)
1009 sortlist[i] = dwpnt;
1010
1011 /* sort the list */
1012 #ifdef PROTOTYPES
1013 qsort(sortlist, num, sizeof (struct deferred_write *),
1014 (int (*)(const void *, const void *))compare_sort);
1015 #else
1016 qsort(sortlist, num, sizeof (struct deferred_write *), compare_sort);
1017 #endif
1018
1019 /* reconstruct the linked list */
1020 for (i = 0; i < num-1; i++) {
1021 sortlist[i]->next = sortlist[i+1];
1022 }
1023
1024 sortlist[num-1]->next = NULL;
1025 dw_head = sortlist[0];
1026
1027 free(sortlist);
1028
1029 /* set the new start extents for the sorted list */
1030 for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next) {
1031 s_entry = dwpnt->s_entry;
1032 dwpnt->extent = s_entry->starting_block = start_extent;
1033
1034 if (s_entry->de_flags & MULTI_EXTENT) {
1035 struct directory_entry *s_e;
1036 UInt32_t ext = start_extent;
1037
1038 /*
1039 * For unknown reason, we sometimes get mxroot as
1040 * part of the chain and sometime it's missing.
1041 * Be careful to distinct between the mxroot entry and
1042 * others to select both corectly in a conservative way.
1043 */
1044 s_entry->mxroot->starting_block = start_extent;
1045 set_733((char *)s_entry->mxroot->isorec.extent,
1046 start_extent);
1047 start_extent += ISO_BLOCKS(s_entry->mxroot->size);
1048
1049 for (s_e = s_entry;
1050 s_e && s_e->mxroot == s_entry->mxroot;
1051 s_e = s_e->next) {
1052 if (s_e == s_entry->mxroot)
1053 continue;
1054
1055 set_733((char *)s_e->isorec.extent, ext);
1056 s_entry->starting_block = ext;
1057 ext += ISO_BLOCKS(s_e->size);
1058 }
1059 } else {
1060 set_733((char *)s_entry->isorec.extent, start_extent);
1061 start_extent += ISO_BLOCKS(s_entry->size);
1062 }
1063 #ifdef DVD_AUD_VID
1064 /*
1065 * Shouldn't this be done for every type of sort? Otherwise
1066 * we will loose every pad info we add if we sort the files
1067 */
1068 if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
1069 start_extent += dwpnt->pad;
1070 }
1071 #endif /* DVD_AUD_VID */
1072
1073 /* cache start extents for any linked files */
1074 add_hash(s_entry);
1075 }
1076
1077 return (0);
1078 }
1079 #endif /* SORTING */
1080
1081
1082
1083 LOCAL BOOL
assign_file_addresses(dpnt,isnest)1084 assign_file_addresses(dpnt, isnest)
1085 struct directory *dpnt;
1086 BOOL isnest;
1087 {
1088 struct directory *finddir;
1089 struct directory_entry *s_entry;
1090 struct file_hash *s_hash;
1091 struct deferred_write *dwpnt;
1092 char whole_path[PATH_MAX];
1093 #ifdef DVD_AUD_VID
1094 char dvd_path[PATH_MAX];
1095 title_set_info_t *title_set_info = NULL;
1096 char *p;
1097 #endif
1098 BOOL ret = FALSE;
1099
1100 while (dpnt) {
1101 #ifdef DVD_AUD_VID
1102 if ((dvd_aud_vid_flag & DVD_SPEC_VIDEO) && root == dpnt->parent &&
1103 ((p = strstr(dpnt->whole_name, "VIDEO_TS")) != 0)&&
1104 strcmp(p, "VIDEO_TS") == 0) {
1105 int maxlen = strlen(dpnt->whole_name)-8+1;
1106
1107 if (maxlen > sizeof (dvd_path))
1108 maxlen = sizeof (dvd_path);
1109 strlcpy(dvd_path, dpnt->whole_name, maxlen);
1110 #ifdef DEBUG
1111 fprintf(stderr, _("Found 'VIDEO_TS', the path is %s \n"), dvd_path);
1112 #endif
1113 title_set_info = DVDGetFileSet(dvd_path);
1114 if (title_set_info == 0) {
1115 /*
1116 * Do not switch off -dvd-video but let is fail later.
1117 */
1118 /* dvd_aud_vid_flag &= ~DVD_SPEC_VIDEO;*/
1119 errmsgno(EX_BAD, _("Unable to parse DVD-Video structures.\n"));
1120 } else {
1121 ret = TRUE;
1122 }
1123 }
1124 #endif /* DVD_AUD_VID */
1125
1126 for (s_entry = dpnt->contents; s_entry;
1127 s_entry = s_entry->next) {
1128 /*
1129 * If we already have an extent for this entry, then
1130 * don't assign a new one. It must have come from a
1131 * previous session on the disc. Note that we don't
1132 * end up scheduling the thing for writing either.
1133 */
1134 if (get_733(s_entry->isorec.extent) != 0) {
1135 continue;
1136 }
1137 /*
1138 * This saves some space if there are symlinks present.
1139 * If this is a multi-extent file, we get mxpart == 1
1140 * from find_hash().
1141 */
1142 s_hash = find_hash(s_entry);
1143 if (s_hash) {
1144 if (verbose > 2) {
1145 fprintf(stderr, _("Cache hit for '%s%s%s'\n"),
1146 s_entry->filedir->de_name,
1147 SPATH_SEPARATOR,
1148 s_entry->name);
1149 }
1150 s_entry->starting_block = s_hash->starting_block;
1151 set_733((char *)s_entry->isorec.extent,
1152 s_hash->starting_block);
1153 set_733((char *)s_entry->isorec.size,
1154 s_hash->size);
1155 #ifdef USE_LARGEFILES
1156 if (s_entry->de_flags & MULTI_EXTENT) {
1157 struct directory_entry *s_e;
1158 unsigned int ext = s_hash->starting_block;
1159
1160 /*
1161 * Skip the multi extent root entry.
1162 */
1163 if (s_entry->mxpart == 0)
1164 continue;
1165 /*
1166 * The directory is sorted, so we should
1167 * see s_entry->mxpart == 1 first.
1168 */
1169 if (s_entry->mxpart != 1) {
1170 comerrno(EX_BAD,
1171 _("Panic: Multi extent parts for %s not sorted.\n"),
1172 s_entry->whole_name);
1173 }
1174 s_entry->mxroot->starting_block = ext;
1175 for (s_e = s_entry;
1176 s_e && s_e->mxroot == s_entry->mxroot;
1177 s_e = s_e->next) {
1178 set_733((char *)s_e->isorec.extent,
1179 ext);
1180 ext += ISO_BLOCKS(s_e->size);
1181 }
1182 }
1183 #endif
1184
1185 #ifdef SORTING
1186 /* check for non-directory files */
1187 if (do_sort && ((s_entry->isorec.flags[0] & ISO_DIRECTORY) == 0)) {
1188 /* make sure the real file has the highest weighting */
1189 s_hash->de->sort = MAX(s_entry->sort, s_hash->de->sort);
1190 /* flag this as a potential non-sorted file */
1191 s_entry->sort = NOT_SORTED;
1192 }
1193 #endif /* SORTING */
1194 continue;
1195 }
1196 /*
1197 * If this is for a directory that is not a . or
1198 * a .. entry, then look up the information for the
1199 * entry. We have already assigned extents for
1200 * directories, so we just need to fill in the blanks
1201 * here.
1202 */
1203 if (strcmp(s_entry->name, ".") != 0 &&
1204 strcmp(s_entry->name, "..") != 0 &&
1205 s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1206 finddir = dpnt->subdir;
1207 while (finddir && finddir->self != s_entry) {
1208 finddir = finddir->next;
1209 }
1210 if (!finddir) {
1211 #ifdef DVD_AUD_VID
1212 if (title_set_info != 0) {
1213 DVDFreeFileSet(title_set_info);
1214 }
1215 #endif
1216 comerrno(EX_BAD,
1217 _("Fatal goof - could not find dir entry for '%s'\n"),
1218 s_entry->name);
1219 }
1220 set_733((char *)s_entry->isorec.extent,
1221 finddir->extent);
1222 s_entry->starting_block = finddir->extent;
1223 s_entry->size = ISO_ROUND_UP(finddir->size);
1224 total_dir_size += s_entry->size;
1225 add_hash(s_entry);
1226 set_733((char *)s_entry->isorec.size,
1227 ISO_ROUND_UP(finddir->size));
1228 continue;
1229 }
1230 /*
1231 * If this is . or .., then look up the relevant info
1232 * from the tables.
1233 */
1234 if (strcmp(s_entry->name, ".") == 0) {
1235 set_733((char *)s_entry->isorec.extent,
1236 dpnt->extent);
1237
1238 /*
1239 * Set these so that the hash table has the
1240 * correct information
1241 */
1242 s_entry->starting_block = dpnt->extent;
1243 s_entry->size = ISO_ROUND_UP(dpnt->size);
1244
1245 add_hash(s_entry);
1246 s_entry->starting_block = dpnt->extent;
1247 set_733((char *)s_entry->isorec.size,
1248 ISO_ROUND_UP(dpnt->size));
1249 continue;
1250 }
1251 if (strcmp(s_entry->name, "..") == 0) {
1252 if (dpnt == root) {
1253 total_dir_size += root->size;
1254 }
1255 set_733((char *)s_entry->isorec.extent,
1256 dpnt->parent->extent);
1257
1258 /*
1259 * Set these so that the hash table has the
1260 * correct information
1261 */
1262 s_entry->starting_block = dpnt->parent->extent;
1263 s_entry->size =
1264 ISO_ROUND_UP(dpnt->parent->size);
1265
1266 add_hash(s_entry);
1267 s_entry->starting_block = dpnt->parent->extent;
1268 set_733((char *)s_entry->isorec.size,
1269 ISO_ROUND_UP(dpnt->parent->size));
1270 continue;
1271 }
1272 /*
1273 * Some ordinary non-directory file. Just schedule
1274 * the file to be written. This is all quite
1275 * straightforward, just make a list and assign
1276 * extents as we go. Once we get through writing all
1277 * of the directories, we should be ready write out
1278 * these files
1279 */
1280 if (s_entry->size) {
1281 dwpnt = (struct deferred_write *)
1282 e_malloc(sizeof (struct deferred_write));
1283 /* save this directory entry for later use */
1284 dwpnt->s_entry = s_entry;
1285 /* set the initial padding to zero */
1286 dwpnt->pad = 0;
1287 dwpnt->dw_flags = 0;
1288 #ifdef DVD_AUD_VID
1289 if ((dvd_aud_vid_flag & DVD_SPEC_VIDEO) && (title_set_info != 0)) {
1290 int pad;
1291
1292 pad = DVDGetFilePad(title_set_info, s_entry->name);
1293 if (pad < 0) {
1294 errmsgno(EX_BAD,
1295 _("Implementation botch. Video pad for file %s is %d\n"),
1296 s_entry->name, pad),
1297 comerrno(EX_BAD,
1298 _("Either the *.IFO file is bad or you found a mkisofs bug.\n"));
1299 }
1300 dwpnt->pad = pad;
1301 if (verbose > 0 && pad != 0) {
1302 fprintf(stderr,
1303 _("The pad was %d for file %s\n"),
1304 dwpnt->pad, s_entry->name);
1305 }
1306 }
1307 #endif /* DVD_AUD_VID */
1308 #ifdef APPLE_HYB
1309 /*
1310 * maybe an offset to start of the real
1311 * file/fork
1312 */
1313 dwpnt->off = s_entry->hfs_off;
1314 dwpnt->hfstype = s_entry->hfs_type;
1315 #else
1316 dwpnt->off = (off_t)0;
1317 #endif /* APPLE_HYB */
1318 if (s_entry->inode == TABLE_INODE) {
1319 dwpnt->table = s_entry->table;
1320 dwpnt->name = NULL;
1321 sprintf(whole_path, "%s%s%s",
1322 s_entry->filedir->whole_name,
1323 SPATH_SEPARATOR, trans_tbl);
1324 } else {
1325 dwpnt->table = NULL;
1326 strlcpy(whole_path,
1327 s_entry->whole_name,
1328 sizeof (whole_path));
1329 dwpnt->name = e_strdup(whole_path);
1330 }
1331 dwpnt->next = NULL;
1332 dwpnt->size = s_entry->size;
1333 dwpnt->extent = last_extent;
1334 set_733((char *)s_entry->isorec.extent,
1335 last_extent);
1336 s_entry->starting_block = last_extent;
1337 #ifdef USE_LARGEFILES
1338 /*
1339 * Update the entries for multi-section files
1340 * as we now know the starting extent numbers.
1341 */
1342 if (s_entry->de_flags & MULTI_EXTENT) {
1343 struct directory_entry *s_e;
1344 unsigned int ext = last_extent;
1345
1346 /*
1347 * Skip the multi extent root entry.
1348 */
1349 if (s_entry->mxpart == 0) {
1350 if (dwpnt->name)
1351 free(dwpnt->name);
1352 free(dwpnt);
1353 continue;
1354 }
1355 /*
1356 * The directory is sorted, so we should
1357 * see s_entry->mxpart == 1 first.
1358 */
1359 if (s_entry->mxpart != 1) {
1360 comerrno(EX_BAD,
1361 _("Panic: Multi extent parts for %s not sorted.\n"),
1362 s_entry->whole_name);
1363 }
1364 dwpnt->size = s_entry->mxroot->size;
1365 s_entry->mxroot->starting_block = ext;
1366 /*
1367 * Set the mxroot (mxpart == 0) to allow
1368 * the UDF code to fetch the starting
1369 * extent number.
1370 */
1371 set_733((char *)s_entry->mxroot->isorec.extent, ext);
1372 for (s_e = s_entry;
1373 s_e && s_e->mxroot == s_entry->mxroot;
1374 s_e = s_e->next) {
1375 if (s_e->mxpart == 0)
1376 continue;
1377 set_733((char *)s_e->isorec.extent,
1378 ext);
1379 ext += ISO_BLOCKS(s_e->size);
1380 }
1381 add_hash(s_entry);
1382 }
1383 #endif
1384 if (dw_tail) {
1385 dw_tail->next = dwpnt;
1386 dw_tail = dwpnt;
1387 } else {
1388 dw_head = dwpnt;
1389 dw_tail = dwpnt;
1390 }
1391 add_hash(s_entry);
1392 /*
1393 * The cache holds the full size of the file
1394 */
1395 last_extent += ISO_BLOCKS(dwpnt->size);
1396 dwpnt->dw_flags = s_entry->de_flags;
1397 #ifdef APPLE_HYB
1398 #if defined(INSERTMACRESFORK) && defined(UDF)
1399 if (file_is_resource(dwpnt->name, dwpnt->s_entry->hfs_type) && (dwpnt->size > 0) && use_udf) {
1400 last_extent++;
1401 if (ISO_ROUND_UP(dwpnt->size) <
1402 ISO_ROUND_UP(dwpnt->size + SIZEOF_UDF_EXT_ATTRIBUTE_COMMON)) {
1403 last_extent++;
1404 }
1405 }
1406 #endif
1407 #endif /* APPLE_HYB */
1408 #ifdef DVD_AUD_VID
1409 /* Shouldn't we always add the pad info? */
1410 if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
1411 last_extent += dwpnt->pad;
1412 }
1413 #endif /* DVD_AUD_VID */
1414 if (verbose > 2) {
1415 fprintf(stderr, "%u %d %s\n",
1416 s_entry->starting_block,
1417 last_extent - 1, whole_path);
1418 }
1419 #ifdef DBG_ISO
1420 if (ISO_BLOCKS(s_entry->size) > 500) {
1421 fprintf(stderr,
1422 _("Warning: large file '%s'\n"),
1423 whole_path);
1424 fprintf(stderr,
1425 _("Starting block is %d\n"),
1426 s_entry->starting_block);
1427 fprintf(stderr,
1428 _("Reported file size is %lld\n"),
1429 (Llong)s_entry->size);
1430
1431 }
1432 #endif
1433 #ifdef NOT_NEEDED /* Never use this code if you like to create a DVD */
1434
1435 if (last_extent > (800000000 >> 11)) {
1436 /* More than 800Mb? Punt */
1437 fprintf(stderr,
1438 _("Extent overflow processing file '%s'\n"),
1439 whole_path);
1440 fprintf(stderr,
1441 _("Starting block is %d\n"),
1442 s_entry->starting_block);
1443 fprintf(stderr,
1444 _("Reported file size is %lld\n"),
1445 (Llong)s_entry->size);
1446 exit(1);
1447 }
1448 #endif
1449 continue;
1450 }
1451 /*
1452 * This is for zero-length files. If we leave the
1453 * extent 0, then we get screwed, because many readers
1454 * simply drop files that have an extent of zero.
1455 * Thus we leave the size 0, and just assign the
1456 * extent number.
1457 */
1458 set_733((char *)s_entry->isorec.extent, last_extent);
1459 }
1460 if (dpnt->subdir) {
1461 if (assign_file_addresses(dpnt->subdir, TRUE))
1462 ret = TRUE;
1463 }
1464 dpnt = dpnt->next;
1465 }
1466 #ifdef DVD_AUD_VID
1467 if (title_set_info != NULL) {
1468 DVDFreeFileSet(title_set_info);
1469 }
1470 if ((dvd_aud_vid_flag & DVD_SPEC_VIDEO)&& !ret && !isnest) {
1471 errmsgno(EX_BAD,
1472 _("Could not find correct 'VIDEO_TS' directory.\n"));
1473 }
1474 #endif /* DVD_AUD_VID */
1475 return (ret);
1476 } /* assign_file_addresses(... */
1477
1478 LOCAL void
free_one_directory(dpnt)1479 free_one_directory(dpnt)
1480 struct directory *dpnt;
1481 {
1482 struct directory_entry *s_entry;
1483 struct directory_entry *s_entry_d;
1484
1485 s_entry = dpnt->contents;
1486 while (s_entry) {
1487 s_entry_d = s_entry;
1488 s_entry = s_entry->next;
1489
1490 if (s_entry_d->rr_attributes) {
1491 free(s_entry_d->rr_attributes);
1492 s_entry_d->rr_attributes = NULL;
1493 }
1494 if (s_entry_d->name != NULL) {
1495 free(s_entry_d->name);
1496 s_entry_d->name = NULL;
1497 }
1498 if (s_entry_d->whole_name != NULL) {
1499 free(s_entry_d->whole_name);
1500 s_entry_d->whole_name = NULL;
1501 }
1502 #ifdef APPLE_HYB
1503 if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc &&
1504 (s_entry_d->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
1505 free(s_entry_d->hfs_ent);
1506 }
1507 #endif /* APPLE_HYB */
1508
1509 #ifdef DUPLICATES_ONCE
1510 if (s_entry_d->digest_fast) {
1511
1512 if (s_entry_d->digest_full &&
1513 (s_entry_d->digest_full != s_entry_d->digest_fast))
1514 free(s_entry_d->digest_full);
1515
1516 free(s_entry_d->digest_fast);
1517
1518 s_entry_d->digest_fast = NULL;
1519 s_entry_d->digest_full = NULL;
1520 }
1521 #endif
1522 free(s_entry_d);
1523 s_entry_d = NULL;
1524 }
1525 dpnt->contents = NULL;
1526 } /* free_one_directory(... */
1527
1528 LOCAL void
free_directories(dpnt)1529 free_directories(dpnt)
1530 struct directory *dpnt;
1531 {
1532 while (dpnt) {
1533 free_one_directory(dpnt);
1534 if (dpnt->subdir)
1535 free_directories(dpnt->subdir);
1536 dpnt = dpnt->next;
1537 }
1538 }
1539
1540 EXPORT void
generate_one_directory(dpnt,outfile)1541 generate_one_directory(dpnt, outfile)
1542 struct directory *dpnt;
1543 FILE *outfile;
1544 {
1545 unsigned int ce_address = 0;
1546 char *ce_buffer;
1547 unsigned int ce_index = 0;
1548 unsigned int ce_size;
1549 unsigned int dir_index;
1550 char *directory_buffer;
1551 int new_reclen;
1552 struct directory_entry *s_entry;
1553 struct directory_entry *s_entry_d;
1554 unsigned int total_size;
1555
1556 total_size = ISO_ROUND_UP(dpnt->size);
1557 directory_buffer = (char *)e_malloc(total_size);
1558 memset(directory_buffer, 0, total_size);
1559 dir_index = 0;
1560
1561 ce_size = ISO_ROUND_UP(dpnt->ce_bytes);
1562 ce_buffer = NULL;
1563
1564 if (ce_size > 0) {
1565 ce_buffer = (char *)e_malloc(ce_size);
1566 memset(ce_buffer, 0, ce_size);
1567
1568 ce_index = 0;
1569
1570 /* Absolute sector address of CE entries for this directory */
1571 ce_address = last_extent_written + (total_size >> 11);
1572 }
1573 s_entry = dpnt->contents;
1574 while (s_entry) {
1575 /* skip if it's hidden */
1576 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1577 s_entry = s_entry->next;
1578 continue;
1579 }
1580 /*
1581 * We do not allow directory entries to cross sector
1582 * boundaries. Simply pad, and then start the next entry at
1583 * the next sector
1584 */
1585 new_reclen = s_entry->isorec.length[0];
1586 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >=
1587 SECTOR_SIZE) {
1588 dir_index = ISO_ROUND_UP(dir_index);
1589 }
1590 memcpy(directory_buffer + dir_index, &s_entry->isorec,
1591 offsetof(struct iso_directory_record, name[0]) +
1592 s_entry->isorec.name_len[0]);
1593 dir_index += offsetof(struct iso_directory_record, name[0]) +
1594 s_entry->isorec.name_len[0];
1595
1596 /* Add the Rock Ridge attributes, if present */
1597 if (s_entry->rr_attr_size) {
1598 if (dir_index & 1) {
1599 directory_buffer[dir_index++] = 0;
1600 }
1601 /*
1602 * If the RR attributes were too long, then write the
1603 * CE records, as required.
1604 */
1605 if (s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
1606 struct iso_xa_dir_record *xadp;
1607 unsigned char *pnt;
1608 int len,
1609 nbytes;
1610
1611 /*
1612 * Go through the entire record, first skip
1613 * the XA record and then fix up the
1614 * CE entries so that the extent and offset
1615 * are correct
1616 */
1617 pnt = s_entry->rr_attributes;
1618 len = s_entry->total_rr_attr_size;
1619
1620 if (len >= 14) {
1621 xadp = (struct iso_xa_dir_record *)pnt;
1622
1623 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
1624 xadp->reserved[0] == '\0') {
1625 len -= 14;
1626 pnt += 14;
1627 }
1628 }
1629
1630 while (len > 3) {
1631 #ifdef DEBUG
1632 if (ce_size <= 0) {
1633 fprintf(stderr,
1634 _("Warning: ce_index(%d) && ce_address(%d) not initialized\n"),
1635 ce_index, ce_address);
1636 }
1637 #endif
1638
1639 if (pnt[0] == 'C' && pnt[1] == 'E') {
1640 nbytes = get_733((char *)pnt + 20);
1641
1642 if ((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
1643 SECTOR_SIZE) {
1644 ce_index = ISO_ROUND_UP(ce_index);
1645 }
1646 set_733((char *)pnt + 4,
1647 ce_address + (ce_index >> 11));
1648 set_733((char *)pnt + 12,
1649 ce_index & (SECTOR_SIZE - 1));
1650
1651
1652
1653 /*
1654 * Now store the block in the
1655 * ce buffer
1656 */
1657 memcpy(ce_buffer + ce_index,
1658 pnt + pnt[2], nbytes);
1659 ce_index += nbytes;
1660 if (ce_index & 1) {
1661 ce_index++;
1662 }
1663 }
1664 len -= pnt[2];
1665 pnt += pnt[2];
1666 }
1667
1668 }
1669 rockridge_size += s_entry->total_rr_attr_size;
1670 memcpy(directory_buffer + dir_index,
1671 s_entry->rr_attributes,
1672 s_entry->rr_attr_size);
1673 dir_index += s_entry->rr_attr_size;
1674 }
1675 if (dir_index & 1) {
1676 directory_buffer[dir_index++] = 0;
1677 }
1678 s_entry_d = s_entry;
1679 s_entry = s_entry->next;
1680
1681 /*
1682 * Joliet doesn't use the Rock Ridge attributes, so we free
1683 * it here.
1684 */
1685 if (s_entry_d->rr_attributes) {
1686 free(s_entry_d->rr_attributes);
1687 s_entry_d->rr_attributes = NULL;
1688 }
1689 }
1690
1691 if (dpnt->size != dir_index) {
1692 errmsgno(EX_BAD,
1693 _("Unexpected directory length %lld expected: %d '%s'\n"),
1694 (Llong)dpnt->size,
1695 dir_index, dpnt->de_name);
1696 }
1697 xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
1698 last_extent_written += total_size >> 11;
1699 free(directory_buffer);
1700 directory_buffer = NULL;
1701
1702 if (ce_size > 0) {
1703 if (ce_index != dpnt->ce_bytes) {
1704 errmsgno(EX_BAD,
1705 _("Continuation entry record length mismatch %d expected: %d.\n"),
1706 ce_index, dpnt->ce_bytes);
1707 }
1708 xfwrite(ce_buffer, ce_size, 1, outfile, 0, FALSE);
1709 last_extent_written += ce_size >> 11;
1710 free(ce_buffer);
1711 ce_buffer = NULL;
1712 }
1713 } /* generate_one_directory(... */
1714
1715 LOCAL void
build_pathlist(node)1716 build_pathlist(node)
1717 struct directory *node;
1718 {
1719 struct directory *dpnt;
1720
1721 dpnt = node;
1722
1723 while (dpnt) {
1724 /* skip if it's hidden */
1725 if ((dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
1726 pathlist[dpnt->path_index] = dpnt;
1727
1728 if (dpnt->subdir)
1729 build_pathlist(dpnt->subdir);
1730 dpnt = dpnt->next;
1731 }
1732 } /* build_pathlist(... */
1733
1734 LOCAL int
compare_paths(r,l)1735 compare_paths(r, l)
1736 void const *r;
1737 void const *l;
1738 {
1739 struct directory const *ll = *(struct directory * const *) l;
1740 struct directory const *rr = *(struct directory * const *) r;
1741
1742 if (rr->parent->path_index < ll->parent->path_index) {
1743 return (-1);
1744 }
1745 if (rr->parent->path_index > ll->parent->path_index) {
1746 return (1);
1747 }
1748 return (strcmp(rr->self->isorec.name, ll->self->isorec.name));
1749
1750 } /* compare_paths(... */
1751
1752 LOCAL int
generate_path_tables()1753 generate_path_tables()
1754 {
1755 struct directory_entry *de = NULL;
1756 struct directory *dpnt;
1757 int fix;
1758 int i;
1759 int j;
1760 int namelen;
1761 char *npnt;
1762 char *npnt1;
1763 int tablesize;
1764
1765 /* First allocate memory for the tables and initialize the memory */
1766 tablesize = path_blocks << 11;
1767 path_table_m = (char *)e_malloc(tablesize);
1768 path_table_l = (char *)e_malloc(tablesize);
1769 memset(path_table_l, 0, tablesize);
1770 memset(path_table_m, 0, tablesize);
1771
1772 /*
1773 * Now start filling in the path tables. Start with root directory
1774 */
1775
1776 path_table_index = 0;
1777 pathlist = (struct directory **)e_malloc(sizeof (struct directory *)
1778 *next_path_index);
1779 memset(pathlist, 0, sizeof (struct directory *) * next_path_index);
1780 build_pathlist(root);
1781
1782 do {
1783 fix = 0;
1784 #ifdef PROTOTYPES
1785 qsort(&pathlist[1], next_path_index - 1,
1786 sizeof (struct directory *),
1787 (int (*) (const void *, const void *)) compare_paths);
1788 #else
1789 qsort(&pathlist[1], next_path_index - 1,
1790 sizeof (struct directory *),
1791 compare_paths);
1792 #endif
1793
1794 for (j = 1; j < next_path_index; j++) {
1795 if (pathlist[j]->path_index != j) {
1796 pathlist[j]->path_index = j;
1797 fix++;
1798 }
1799 }
1800 } while (fix);
1801
1802 for (j = 1; j < next_path_index; j++) {
1803 dpnt = pathlist[j];
1804 if (!dpnt) {
1805 comerrno(EX_BAD, _("Entry %d not in path tables\n"), j);
1806 }
1807 npnt = dpnt->de_name;
1808
1809 /* So the root comes out OK */
1810 if ((*npnt == 0) || (dpnt == root)) {
1811 npnt = ".";
1812 }
1813 npnt1 = strrchr(npnt, PATH_SEPARATOR);
1814 if (npnt1) {
1815 npnt = npnt1 + 1;
1816 }
1817 de = dpnt->self;
1818 if (!de) {
1819 comerrno(EX_BAD,
1820 _("Fatal ISO9660 goof - directory has amnesia\n"));
1821 }
1822 namelen = de->isorec.name_len[0];
1823
1824 path_table_l[path_table_index] = namelen;
1825 path_table_m[path_table_index] = namelen;
1826 path_table_index += 2;
1827
1828 set_731(path_table_l + path_table_index, dpnt->extent);
1829 set_732(path_table_m + path_table_index, dpnt->extent);
1830 path_table_index += 4;
1831
1832 set_721(path_table_l + path_table_index,
1833 dpnt->parent->path_index);
1834 set_722(path_table_m + path_table_index,
1835 dpnt->parent->path_index);
1836
1837 if (dpnt->parent->path_index > 0xffff) {
1838 static int warned = 0;
1839
1840 if (!warned) {
1841 warned++;
1842 errmsgno(EX_BAD,
1843 _("Unable to generate sane path tables - too many directories (%u)\n"),
1844 dpnt->parent->path_index);
1845 if (!nolimitpathtables)
1846 errmsgno(EX_BAD,
1847 _("Try to use the option -no-limit-pathtables\n"));
1848 }
1849 if (!nolimitpathtables)
1850 exit(EX_BAD);
1851 /*
1852 * Let it point to the root directory instead.
1853 */
1854 set_721(path_table_l + path_table_index, 1);
1855 set_722(path_table_m + path_table_index, 1);
1856 }
1857
1858 path_table_index += 2;
1859
1860 for (i = 0; i < namelen; i++) {
1861 path_table_l[path_table_index] = de->isorec.name[i];
1862 path_table_m[path_table_index] = de->isorec.name[i];
1863 path_table_index++;
1864 }
1865 if (path_table_index & 1) {
1866 path_table_index++; /* For odd lengths we pad */
1867 }
1868 }
1869
1870 free(pathlist);
1871 pathlist = NULL;
1872 if (path_table_index != path_table_size) {
1873 errmsgno(EX_BAD,
1874 _("Path table lengths do not match %d expected: %d\n"),
1875 path_table_index,
1876 path_table_size);
1877 }
1878 return (0);
1879 } /* generate_path_tables(... */
1880
1881 EXPORT void
memcpy_max(to,from,max)1882 memcpy_max(to, from, max)
1883 char *to;
1884 char *from;
1885 int max;
1886 {
1887 int n = strlen(from);
1888
1889 if (n > max) {
1890 n = max;
1891 }
1892 memcpy(to, from, n);
1893
1894 } /* memcpy_max(... */
1895
1896 EXPORT void
outputlist_insert(frag)1897 outputlist_insert(frag)
1898 struct output_fragment *frag;
1899 {
1900 struct output_fragment *nfrag;
1901
1902 nfrag = e_malloc(sizeof (*frag));
1903 movebytes(frag, nfrag, sizeof (*frag));
1904 nfrag->of_start_extent = 0;
1905
1906 if (out_tail == NULL) {
1907 out_list = out_tail = nfrag;
1908 } else {
1909 out_tail->of_next = nfrag;
1910 out_tail = nfrag;
1911 }
1912 }
1913
1914 LOCAL int
file_write(outfile)1915 file_write(outfile)
1916 FILE *outfile;
1917 {
1918 Uint should_write;
1919
1920 #ifdef APPLE_HYB
1921 char buffer[SECTOR_SIZE];
1922
1923 memset(buffer, 0, sizeof (buffer));
1924
1925 if (apple_hyb && !donotwrite_macpart) {
1926
1927 int i;
1928
1929 /*
1930 * write out padding to round up to HFS allocation block
1931 */
1932 for (i = 0; i < hfs_pad; i++)
1933 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
1934
1935 last_extent_written += hfs_pad;
1936 }
1937 #endif /* APPLE_HYB */
1938
1939 /*
1940 * OK, all done with that crap. Now write out the directories. This is
1941 * where the fur starts to fly, because we need to keep track of each
1942 * file as we find it and keep track of where we put it.
1943 */
1944 should_write = last_extent - session_start;
1945
1946 if (verbose > 2) {
1947 #ifdef DBG_ISO
1948 fprintf(stderr,
1949 _("Total directory extents being written = %u\n"),
1950 last_extent);
1951 #endif
1952
1953 #ifdef APPLE_HYB
1954 if (apple_hyb && !donotwrite_macpart)
1955 fprintf(stderr,
1956 _("Total extents scheduled to be written (inc HFS) = %u\n"),
1957 last_extent - session_start);
1958 else
1959 #endif /* APPLE_HYB */
1960
1961 fprintf(stderr,
1962 _("Total extents scheduled to be written = %u\n"),
1963 last_extent - session_start);
1964 }
1965 /* Now write all of the files that we need. */
1966 write_files(outfile);
1967
1968 #ifdef APPLE_HYB
1969 /* write out extents/catalog/dt file */
1970 if (apple_hyb && !donotwrite_macpart) {
1971
1972 xfwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, outfile, 0, FALSE);
1973
1974 /* round up to a whole CD block */
1975 if (HFS_ROUND_UP(hce->hfs_tot_size) -
1976 hce->hfs_tot_size * HFS_BLOCKSZ) {
1977 xfwrite(buffer,
1978 HFS_ROUND_UP(hce->hfs_tot_size) -
1979 hce->hfs_tot_size * HFS_BLOCKSZ, 1, outfile, 0, FALSE);
1980 }
1981 last_extent_written += ISO_ROUND_UP(hce->hfs_tot_size *
1982 HFS_BLOCKSZ) / SECTOR_SIZE;
1983
1984 /* write out HFS boot block */
1985 if (mac_boot.name)
1986 write_one_file(mac_boot.name, mac_boot.size, outfile,
1987 mac_boot.off, 0, 0);
1988 }
1989 #endif /* APPLE_HYB */
1990
1991 /* The rest is just fluff. */
1992 if (verbose == 0) {
1993 return (0);
1994 }
1995 #ifdef APPLE_HYB
1996 if (apple_hyb && !donotwrite_macpart) {
1997 fprintf(stderr,
1998 _("Total extents actually written (inc HFS) = %u\n"),
1999 last_extent_written - session_start);
2000 fprintf(stderr, _("(Size of ISO volume = %d, HFS extra = %d)\n"),
2001 last_extent_written - session_start - hfs_extra,
2002 hfs_extra);
2003 } else
2004 #else
2005 fprintf(stderr, _("Total extents actually written = %d\n"),
2006 last_extent_written - session_start);
2007 #endif /* APPLE_HYB */
2008
2009 /* Hard links throw us off here */
2010 if (should_write != (last_extent - session_start)) {
2011 fprintf(stderr,
2012 _("Number of extents written not what was predicted. Please fix.\n"));
2013 fprintf(stderr, _("Predicted = %d, written = %d\n"),
2014 should_write, last_extent);
2015 }
2016 fprintf(stderr, _("Total translation table size: %d\n"), table_size);
2017 fprintf(stderr, _("Total rockridge attributes bytes: %d\n"),
2018 rockridge_size);
2019 fprintf(stderr, _("Total directory bytes: %d\n"), total_dir_size);
2020 fprintf(stderr, _("Path table size(bytes): %d\n"), path_table_size);
2021
2022 #ifdef DEBUG
2023 fprintf(stderr,
2024 "next extent, last_extent, last_extent_written %d %d %d\n",
2025 next_extent, last_extent, last_extent_written);
2026 #endif
2027
2028 return (0);
2029
2030 } /* iso_write(... */
2031
2032 /*
2033 * Function to write the PVD for the disc.
2034 */
2035 LOCAL int
pvd_write(outfile)2036 pvd_write(outfile)
2037 FILE *outfile;
2038 {
2039 char iso_time[17];
2040 int should_write;
2041 int i;
2042 int s;
2043 Uchar *cp;
2044 extern ldate creation_date;
2045 extern ldate modification_date;
2046 extern ldate expiration_date;
2047 extern ldate effective_date;
2048
2049
2050 iso9660_ldate(iso_time, tv_begun.tv_sec, tv_begun.tv_usec * 1000, -100);
2051
2052 /* Next we write out the primary descriptor for the disc */
2053 memset(&vol_desc, 0, sizeof (vol_desc));
2054 vol_desc.type[0] = ISO_VD_PRIMARY;
2055 strncpy(vol_desc.id, ISO_STANDARD_ID, sizeof (vol_desc.id));
2056 vol_desc.version[0] = 1;
2057
2058 memset(vol_desc.system_id, ' ', sizeof (vol_desc.system_id));
2059 memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
2060
2061 memset(vol_desc.volume_id, ' ', sizeof (vol_desc.volume_id));
2062 memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
2063
2064 should_write = last_extent - session_start;
2065 set_733((char *)vol_desc.volume_space_size, should_write);
2066 set_723(vol_desc.volume_set_size, volume_set_size);
2067 set_723(vol_desc.volume_sequence_number, volume_sequence_number);
2068 set_723(vol_desc.logical_block_size, SECTOR_SIZE);
2069
2070 /*
2071 * The path tables are used by DOS based machines to cache directory
2072 * locations
2073 */
2074 set_733((char *)vol_desc.path_table_size, path_table_size);
2075 set_731(vol_desc.type_l_path_table, path_table[0]);
2076 set_731(vol_desc.opt_type_l_path_table, path_table[1]);
2077 set_732(vol_desc.type_m_path_table, path_table[2]);
2078 set_732(vol_desc.opt_type_m_path_table, path_table[3]);
2079
2080 /* Now we copy the actual root directory record */
2081 memcpy(vol_desc.root_directory_record, &root_record,
2082 offsetof(struct iso_directory_record, name[0]) + 1);
2083
2084 /*
2085 * The rest is just fluff. It looks nice to fill in many of these
2086 * fields, though.
2087 */
2088 FILL_SPACE(volume_set_id);
2089 if (volset_id)
2090 memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id));
2091
2092 FILL_SPACE(publisher_id);
2093 if (publisher)
2094 memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher));
2095
2096 FILL_SPACE(preparer_id);
2097 if (preparer)
2098 memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer));
2099
2100 FILL_SPACE(application_id);
2101 if (appid)
2102 memcpy_max(vol_desc.application_id, appid, strlen(appid));
2103
2104 FILL_SPACE(copyright_file_id);
2105 if (copyright)
2106 memcpy_max(vol_desc.copyright_file_id, copyright,
2107 strlen(copyright));
2108
2109 FILL_SPACE(abstract_file_id);
2110 if (abstract)
2111 memcpy_max(vol_desc.abstract_file_id, abstract,
2112 strlen(abstract));
2113
2114 FILL_SPACE(bibliographic_file_id);
2115 if (biblio)
2116 memcpy_max(vol_desc.bibliographic_file_id, biblio,
2117 strlen(biblio));
2118
2119 FILL_SPACE(creation_date);
2120 FILL_SPACE(modification_date);
2121 FILL_SPACE(expiration_date);
2122 FILL_SPACE(effective_date);
2123 vol_desc.file_structure_version[0] = 1;
2124 FILL_SPACE(application_data);
2125
2126 iso9660_ldate(vol_desc.modification_date,
2127 modification_date.l_sec,
2128 modification_date.l_usec * 1000,
2129 modification_date.l_gmtoff);
2130
2131 memcpy(vol_desc.creation_date, iso_time, 17);
2132 memcpy(vol_desc.expiration_date, "0000000000000000", 17);
2133 memcpy(vol_desc.effective_date, iso_time, 17);
2134
2135 if (creation_date.l_sec)
2136 iso9660_ldate(vol_desc.creation_date,
2137 creation_date.l_sec,
2138 creation_date.l_usec * 1000,
2139 creation_date.l_gmtoff);
2140
2141 if (expiration_date.l_sec)
2142 iso9660_ldate(vol_desc.expiration_date,
2143 expiration_date.l_sec,
2144 expiration_date.l_usec * 1000,
2145 expiration_date.l_gmtoff);
2146
2147 if (effective_date.l_sec)
2148 iso9660_ldate(vol_desc.effective_date,
2149 effective_date.l_sec,
2150 effective_date.l_usec * 1000,
2151 effective_date.l_gmtoff);
2152
2153 if (use_XA) {
2154 char *xap = &((char *)&vol_desc)[1024];
2155
2156 memcpy(&xap[0], "CD-XA001", 8); /* XA Sign. */
2157 memcpy(&xap[8], "\0\0", 2); /* XA flags */
2158 memcpy(&xap[10], "\0\0\0\0\0\0\0\0", 8); /* Start dir */
2159 memcpy(&xap[18], "\0\0\0\0\0\0\0\0", 8); /* Reserved */
2160 }
2161
2162 /*
2163 * Compute a checksum to be used as a fingerprint in case we
2164 * include correct inode/link-count information in the current image.
2165 */
2166 for (i = 0, s = 0, cp = (Uchar *)&vol_desc; i < SECTOR_SIZE; i++) {
2167 s += cp[i] & 0xFF;
2168 }
2169 vol_desc_sum = s;
2170
2171 /* if not a bootable cd do it the old way */
2172 xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2173 last_extent_written++;
2174 return (0);
2175 }
2176
2177 /*
2178 * Function to write the Extended PVD for the disc.
2179 */
2180 LOCAL int
xpvd_write(outfile)2181 xpvd_write(outfile)
2182 FILE *outfile;
2183 {
2184 vol_desc.type[0] = ISO_VD_SUPPLEMENTARY;
2185 vol_desc.version[0] = 2;
2186 vol_desc.file_structure_version[0] = 2;
2187
2188 /* if not a bootable cd do it the old way */
2189 xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2190 last_extent_written++;
2191 return (0);
2192 }
2193
2194 /*
2195 * Function to write the EVD for the disc.
2196 */
2197 LOCAL int
evd_write(outfile)2198 evd_write(outfile)
2199 FILE *outfile;
2200 {
2201 struct iso_primary_descriptor evol_desc;
2202
2203 /*
2204 * Now write the end volume descriptor. Much simpler than the other
2205 * one
2206 */
2207 memset(&evol_desc, 0, sizeof (evol_desc));
2208 evol_desc.type[0] = (unsigned char) ISO_VD_END;
2209 strncpy(evol_desc.id, ISO_STANDARD_ID, sizeof (evol_desc.id));
2210 evol_desc.version[0] = 1;
2211 xfwrite(&evol_desc, SECTOR_SIZE, 1, outfile, 0, TRUE);
2212 last_extent_written += 1;
2213 return (0);
2214 }
2215
2216 /*
2217 * Function to write the version information for the disc.
2218 * Warning: Do not disable or change this function. The data created by this
2219 * function is used to tell the filesystem driver in the OS kernel that this
2220 * mkisofs version includes correct inode information.
2221 */
2222 LOCAL int
vers_write(outfile)2223 vers_write(outfile)
2224 FILE *outfile;
2225 {
2226 char vers[SECTOR_SIZE+1];
2227 int X_ac;
2228 char **X_av;
2229 char *cp;
2230 int i;
2231 int idx = 4;
2232 int len;
2233 extern char version_string[];
2234 extern int path_ind;
2235 extern ldate creation_date;
2236
2237 /* Now write the version descriptor. */
2238 memset(vers, 0, sizeof (vers));
2239 strcpy(vers, "MKI "); /* strcpy() OK here */
2240
2241 cp = vers;
2242 X_ac = saved_ac();
2243 X_av = saved_av();
2244 if (creation_date.l_sec)
2245 strlcpy(&cp[idx], ctime(&creation_date.l_sec), 26);
2246 else
2247 strlcpy(&cp[idx], ctime(&begun), 26);
2248 idx += 25;
2249 strlcpy(&cp[idx], version_string, SECTOR_SIZE - idx);
2250 idx += strlen(version_string);
2251 for (i = 1; i < X_ac; i++) {
2252 len = strlen(X_av[i]);
2253 if ((idx + len + 2) >= SECTOR_SIZE)
2254 break;
2255 cp[idx++] = ' ';
2256 /*
2257 * Do not give away secret information when not in debug mode.
2258 */
2259 if (debug)
2260 strlcpy(&cp[idx], X_av[i], SECTOR_SIZE - idx);
2261 else if (i >= path_ind)
2262 len = graftcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2263 else if (X_av[i][0] == '/')
2264 len = pathcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2265 else
2266 strlcpy(&cp[idx], X_av[i], SECTOR_SIZE - idx);
2267 idx += len;
2268 }
2269
2270 cp[SECTOR_SIZE - 1] = '\0';
2271 len = 0;
2272 if (correct_inodes) {
2273 /*
2274 * Only add this fingerprint in case we include correct
2275 * inode/link-count information in the current image.
2276 */
2277 len = vol_desc_sum;
2278 }
2279 cp = &vers[SECTOR_SIZE - 1];
2280 *(Uchar *)cp = len % 256;
2281 len /= 256;
2282 *(Uchar *)--cp = len % 256;
2283 len /= 256;
2284 *(Uchar *)--cp = len % 256;
2285
2286 xfwrite(vers, SECTOR_SIZE, 1, outfile, 0, TRUE);
2287 last_extent_written += 1;
2288 return (0);
2289 }
2290
2291 /*
2292 * Avoid to write unwanted information into the version info string.
2293 */
2294 LOCAL int
graftcp(to,from,ep)2295 graftcp(to, from, ep)
2296 char *to;
2297 char *from;
2298 char *ep;
2299 {
2300 int len = strlen(from);
2301 char *node = NULL;
2302
2303 if (use_graft_ptrs)
2304 node = findgequal(from);
2305
2306 if (node == NULL) {
2307 len = 0;
2308 node = from;
2309 } else {
2310 len = node - from;
2311 *node = '\0';
2312 strncpy(to, from, ep - to);
2313 *node++ = '=';
2314 to += len++;
2315 *to++ = '=';
2316 }
2317 return (len + pathcp(to, node, ep));
2318 }
2319
2320 LOCAL int
pathcp(to,from,ep)2321 pathcp(to, from, ep)
2322 char *to;
2323 char *from;
2324 char *ep;
2325 {
2326 int len = strlen(from);
2327 char *p;
2328
2329 p = strrchr(from, '/');
2330 if (p == NULL) {
2331 strncpy(to, from, ep - to);
2332 } else {
2333 if (p[1] == '\0') {
2334 --p;
2335 while (p > from && *p != '/')
2336 --p;
2337 }
2338 len = 0;
2339 if (*p == '/') {
2340 strncpy(to, "...", ep - to);
2341 to += 3;
2342 len = 3;
2343 }
2344 if (to < ep) {
2345 strncpy(to, p, ep - to);
2346 len += strlen(to);
2347 }
2348 }
2349 return (len);
2350 }
2351
2352
2353 /*
2354 * Function to write the path table for the disc.
2355 */
2356 LOCAL int
pathtab_write(outfile)2357 pathtab_write(outfile)
2358 FILE *outfile;
2359 {
2360 /* Next we write the path tables */
2361 xfwrite(path_table_l, path_blocks << 11, 1, outfile, 0, FALSE);
2362 xfwrite(path_table_m, path_blocks << 11, 1, outfile, 0, FALSE);
2363 last_extent_written += 2 * path_blocks;
2364 free(path_table_l);
2365 free(path_table_m);
2366 path_table_l = NULL;
2367 path_table_m = NULL;
2368 return (0);
2369 }
2370
2371 LOCAL int
exten_write(outfile)2372 exten_write(outfile)
2373 FILE *outfile;
2374 {
2375 xfwrite(extension_record, SECTOR_SIZE, 1, outfile, 0, FALSE);
2376 last_extent_written++;
2377 return (0);
2378 }
2379
2380 /*
2381 * Functions to describe padding block at the start of the disc.
2382 */
2383 EXPORT int
oneblock_size(starting_extent)2384 oneblock_size(starting_extent)
2385 UInt32_t starting_extent;
2386 {
2387 last_extent++;
2388 return (0);
2389 }
2390
2391 /*
2392 * Functions to describe path table size.
2393 */
2394 LOCAL int
pathtab_size(starting_extent)2395 pathtab_size(starting_extent)
2396 UInt32_t starting_extent;
2397 {
2398 path_table[0] = starting_extent;
2399
2400 path_table[1] = 0;
2401 path_table[2] = path_table[0] + path_blocks;
2402 path_table[3] = 0;
2403 last_extent += 2 * path_blocks;
2404 return (0);
2405 }
2406
2407 /*
2408 * Functions to describe padding blocks before PVD.
2409 */
2410 LOCAL int
startpad_size(starting_extent)2411 startpad_size(starting_extent)
2412 UInt32_t starting_extent;
2413 {
2414 last_extent = session_start + 16;
2415 return (0);
2416 }
2417
2418 /*
2419 * Functions to describe padding blocks between sections.
2420 */
2421 LOCAL int
interpad_size(starting_extent)2422 interpad_size(starting_extent)
2423 UInt32_t starting_extent;
2424 {
2425 int emod = 0;
2426
2427 #ifdef needed
2428 starting_extent += 16; /* First add 16 pad blocks */
2429 #endif
2430 if ((emod = starting_extent % 16) != 0) {
2431 starting_extent += 16 - emod; /* Now pad to mod 16 # */
2432 }
2433 last_extent = starting_extent;
2434 return (0);
2435 }
2436
2437 /*
2438 * Functions to describe padding blocks at end of disk.
2439 */
2440 LOCAL int
endpad_size(starting_extent)2441 endpad_size(starting_extent)
2442 UInt32_t starting_extent;
2443 {
2444 starting_extent += 150; /* 150 pad blocks (post gap) */
2445 last_extent = starting_extent;
2446 return (0);
2447 }
2448
2449 LOCAL int
file_gen()2450 file_gen()
2451 {
2452 #ifdef APPLE_HYB
2453 UInt32_t start_extent = last_extent; /* orig ISO files start */
2454
2455 #endif /* APPLE_HYB */
2456
2457 if (!assign_file_addresses(root, FALSE)) {
2458 #ifdef DVD_AUD_VID
2459 if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
2460 comerrno(EX_BAD, _("Unable to make a DVD-Video image.\n"));
2461 }
2462 #else
2463 ;
2464 /* EMPTY */
2465 #endif
2466 }
2467
2468
2469 #ifdef SORTING
2470 if (do_sort) {
2471 if (sort_file_addresses() == 0)
2472 reassign_link_addresses(root);
2473 }
2474 #endif /* SORTING */
2475
2476 #ifdef APPLE_HYB
2477 /*
2478 * put this here for the time being - may when I've worked out how to
2479 * use Eric's new system for creating/writing parts of the image it
2480 * may move to it's own routine
2481 */
2482 if (apple_hyb && !donotwrite_macpart)
2483 hfs_file_gen(start_extent);
2484 #ifdef PREP_BOOT
2485 else if (use_prep_boot || use_chrp_boot)
2486 gen_prepboot();
2487 #endif /* PREP_BOOT */
2488 #endif /* APPLE_HYB */
2489
2490 /*
2491 * Do inode/hard link related stuff for non-directory type files.
2492 */
2493 do_inode(root);
2494 return (0);
2495 }
2496
2497 LOCAL int
dirtree_dump()2498 dirtree_dump()
2499 {
2500 if (verbose > 2) {
2501 dump_tree(root);
2502 }
2503 return (0);
2504 }
2505
2506 LOCAL int
dirtree_fixup(starting_extent)2507 dirtree_fixup(starting_extent)
2508 UInt32_t starting_extent;
2509 {
2510 if (use_RockRidge && reloc_dir)
2511 finish_cl_pl_entries();
2512
2513 /*
2514 * Set the link count for directories to 2 + number of sub-directories.
2515 */
2516 if (use_RockRidge)
2517 do_dir_nlink(root);
2518 return (0);
2519 }
2520
2521 LOCAL int
dirtree_size(starting_extent)2522 dirtree_size(starting_extent)
2523 UInt32_t starting_extent;
2524 {
2525 assign_directory_addresses(root);
2526 return (0);
2527 }
2528
2529 LOCAL int
ext_size(starting_extent)2530 ext_size(starting_extent)
2531 UInt32_t starting_extent;
2532 {
2533 extern int extension_record_size;
2534 struct directory_entry *s_entry;
2535
2536 extension_record_extent = starting_extent;
2537 s_entry = root->contents;
2538 set_733((char *)s_entry->rr_attributes + s_entry->rr_attr_size - 24,
2539 extension_record_extent);
2540 set_733((char *)s_entry->rr_attributes + s_entry->rr_attr_size - 8,
2541 extension_record_size);
2542 last_extent++;
2543 return (0);
2544 }
2545
2546 LOCAL int
dirtree_write(outfile)2547 dirtree_write(outfile)
2548 FILE *outfile;
2549 {
2550 generate_iso9660_directories(root, outfile);
2551 return (0);
2552 }
2553
2554 LOCAL int
dirtree_cleanup(outfile)2555 dirtree_cleanup(outfile)
2556 FILE *outfile;
2557 {
2558 free_directories(root);
2559 return (0);
2560 }
2561
2562 LOCAL int
startpad_write(outfile)2563 startpad_write(outfile)
2564 FILE *outfile;
2565 {
2566 char buffer[SECTOR_SIZE];
2567 int i;
2568 int npad;
2569
2570 memset(buffer, 0, sizeof (buffer));
2571
2572 npad = session_start + 16 - last_extent_written;
2573
2574 for (i = 0; i < npad; i++) {
2575 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2576 }
2577
2578 last_extent_written += npad;
2579 return (0);
2580 }
2581
2582 LOCAL int
interpad_write(outfile)2583 interpad_write(outfile)
2584 FILE *outfile;
2585 {
2586 char buffer[SECTOR_SIZE];
2587 int i;
2588 int npad = 0;
2589
2590 memset(buffer, 0, sizeof (buffer));
2591
2592 #ifdef needed
2593 npad = 16;
2594 #endif
2595 if ((i = last_extent_written % 16) != 0)
2596 npad += 16 - i;
2597
2598 for (i = 0; i < npad; i++) {
2599 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2600 }
2601
2602 last_extent_written += npad;
2603 return (0);
2604 }
2605
2606 LOCAL int
endpad_write(outfile)2607 endpad_write(outfile)
2608 FILE *outfile;
2609 {
2610 char buffer[SECTOR_SIZE];
2611 int i;
2612
2613 memset(buffer, 0, sizeof (buffer));
2614
2615 for (i = 0; i < 150; i++) {
2616 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2617 }
2618
2619 last_extent_written += 150;
2620 return (0);
2621 }
2622
2623 #ifdef APPLE_HYB
2624
2625 /*
2626 * hfs_get_parms: get HFS parameters from the command line
2627 */
2628
2629 LOCAL int
hfs_get_parms(key)2630 hfs_get_parms(key)
2631 char *key;
2632 {
2633 int ret = 0;
2634 char *p;
2635
2636 if (hfs_parms == NULL)
2637 return (ret);
2638
2639 if ((p = strstr(hfs_parms, key)) != NULL) {
2640 p += strlen(key) + 1;
2641 sscanf(p, "%d", &ret);
2642 }
2643
2644 return (ret);
2645 }
2646
2647 /*
2648 * hfs_file_gen: set up "fake" HFS volume using the ISO9660 tree
2649 */
2650 LOCAL void
hfs_file_gen(start_extent)2651 hfs_file_gen(start_extent)
2652 UInt32_t start_extent;
2653 {
2654 int Csize; /* clump size for HFS vol */
2655 int loop;
2656 UInt32_t last_extent_save = last_extent;
2657 char *p;
2658
2659 /* allocate memory for the libhfs/mkisofs extra info */
2660 hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2661
2662 hce->error = (char *)e_malloc(1024);
2663
2664 /* mark as unallocated for use later */
2665 hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2666
2667 /* reserve space for the label partition - if it is needed */
2668 #ifdef PREP_BOOT
2669 /* a PReP bootable partition needs the map.. */
2670 if (gen_pt || use_prep_boot || use_chrp_boot)
2671 #else
2672 if (gen_pt)
2673 #endif /* PREP_BOOT */
2674 hce->hfs_map_size = HFS_MAP_SIZE;
2675 else
2676 hce->hfs_map_size = 0;
2677
2678 /* set the HFS parameter string to upper case */
2679 if (hfs_parms) {
2680 for (p = hfs_parms; *p; p++)
2681 *p = toupper((*p & 0xFF));
2682 }
2683
2684 /* set the initial factor to increase Catalog file size */
2685 if ((hce->ctc_size = hfs_get_parms("CTC")) == 0)
2686 hce->ctc_size = CTC;
2687
2688 /* set the max size of the Catalog file */
2689 if ((hce->max_XTCsize = hfs_get_parms("MAX_XTCSIZE")) == 0)
2690 hce->max_XTCsize = MAX_XTCSIZE;
2691
2692 /* set the number of time to try to make an HFS volume */
2693 if ((loop = hfs_get_parms("CTC_LOOP")) == 0)
2694 loop = CTC_LOOP;
2695
2696 /*
2697 * "create" the HFS volume (just the header, catalog/extents files) if
2698 * there's a problem with the Catalog file being too small, we keep on
2699 * increasing the size (up to CTC_LOOP) times and try again.
2700 * Unfortunately I don't know enough about the inner workings of HFS,
2701 * so I can't workout the size of the Catalog file in advance (and I
2702 * don't want to "grow" as is is normally allowed to), therefore, this
2703 * approach is a bit over the top as it involves throwing away the
2704 * "volume" we have created and trying again ...
2705 */
2706 do {
2707 hce->error[0] = '\0';
2708
2709 /* attempt to create the Mac volume */
2710 #ifdef APPLE_HFS_HYB
2711 Csize = make_mac_volume(root, start_extent);
2712 #else
2713 Csize = -1;
2714 #endif
2715
2716 /* if we have a problem ... */
2717 if (Csize < 0) {
2718 /*
2719 * we've made too many attempts, or got some other
2720 * error
2721 */
2722 if (loop == 0 || errno != HCE_ERROR) {
2723 /* HCE_ERROR is not a valid errno value */
2724 if (errno == HCE_ERROR)
2725 errno = 0;
2726
2727 /* exit with the error */
2728 if (*hce->error)
2729 fprintf(stderr, "%s\n", hce->error);
2730 perr(hfs_error);
2731 } else {
2732 /* increase Catalog file size factor */
2733 hce->ctc_size *= CTC;
2734
2735 /*
2736 * reset the initial "last_extent" and try
2737 * again
2738 */
2739 last_extent = last_extent_save;
2740 }
2741 } else {
2742 /* everything OK - just carry on ... */
2743 loop = 0;
2744 }
2745 }
2746 while (loop--);
2747
2748 hfs_extra = HFS_ROUND_UP(hce->hfs_tot_size) / SECTOR_SIZE;
2749
2750 last_extent += hfs_extra;
2751
2752 /* generate the Mac label and HFS partition maps */
2753 mac_boot.name = hfs_boot_file;
2754
2755 /*
2756 * only generate the partition tables etc. if we are making a bootable
2757 * CD - or if the -part option is given
2758 */
2759 if (gen_pt) {
2760 if (gen_mac_label(&mac_boot)) {
2761 if (*hce->error)
2762 fprintf(stderr, "%s\n", hce->error);
2763 perr(hfs_error);
2764 }
2765 }
2766 /* set Autostart filename if required */
2767 if (autoname) {
2768 if (autostart())
2769 perr("Autostart filename must less than 12 characters");
2770 }
2771 /* finished with any HFS type errors */
2772 free(hce->error);
2773 hce->error = 0;
2774
2775 /*
2776 * the ISO files need to start on a multiple of the HFS allocation
2777 * blocks, so find out how much padding we need
2778 */
2779
2780 /*
2781 * take in accout alignment of files wrt HFS volume start - remove any
2782 * previous session as well
2783 */
2784 start_extent -= session_start;
2785 hfs_pad = ROUND_UP(start_extent*SECTOR_SIZE +
2786 (hce->hfs_hdr_size + hce->hfs_map_size) * HFS_BLOCKSZ,
2787 Csize) / SECTOR_SIZE;
2788
2789 hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size) /
2790 HFS_BLK_CONV);
2791
2792 #ifdef PREP_BOOT
2793 gen_prepboot_label(hce->hfs_map);
2794 #endif /* PREP_BOOT */
2795
2796 }
2797
2798 #ifdef PREP_BOOT
2799 LOCAL void
gen_prepboot()2800 gen_prepboot()
2801 {
2802 /*
2803 * we need to allocate the hce struct since hce->hfs_map is used to
2804 * generate the fdisk partition map required for PReP booting
2805 */
2806 hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2807
2808 /* mark as unallocated for use later */
2809 hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2810
2811 /* reserve space for the label partition - if it is needed */
2812 hce->hfs_map_size = HFS_MAP_SIZE;
2813
2814 hce->hfs_map = (unsigned char *) e_malloc(hce->hfs_map_size * HFS_BLOCKSZ);
2815 gen_prepboot_label(hce->hfs_map);
2816 }
2817
2818 #endif /* PREP_BOOT */
2819
2820 /*
2821 * get_adj_size: get the ajusted size of the volume with the HFS
2822 * allocation block size for each file
2823 */
2824 EXPORT Ulong
get_adj_size(Csize)2825 get_adj_size(Csize)
2826 int Csize;
2827 {
2828 struct deferred_write *dw;
2829 Ulong size = 0;
2830 int count = 0;
2831
2832 /* loop through all the files finding the new total size */
2833 for (dw = dw_head; dw; dw = dw->next) {
2834 size += (ROUND_UP(dw->size, Csize)/HFS_BLOCKSZ);
2835 count++;
2836 }
2837
2838 /*
2839 * crude attempt to prevent overflows - HFS can only cope with a
2840 * maximum of about 65536 forks (actually less) - this will trap cases
2841 * when we have far too many files
2842 */
2843
2844 if (count >= 65536)
2845 return (-1);
2846 else
2847 return (size);
2848 }
2849
2850 /*
2851 * adj_size: adjust the ISO record entries for all files
2852 * based on the HFS allocation block size
2853 */
2854 EXPORT int
adj_size(Csize,start_extent,extra)2855 adj_size(Csize, start_extent, extra)
2856 int Csize;
2857 UInt32_t start_extent;
2858 int extra;
2859 {
2860 struct deferred_write *dw;
2861 struct directory_entry *s_entry;
2862 int size;
2863
2864 /* get the adjusted start_extent (with padding) */
2865 /* take in accout alignment of files wrt HFS volume start */
2866
2867 start_extent -= session_start;
2868
2869 start_extent = ROUND_UP(start_extent*SECTOR_SIZE + extra*HFS_BLOCKSZ,
2870 Csize) / SECTOR_SIZE;
2871
2872 start_extent -= (extra / HFS_BLK_CONV);
2873
2874 start_extent += session_start;
2875
2876 /* initialise file hash */
2877 flush_hash();
2878
2879 /*
2880 * loop through all files changing their starting blocks and finding
2881 * any padding needed to written out latter
2882 */
2883 for (dw = dw_head; dw; dw = dw->next) {
2884 s_entry = dw->s_entry;
2885 s_entry->starting_block = dw->extent = start_extent;
2886 set_733((char *)s_entry->isorec.extent, start_extent);
2887 size = ROUND_UP(dw->size, Csize) / SECTOR_SIZE;
2888 dw->pad = size - ISO_ROUND_UP(dw->size) / SECTOR_SIZE;
2889
2890 /*
2891 * cache non-HFS files - as there may be multiple links to
2892 * these files (HFS files can't have multiple links). We will
2893 * need to change the starting extent of the other links later
2894 */
2895 if (!s_entry->hfs_ent)
2896 add_hash(s_entry);
2897
2898 start_extent += size;
2899 }
2900
2901 return (start_extent);
2902 }
2903
2904 /*
2905 * adj_size_other: adjust any non-HFS files that may be linked
2906 * to an existing file (i.e. not have a deferred_write
2907 * entry of it's own
2908 */
2909 EXPORT void
adj_size_other(dpnt)2910 adj_size_other(dpnt)
2911 struct directory *dpnt;
2912 {
2913 struct directory_entry *s_entry;
2914 struct file_hash *s_hash;
2915
2916 while (dpnt) {
2917 s_entry = dpnt->contents;
2918 for (s_entry = dpnt->contents; s_entry;
2919 s_entry = s_entry->next) {
2920 /*
2921 * if it's an HFS file or a directory - then ignore
2922 * (we're after non-HFS files)
2923 */
2924 if (s_entry->hfs_ent ||
2925 (s_entry->isorec.flags[0] & ISO_DIRECTORY))
2926 continue;
2927
2928 /*
2929 * find any cached entry and assign new starting
2930 * extent
2931 */
2932 s_hash = find_hash(s_entry);
2933 if (s_hash) {
2934 set_733((char *)s_entry->isorec.extent,
2935 s_hash->starting_block);
2936 /* not vital - but tidy */
2937 s_entry->starting_block =
2938 s_hash->starting_block;
2939 }
2940 }
2941 if (dpnt->subdir) {
2942 adj_size_other(dpnt->subdir);
2943 }
2944 dpnt = dpnt->next;
2945 }
2946
2947 /* clear file hash */
2948 flush_hash();
2949 }
2950
2951 /*
2952 * hfs_hce_write: write out the HFS header stuff
2953 */
2954 LOCAL int
hfs_hce_write(outfile)2955 hfs_hce_write(outfile)
2956 FILE *outfile;
2957 {
2958 char buffer[SECTOR_SIZE];
2959 int n = 0;
2960 int r; /* HFS hdr output */
2961 int tot_size = hce->hfs_map_size + hce->hfs_hdr_size;
2962
2963 memset(buffer, 0, sizeof (buffer));
2964
2965 /*
2966 * hack time ... if the tot_size is greater than 32Kb then
2967 * it won't fit in the first 16 blank SECTORS (64 512 byte
2968 * blocks, as most of this is padding, we just truncate this
2969 * data to 64x4xHFS_BLOCKSZ ... hope this is OK ...
2970 */
2971
2972 if (tot_size > 64) tot_size = 64;
2973
2974 /* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */
2975 n = tot_size / HFS_BLK_CONV;
2976 r = tot_size % HFS_BLK_CONV;
2977
2978 /* write out HFS volume header info */
2979 xfwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, outfile, 0, FALSE);
2980
2981 /* fill up to a complete CD block */
2982 if (r) {
2983 xfwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, outfile, 0, FALSE);
2984 n++;
2985 }
2986 last_extent_written += n;
2987 return (0);
2988 }
2989
2990 /*
2991 * insert_padding_file : insert a dumy file to make volume at least
2992 * 800k
2993 *
2994 * XXX If we ever need to write more then 2 GB, make size off_t
2995 */
2996 EXPORT int
insert_padding_file(size)2997 insert_padding_file(size)
2998 int size;
2999 {
3000 struct deferred_write *dwpnt;
3001
3002 /* get the size in bytes */
3003 size *= HFS_BLOCKSZ;
3004
3005 dwpnt = (struct deferred_write *)
3006 e_malloc(sizeof (struct deferred_write));
3007 dwpnt->s_entry = 0;
3008 /* set the padding to zero */
3009 dwpnt->pad = 0;
3010 /* set offset to zero */
3011 dwpnt->off = (off_t)0;
3012 dwpnt->dw_flags = 0;
3013 #ifdef APPLE_HYB
3014 dwpnt->hfstype = TYPE_NONE;
3015 #endif
3016
3017 /*
3018 * don't need to wory about the s_entry stuff as it won't be touched#
3019 * at this point onwards
3020 */
3021
3022 /* insert the entry in the list */
3023 if (dw_tail) {
3024 dw_tail->next = dwpnt;
3025 dw_tail = dwpnt;
3026 } else {
3027 dw_head = dwpnt;
3028 dw_tail = dwpnt;
3029 }
3030
3031 /* aloocate memory as a "Table" file */
3032 dwpnt->table = e_malloc(size);
3033 dwpnt->name = NULL;
3034
3035 dwpnt->next = NULL;
3036 dwpnt->size = size;
3037 dwpnt->extent = last_extent;
3038 last_extent += ISO_BLOCKS(size);
3039
3040 /* retune the size in HFS blocks */
3041 return (ISO_ROUND_UP(size) / HFS_BLOCKSZ);
3042 }
3043
3044 struct output_fragment hfs_desc = {NULL, NULL, NULL, hfs_hce_write, "HFS volume header"};
3045
3046 #endif /* APPLE_HYB */
3047
3048 struct output_fragment startpad_desc = {NULL, startpad_size, NULL, startpad_write, "Initial Padblock"};
3049 struct output_fragment voldesc_desc = {NULL, oneblock_size, root_gen, pvd_write, "Primary Volume Descriptor"};
3050 struct output_fragment xvoldesc_desc = {NULL, oneblock_size, NULL, xpvd_write, "Enhanced Volume Descriptor"};
3051 struct output_fragment end_vol = {NULL, oneblock_size, NULL, evd_write, "End Volume Descriptor" };
3052 struct output_fragment version_desc = {NULL, oneblock_size, NULL, vers_write, "Version block" };
3053 struct output_fragment pathtable_desc = {NULL, pathtab_size, generate_path_tables, pathtab_write, "Path table"};
3054 struct output_fragment dirtree_desc = {NULL, dirtree_size, NULL, dirtree_write, "Directory tree" };
3055 struct output_fragment dirtree_clean = {NULL, dirtree_fixup, dirtree_dump, dirtree_cleanup, "Directory tree cleanup" };
3056 struct output_fragment extension_desc = {NULL, ext_size, NULL, exten_write, "Extension record" };
3057 struct output_fragment files_desc = {NULL, NULL, file_gen, file_write, "The File(s)"};
3058 struct output_fragment interpad_desc = {NULL, interpad_size, NULL, interpad_write, "Intermediate Padblock"};
3059 struct output_fragment endpad_desc = {NULL, endpad_size, NULL, endpad_write, "Ending Padblock"};
3060