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