1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 #define TITLE "cdpatch - CD-XA image insert/extract utility"
4 #define COPYR "Copyright (C) 2001,2011 Neill Corlett"
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include "common.h"
22 #include "banner.h"
23
24 ////////////////////////////////////////////////////////////////////////////////
25
26 static const uint32_t max_path_depth = 256;
27
28 ////////////////////////////////////////////////////////////////////////////////
29 //
30 // Program options
31 //
32 struct cdpatch_options {
33 int8_t insert;
34 int8_t extract;
35 const char* binname;
36 const char* basedir;
37 int8_t big;
38 int8_t little;
39 int8_t boot;
40 int8_t enforce_fscheck;
41 int8_t overwrite;
42 int8_t verbose;
43 int8_t recurse;
44 const char** files;
45 int files_count;
46 };
47
48 static const char* fsoverride = " (use -f to override)";
49
50 ////////////////////////////////////////////////////////////////////////////////
51
exists(const char * filename)52 static int exists(const char* filename) {
53 FILE* f = fopen(filename, "rb");
54 if(f) { fclose(f); return 1; }
55 return 0;
56 }
57
58 ////////////////////////////////////////////////////////////////////////////////
59
60 static const char* oom = "Error: Out of memory\n";
61
62 ////////////////////////////////////////////////////////////////////////////////
63
get32lsb(const uint8_t * p)64 static uint32_t get32lsb(const uint8_t* p) {
65 return
66 (((uint32_t)(p[0])) << 0) |
67 (((uint32_t)(p[1])) << 8) |
68 (((uint32_t)(p[2])) << 16) |
69 (((uint32_t)(p[3])) << 24);
70 }
71
get32msb(const uint8_t * p)72 static uint32_t get32msb(const uint8_t* p) {
73 return
74 (((uint32_t)(p[0])) << 24) |
75 (((uint32_t)(p[1])) << 16) |
76 (((uint32_t)(p[2])) << 8) |
77 (((uint32_t)(p[3])) << 0);
78 }
79
set32lsb(uint8_t * p,uint32_t value)80 static void set32lsb(uint8_t* p, uint32_t value) {
81 p[0] = (uint8_t)(value >> 0);
82 p[1] = (uint8_t)(value >> 8);
83 p[2] = (uint8_t)(value >> 16);
84 p[3] = (uint8_t)(value >> 24);
85 }
86
set32msb(uint8_t * p,uint32_t value)87 static void set32msb(uint8_t* p, uint32_t value) {
88 p[0] = (uint8_t)(value >> 24);
89 p[1] = (uint8_t)(value >> 16);
90 p[2] = (uint8_t)(value >> 8);
91 p[3] = (uint8_t)(value >> 0);
92 }
93
94 ////////////////////////////////////////////////////////////////////////////////
95 //
96 // Returns nonzero if any bytes in the array are nonzero
97 //
anynonzero(const uint8_t * data,size_t len)98 static int anynonzero(const uint8_t* data, size_t len) {
99 for(; len; len--) {
100 if(*data++) { return 1; }
101 }
102 return 0;
103 }
104
105 ////////////////////////////////////////////////////////////////////////////////
106 //
107 // Convert ISO9660 file size to sector count, rounding up
108 //
sectorcount(uint32_t size)109 static uint32_t sectorcount(uint32_t size) {
110 return (size >> 11) + ((size & 0x7FF) != 0);
111 }
112
113 ////////////////////////////////////////////////////////////////////////////////
114 //
115 // LUTs for computing ECC/EDC
116 //
117 static uint8_t ecc_f_lut[256];
118 static uint8_t ecc_b_lut[256];
119 static uint32_t edc_lut [256];
120
eccedc_init(void)121 static void eccedc_init(void) {
122 uint32_t i, j, edc;
123 for(i = 0; i < 256; i++) {
124 j = (i << 1) ^ (i & 0x80 ? 0x11D : 0);
125 ecc_f_lut[i ] = (uint8_t)j;
126 ecc_b_lut[i ^ j] = (uint8_t)i;
127 edc = i;
128 for(j = 0; j < 8; j++) {
129 edc = (edc >> 1) ^ (edc & 1 ? 0xD8018001 : 0);
130 }
131 edc_lut[i] = edc;
132 }
133 }
134
135 ////////////////////////////////////////////////////////////////////////////////
136 //
137 // Compute EDC for a block
138 //
edc_computeblock(const uint8_t * src,size_t size,uint8_t * dest)139 static void edc_computeblock(const uint8_t* src, size_t size, uint8_t* dest) {
140 uint32_t edc = 0;
141 while(size--) {
142 edc = (edc >> 8) ^ edc_lut[(edc ^ (*src++)) & 0xFF];
143 }
144 set32lsb(dest, edc);
145 }
146
147 ////////////////////////////////////////////////////////////////////////////////
148 //
149 // Compute ECC for a block (can do either P or Q)
150 //
ecc_computeblock(uint8_t * src,uint32_t major_count,uint32_t minor_count,uint32_t major_mult,uint32_t minor_inc,uint8_t * dest)151 static void ecc_computeblock(
152 uint8_t* src,
153 uint32_t major_count,
154 uint32_t minor_count,
155 uint32_t major_mult,
156 uint32_t minor_inc,
157 uint8_t* dest
158 ) {
159 uint32_t size = major_count * minor_count;
160 uint32_t major, minor;
161 for(major = 0; major < major_count; major++) {
162 uint32_t index = (major >> 1) * major_mult + (major & 1);
163 uint8_t ecc_a = 0;
164 uint8_t ecc_b = 0;
165 for(minor = 0; minor < minor_count; minor++) {
166 uint8_t temp = src[index];
167 index += minor_inc;
168 if(index >= size) index -= size;
169 ecc_a ^= temp;
170 ecc_b ^= temp;
171 ecc_a = ecc_f_lut[ecc_a];
172 }
173 ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
174 dest[major ] = ecc_a;
175 dest[major + major_count] = ecc_a ^ ecc_b;
176 }
177 }
178
179 //
180 // Generate ECC P and Q codes for a block
181 //
ecc_generate(uint8_t * sector,int zeroaddress)182 static void ecc_generate(uint8_t* sector, int zeroaddress) {
183 uint8_t saved_address[4];
184 //
185 // Save the address and zero it out, if necessary
186 //
187 if(zeroaddress) {
188 memmove(saved_address, sector + 12, 4);
189 memset(sector + 12, 0, 4);
190 }
191 //
192 // Compute ECC P code
193 //
194 ecc_computeblock(sector + 0xC, 86, 24, 2, 86, sector + 0x81C);
195 //
196 // Compute ECC Q code
197 //
198 ecc_computeblock(sector + 0xC, 52, 43, 86, 88, sector + 0x8C8);
199 //
200 // Restore the address, if necessary
201 //
202 if(zeroaddress) {
203 memmove(sector + 12, saved_address, 4);
204 }
205 }
206
207 ////////////////////////////////////////////////////////////////////////////////
208 //
209 // CD sync header
210 //
211 static const uint8_t sync_header[12] = {
212 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00
213 };
214
215 ////////////////////////////////////////////////////////////////////////////////
216 //
217 // Generate ECC/EDC information for a sector (must be 2352 = 0x930 bytes)
218 //
eccedc_generate(uint8_t * sector)219 static void eccedc_generate(uint8_t* sector) {
220 //
221 // Generate sync
222 //
223 memmove(sector, sync_header, sizeof(sync_header));
224 switch(sector[0x0F]) {
225 case 0x00:
226 //
227 // Mode 0: no data; generate zeroes
228 //
229 memset(sector + 0x10, 0, 0x920);
230 break;
231
232 case 0x01:
233 //
234 // Mode 1:
235 //
236 // Compute EDC
237 //
238 edc_computeblock(sector + 0x00, 0x810, sector + 0x810);
239 //
240 // Zero out reserved area
241 //
242 memset(sector + 0x814, 0, 8);
243 //
244 // Generate ECC P/Q codes
245 //
246 ecc_generate(sector, 0);
247 break;
248
249 case 0x02:
250 //
251 // Mode 2:
252 //
253 // Make sure XA flags match
254 //
255 memmove(sector + 0x14, sector + 0x10, 4);
256
257 if(!(sector[0x12] & 0x20)) {
258 //
259 // Form 1: Compute EDC
260 //
261 edc_computeblock(sector + 0x10, 0x808, sector + 0x818);
262 //
263 // Generate ECC P/Q codes
264 //
265 ecc_generate(sector, 1);
266
267 } else {
268 //
269 // Form 2: Compute EDC
270 //
271 edc_computeblock(sector + 0x10, 0x91C, sector + 0x92C);
272 }
273 break;
274 }
275 }
276
277 ////////////////////////////////////////////////////////////////////////////////
278 //
279 // Verify EDC for a sector (must be 2352 = 0x930 bytes)
280 // Returns 0 on success
281 //
edc_verify(const uint8_t * sector)282 static int edc_verify(const uint8_t* sector) {
283 uint8_t myedc[4];
284 //
285 // Verify sync
286 //
287 if(memcmp(sector, sync_header, sizeof(sync_header))) { return 1; }
288
289 switch(sector[0x0F]) {
290 case 0x00:
291 //
292 // Mode 0: no data; everything had better be zero
293 //
294 return anynonzero(sector + 0x10, 0x920);
295
296 case 0x01:
297 //
298 // Mode 1
299 //
300 edc_computeblock(sector + 0x00, 0x810, myedc);
301 return memcmp(myedc, sector + 0x810, 4);
302
303 case 0x02:
304 //
305 // Mode 2: Verify that the XA type is correctly copied twice
306 //
307 if(memcmp(sector + 0x10, sector + 0x14, 4)) { return 1; }
308
309 if(!(sector[0x12] & 0x20)) {
310 //
311 // Form 1
312 //
313 edc_computeblock(sector + 0x10, 0x808, myedc);
314 return memcmp(myedc, sector + 0x818, 4);
315
316 } else {
317 //
318 // Form 2
319 //
320 edc_computeblock(sector + 0x10, 0x91C, myedc);
321 return memcmp(myedc, sector + 0x92C, 4);
322 }
323 }
324 //
325 // Invalid mode
326 //
327 return 1;
328 }
329
330 ////////////////////////////////////////////////////////////////////////////////
331
332 struct cacheentry {
333 uint8_t* data;
334 uint32_t sector;
335 uint8_t valid;
336 };
337
338 enum { CACHE_ENTRIES = 4 };
339
340 enum {
341 BINTYPE_UNKNOWN = 0,
342 BINTYPE_2048 = 1,
343 BINTYPE_2352 = 2
344 };
345
346 struct binfile {
347 FILE* f;
348 const char* name;
349 int type;
350 uint32_t sectors;
351 struct cacheentry cache[CACHE_ENTRIES];
352 };
353
bin_quit(struct binfile * bin)354 static void bin_quit(struct binfile* bin) {
355 size_t i;
356 if(bin->f) { fclose(bin->f); }
357 for(i = 0; i < CACHE_ENTRIES; i++) {
358 if(bin->cache[i].data) { free(bin->cache[i].data); }
359 }
360 }
361
bin_init(struct binfile * bin)362 static int bin_init(struct binfile* bin) {
363 size_t i;
364 memset(bin, 0, sizeof(struct binfile));
365 for(i = 0; i < CACHE_ENTRIES; i++) {
366 bin->cache[i].data = malloc(2352);
367 if(!bin->cache[i].data) {
368 printf("%s", oom);
369 bin_quit(bin);
370 return 1;
371 }
372 }
373 return 0;
374 }
375
cache_mtf(struct binfile * bin,size_t entry)376 static void cache_mtf(struct binfile* bin, size_t entry) {
377 if(entry) {
378 struct cacheentry tmp = bin->cache[entry];
379 memmove(bin->cache + 1, bin->cache, sizeof(struct cacheentry) * entry);
380 bin->cache[0] = tmp;
381 }
382 }
383
cache_find(struct binfile * bin,uint32_t sector)384 static uint8_t* cache_find(struct binfile* bin, uint32_t sector) {
385 size_t i;
386 for(i = 0; i < CACHE_ENTRIES; i++) {
387 if((bin->cache[i].sector == sector) && bin->cache[i].valid) {
388 cache_mtf(bin, i);
389 return bin->cache[0].data;
390 }
391 }
392 return NULL;
393 }
394
cache_allocbegin(struct binfile * bin,uint32_t sector)395 static uint8_t* cache_allocbegin(struct binfile* bin, uint32_t sector) {
396 bin->cache[CACHE_ENTRIES - 1].valid = 0;
397 bin->cache[CACHE_ENTRIES - 1].sector = sector;
398 return bin->cache[CACHE_ENTRIES - 1].data;
399 }
400
cache_allocend(struct binfile * bin)401 static void cache_allocend(struct binfile* bin) {
402 cache_mtf(bin, CACHE_ENTRIES - 1);
403 bin->cache[0].valid = 1;
404 }
405
406 ////////////////////////////////////////////////////////////////////////////////
407 //
408 // Detect whether image is ISO or BIN
409 // Returns nonzero on error
410 //
bintype_detect(struct binfile * bin)411 static int bintype_detect(struct binfile* bin) {
412 uint8_t* sector = NULL;
413 off_t size;
414
415 bin->type = BINTYPE_UNKNOWN;
416
417 if(fseeko(bin->f, 0, SEEK_END) != 0) { goto error_bin; }
418 size = ftello(bin->f);
419 if(size == -1) { goto error_bin; }
420 if(fseeko(bin->f, 0, SEEK_SET) != 0) { goto error_bin; }
421
422 if(size <= 0 || ((size % 2352) != 0 && (size % 2048) != 0)) {
423 //
424 // Size is zero or not cleanly divisible
425 //
426 printf("Error: %s: Unable to determine BIN or ISO format based on size\n",
427 bin->name
428 );
429 goto error;
430
431 } else if((size % 2352) != 0) {
432 //
433 // If indivisible by 2352, assume ISO
434 //
435 bin->type = BINTYPE_2048;
436
437 } else if((size % 2048) != 0) {
438 //
439 // If indivisible by 2048, assume BIN
440 //
441 bin->type = BINTYPE_2352;
442
443 } else {
444 //
445 // If divisible by both, read the first 2352 bytes and see if it's a
446 // valid raw sector. If so, assume BIN.
447 //
448 sector = malloc(2352);
449 if(!sector) { goto error_mem; }
450
451 if(fread(sector, 1, 2352, bin->f) != 2352) { goto error_bin; }
452 bin->type = edc_verify(sector) ? BINTYPE_2048 : BINTYPE_2352;
453 }
454
455 //
456 // Figure out the number of sectors
457 //
458 { off_t sectorsize = (bin->type == BINTYPE_2048) ? 2048 : 2352;
459 bin->sectors =
460 (sizeof(off_t) > 4) ? (
461 ((((off_t)(size / sectorsize)) >> 31) > 1) ?
462 ((uint32_t)(0xFFFFFFFFLU)) :
463 ((uint32_t)(size / sectorsize))
464 ) : (((uint32_t)size) / ((uint32_t)sectorsize));
465 }
466
467 goto done;
468
469 error_mem:
470 printf("%s", oom);
471 goto error;
472 error_bin:
473 printfileerror(bin->f, bin->name);
474 goto error;
475 error:
476 bin->type = BINTYPE_UNKNOWN;
477 goto done;
478 done:
479 if(sector) { free(sector); }
480 return (bin->type == BINTYPE_UNKNOWN);
481 }
482
483 ////////////////////////////////////////////////////////////////////////////////
484 //
485 // Ensure that the sector number is within the seekable range for the bin file;
486 // returns nonzero on error
487 //
check_bin_sector_range(const struct binfile * bin,uint32_t sector)488 int check_bin_sector_range(const struct binfile* bin, uint32_t sector) {
489 if(sector >= bin->sectors) {
490 printf("Error: Sector %lu is out of range\n", (unsigned long)sector);
491 return 1;
492 }
493 return 0;
494 }
495
496 ////////////////////////////////////////////////////////////////////////////////
497 //
498 // Returns NULL on failure
499 // The returned buffer is valid until the next call
500 //
read_raw_sector(struct binfile * bin,uint32_t sector)501 static uint8_t* read_raw_sector(struct binfile* bin, uint32_t sector) {
502 uint8_t* data = NULL;
503
504 if(check_bin_sector_range(bin, sector)) { goto error; }
505
506 if(bin->type != BINTYPE_2352) {
507 printf("Error: Tried to read raw sector from ISO\n");
508 goto error;
509 }
510
511 data = cache_find(bin, sector);
512 if(!data) {
513 data = cache_allocbegin(bin, sector);
514 if(fseeko(bin->f, 2352 * ((off_t)sector), SEEK_SET) != 0) {
515 goto error_f;
516 }
517 if(fread(data, 1, 2352, bin->f) != 2352) { goto error_f; }
518 cache_allocend(bin);
519 }
520 return data;
521
522 error_f:
523 printf("At sector %lu: ", (unsigned long)sector);
524 printfileerror(bin->f, bin->name);
525 goto error;
526 error:
527 return NULL;
528 }
529
530 ////////////////////////////////////////////////////////////////////////////////
531 //
532 // Returns NULL on failure
533 // The returned buffer is valid until the next call
534 //
read_cooked_sector(struct binfile * bin,uint32_t sector,const struct cdpatch_options * opt)535 static uint8_t* read_cooked_sector(
536 struct binfile* bin,
537 uint32_t sector,
538 const struct cdpatch_options* opt
539 ) {
540 uint8_t* data = NULL;
541
542 if(check_bin_sector_range(bin, sector)) { goto error; }
543
544 data = cache_find(bin, sector);
545 if(!data) {
546 data = cache_allocbegin(bin, sector);
547 if(bin->type == BINTYPE_2048) {
548 if(fseeko(bin->f, 2048 * ((off_t)sector), SEEK_SET) != 0) {
549 goto error_f;
550 }
551 if(fread(data, 1, 2048, bin->f) != 2048) { goto error_f; }
552 } else {
553 if(fseeko(bin->f, 2352 * ((off_t)sector), SEEK_SET) != 0) {
554 goto error_f;
555 }
556 if(fread(data, 1, 2352, bin->f) != 2352) { goto error_f; }
557 //
558 // Verify the EDC
559 //
560 if(edc_verify(data)) {
561 if(opt->enforce_fscheck || opt->verbose) {
562 printf("%s: CD sector %lu is corrupt%s\n",
563 opt->enforce_fscheck ? "Error" : "Warning",
564 (unsigned long)sector,
565 opt->enforce_fscheck ? fsoverride : ""
566 );
567 }
568 if(opt->enforce_fscheck) { goto error; }
569 }
570 }
571 cache_allocend(bin);
572 }
573
574 if(bin->type == BINTYPE_2352) {
575 //
576 // Figure out where the data actually resides in the sector
577 //
578 switch(data[0xF]) {
579 case 1:
580 data += 0x10;
581 break;
582 case 2:
583 if(data[0x12] & 0x20) {
584 if(opt->enforce_fscheck || opt->verbose) {
585 printf("%s: Attempted to read Form 2 sector %lu%s\n",
586 opt->enforce_fscheck ? "Error" : "Warning",
587 (unsigned long)sector,
588 opt->enforce_fscheck ? fsoverride : ""
589 );
590 }
591 if(opt->enforce_fscheck) { goto error; }
592 }
593 data += 0x18;
594 break;
595 default:
596 if(opt->enforce_fscheck || opt->verbose) {
597 printf("%s: Invalid mode 0x%02X at sector %lu%s\n",
598 opt->enforce_fscheck ? "Error" : "Warning",
599 (int)data[0xF], (unsigned long)sector,
600 opt->enforce_fscheck ? fsoverride : ""
601 );
602 if(opt->enforce_fscheck) { goto error; }
603 }
604 data += 0x10; // assume mode 1
605 break;
606 }
607 }
608
609 return data;
610
611 error_f:
612 printf("At sector %lu: ", (unsigned long)sector);
613 printfileerror(bin->f, bin->name);
614 goto error;
615 error:
616 return NULL;
617 }
618
619 ////////////////////////////////////////////////////////////////////////////////
620 //
621 // Allocate space for a cooked sector, with the understanding that we will
622 // overwrite all of it
623 //
624 // Returns NULL on failure
625 // The returned buffer is valid until the next call
626 //
alloc_cooked_sector(struct binfile * bin,uint32_t sector,const struct cdpatch_options * opt)627 static uint8_t* alloc_cooked_sector(
628 struct binfile* bin,
629 uint32_t sector,
630 const struct cdpatch_options* opt
631 ) {
632 if(bin->type == BINTYPE_2048) {
633 uint8_t* data;
634 if(check_bin_sector_range(bin, sector)) { return NULL; }
635 //
636 // Just allocate space and not initialize it
637 //
638 data = cache_find(bin, sector);
639 if(!data) {
640 data = cache_allocbegin(bin, sector);
641 cache_allocend(bin);
642 }
643 return data;
644 } else {
645 //
646 // We need to read the sector anyway, so just read it
647 //
648 return read_cooked_sector(bin, sector, opt);
649 }
650 }
651
652 ////////////////////////////////////////////////////////////////////////////////
653 //
654 // Returns 0 on success
655 //
writeback_raw_sector(struct binfile * bin,uint32_t sector)656 static int writeback_raw_sector(struct binfile* bin, uint32_t sector) {
657 int returncode = 0;
658 const uint8_t* data;
659
660 if(check_bin_sector_range(bin, sector)) { goto error; }
661
662 if(bin->type != BINTYPE_2352) {
663 printf("Error: Tried to write raw sector to ISO\n");
664 goto error;
665 }
666
667 data = cache_find(bin, sector);
668 if(!data) {
669 printf("Error: Sector not in cache\n");
670 goto error;
671 }
672
673 //
674 // Seek and write
675 //
676 if(fseeko(bin->f, 2352 * ((off_t)sector), SEEK_SET) != 0) { goto error_f; }
677 if(fwrite(data, 1, 2352, bin->f) != 2352) { goto error_f; }
678 fflush(bin->f);
679
680 goto done;
681
682 error_f:
683 printf("At sector %lu: ", (unsigned long)sector);
684 printfileerror(bin->f, bin->name);
685 goto error;
686 error:
687 returncode = 1;
688 goto done;
689 done:
690 return returncode;
691 }
692
693 ////////////////////////////////////////////////////////////////////////////////
694 //
695 // Returns 0 on success
696 //
writeback_cooked_sector(struct binfile * bin,uint32_t sector,int redoflags,int last)697 static int writeback_cooked_sector(
698 struct binfile* bin,
699 uint32_t sector,
700 int redoflags,
701 int last
702 ) {
703 int returncode = 0;
704 uint8_t* data;
705
706 if(check_bin_sector_range(bin, sector)) { goto error; }
707
708 data = cache_find(bin, sector);
709 if(!data) {
710 printf("Error: Sector not in cache\n");
711 goto error;
712 }
713
714 if(bin->type == BINTYPE_2048) {
715 //
716 // If this is an ISO file, just seek and write directly
717 //
718 if(fseeko(bin->f, 2048 * ((off_t)sector), SEEK_SET) != 0) { goto error_f; }
719 if(fwrite(data, 1, 2048, bin->f) != 2048) { goto error_f; }
720
721 } else {
722 //
723 // If mode 2, and we care about the XA flags, set those up
724 //
725 if(redoflags && (data[0xF] == 2)) {
726 data[0x10] = data[0x14] = 0;
727 data[0x11] = data[0x15] = 0;
728 data[0x12] = data[0x16] = 0x08 | (last ? 0x81 : 0x00);
729 data[0x13] = data[0x17] = 0;
730 }
731 //
732 // Regenerate ECC/EDC
733 //
734 eccedc_generate(data);
735 //
736 // Seek and write
737 //
738 if(fseeko(bin->f, 2352 * ((off_t)sector), SEEK_SET) != 0) { goto error_f; }
739 if(fwrite(data, 1, 2352, bin->f) != 2352) { goto error_f; }
740
741 }
742
743 fflush(bin->f);
744 goto done;
745
746 error_f:
747 printf("At sector %lu: ", (unsigned long)sector);
748 printfileerror(bin->f, bin->name);
749 goto error;
750 error:
751 returncode = 1;
752 goto done;
753 done:
754 return returncode;
755 }
756
757 ////////////////////////////////////////////////////////////////////////////////
758 //
759 // Read or write arbitrary cooked data; returns nonzero on error
760 //
rw_cooked_data(struct binfile * bin,uint32_t sector,uint32_t offset,uint8_t * data,size_t size,const struct cdpatch_options * opt,int write)761 static int rw_cooked_data(
762 struct binfile* bin,
763 uint32_t sector,
764 uint32_t offset,
765 uint8_t* data,
766 size_t size,
767 const struct cdpatch_options* opt,
768 int write
769 ) {
770 int returncode = 0;
771 //
772 // Normalize sector/offset, and verify the range
773 //
774 if((offset >> 11) > (0xFFFFFFFFLU - sector)) { goto error_range; }
775 sector += offset >> 11;
776 offset &= 0x7FF;
777 if(check_bin_sector_range(bin, sector)) { goto error; }
778
779 if(bin->type == BINTYPE_2048) {
780 //
781 // Read or write the image file directly
782 //
783 if(fseeko(
784 bin->f, 2048 * ((off_t)sector) + ((off_t)offset), SEEK_SET
785 ) != 0) { goto error_f; }
786 if(write) {
787 if(fwrite(data, 1, size, bin->f) != size) { goto error_f; }
788 } else {
789 if(fread (data, 1, size, bin->f) != size) { goto error_f; }
790 }
791 } else {
792 //
793 // Read or write sector-by-sector
794 //
795 for(; size; sector++) {
796 size_t insector = 0x800 - offset;
797 size_t z = size < insector ? size : insector;
798 uint8_t* d = read_cooked_sector(bin, sector, opt);
799 if(!d) { goto error; }
800 if(write) {
801 memmove(d + offset, data, z);
802 if(writeback_cooked_sector(bin, sector, 0, 0)) { goto error; }
803 } else {
804 memmove(data, d + offset, z);
805 }
806 data += z;
807 size -= z;
808 offset = 0;
809 if(size && (sector == 0xFFFFFFFFLU)) { goto error_range; }
810 }
811 }
812 goto done;
813
814 error_f:
815 printf("At sector %lu: ", (unsigned long)sector);
816 printfileerror(bin->f, bin->name);
817 goto error;
818 error_range:
819 printf("Error: %s out of range: sector=%lu offset=%lu\n",
820 write ? "Write" : "Read", (unsigned long)sector, (unsigned long)offset
821 );
822 goto error;
823 error:
824 returncode = 1;
825 done:
826 return returncode;
827 }
828
read_cooked_data(struct binfile * bin,uint32_t sector,uint32_t offset,uint8_t * data,size_t size,const struct cdpatch_options * opt)829 static int read_cooked_data(
830 struct binfile* bin,
831 uint32_t sector,
832 uint32_t offset,
833 uint8_t* data,
834 size_t size,
835 const struct cdpatch_options* opt
836 ) {
837 return rw_cooked_data(bin, sector, offset, data, size, opt, 0);
838 }
839
write_cooked_data(struct binfile * bin,uint32_t sector,uint32_t offset,const uint8_t * data,size_t size,const struct cdpatch_options * opt)840 static int write_cooked_data(
841 struct binfile* bin,
842 uint32_t sector,
843 uint32_t offset,
844 const uint8_t* data,
845 size_t size,
846 const struct cdpatch_options* opt
847 ) {
848 return rw_cooked_data(bin, sector, offset, (uint8_t*)data, size, opt, 1);
849 }
850
851 ////////////////////////////////////////////////////////////////////////////////
852 //
853 // Use RIFF if:
854 // - The sector is mode 0, or invalid
855 // - The sector is mode 2 and any of the flag bits besides 'data', 'last sector
856 // of data record', or 'last sector of file' are set.
857 //
should_use_riff_format(const uint8_t * sector)858 static int should_use_riff_format(const uint8_t* sector) {
859 if(sector[0xF] == 1) { return 0; }
860 if(sector[0xF] == 2) {
861 return
862 ( sector[0x10] != 0) ||
863 ( sector[0x11] != 0) ||
864 ((sector[0x12] & 0x76) != 0) ||
865 ( sector[0x13] != 0);
866 }
867 return 1;
868 }
869
870 ////////////////////////////////////////////////////////////////////////////////
871 //
872 // Returns nonzero on error
873 //
extract_file(struct binfile * bin,uint32_t sector,uint32_t filesize,time_t modtime,const char * filename,const struct cdpatch_options * opt)874 static int extract_file(
875 struct binfile* bin,
876 uint32_t sector,
877 uint32_t filesize,
878 time_t modtime,
879 const char* filename,
880 const struct cdpatch_options* opt
881 ) {
882 int returncode = 0;
883 FILE* f = NULL;
884 uint8_t* data = NULL;
885
886 if(!opt->overwrite && exists(filename)) {
887 printf("Error: %s already exists (use -o to override)\n", filename);
888 goto error;
889 }
890 f = fopen(filename, "wb");
891 if(!f) { goto error_f; }
892
893 //
894 // Check for RIFF format
895 //
896 if(bin->type == BINTYPE_2352) {
897 data = read_raw_sector(bin, sector);
898 if(!data) { goto error; }
899 }
900 if(data && should_use_riff_format(data)) {
901 //
902 // Extract in RIFF format
903 //
904 uint32_t sectors = sectorcount(filesize);
905 if(sectors > 1826091LU) {
906 sectors = 1826091LU; // Exceeds uint32_t - just cap it
907 }
908 if(opt->verbose) {
909 printf(
910 "Extract %7lu %10lu %s (CDXA)\n",
911 (unsigned long)sector,
912 (unsigned long)(2352 * sectors + 0x2C),
913 filename
914 );
915 }
916 //
917 // Write header
918 //
919 { uint8_t hdr[0x2C];
920 memset(hdr, 0, sizeof(hdr));
921 memmove (hdr + 0x00, "RIFF", 4);
922 set32lsb(hdr + 0x04, 2352 * sectors + 0x2C);
923 memmove (hdr + 0x08, "CDXA", 4);
924 set32lsb(hdr + 0x0C, 2352 * sectors);
925 if(fwrite(hdr, 1, 0x2C, f) != 0x2C) { goto error_f; }
926 }
927 //
928 // Write contents
929 //
930 for(; sectors; sector++, sectors--) {
931 data = read_raw_sector(bin, sector);
932 if(!data) { goto error; }
933 if(edc_verify(data)) {
934 if(opt->enforce_fscheck || opt->verbose) {
935 printf("%s: %s: CD sector %lu is corrupt%s\n",
936 opt->enforce_fscheck ? "Error" : "Warning",
937 filename, (unsigned long)sector,
938 opt->enforce_fscheck ? fsoverride : ""
939 );
940 }
941 if(opt->enforce_fscheck) { goto error; }
942 }
943 if(fwrite(data, 1, 2352, f) != 2352) { goto error_f; }
944 }
945 } else {
946 if(opt->verbose) {
947 printf(
948 "Extract %7lu %10lu %s\n",
949 (unsigned long)sector,
950 (unsigned long)filesize,
951 filename
952 );
953 }
954 //
955 // Extract normally
956 //
957 for(; filesize; sector++) {
958 size_t remain = filesize < 2048 ? filesize : 2048;
959 data = read_cooked_sector(bin, sector, opt);
960 if(!data) { goto error; }
961 if(fwrite(data, 1, remain, f) != remain) { goto error_f; }
962 filesize -= remain;
963 }
964 }
965 if(f) { fclose(f); f = NULL; }
966
967 //
968 // Set modification time, if it was valid
969 //
970 if(modtime != ((time_t)(-1))) {
971 struct utimbuf b;
972 b.actime = modtime;
973 b.modtime = modtime;
974 if(utime((char*)filename, &b) != 0) {
975 // Silently fail - preserving modtime shouldn't be considered critical
976 }
977 }
978
979 goto done;
980
981 error_f:
982 printfileerror(f, filename);
983 goto error;
984 error:
985 returncode = 1;
986 goto done;
987 done:
988 if(f) { fclose(f); }
989 return returncode;
990 }
991
992 ////////////////////////////////////////////////////////////////////////////////
993 //
994 // Returns nonzero on error
995 // Outputs the new size in *filesize
996 //
insert_file(struct binfile * bin,uint32_t sector,uint32_t * filesize,const char * filename,const struct cdpatch_options * opt)997 static int insert_file(
998 struct binfile* bin,
999 uint32_t sector,
1000 uint32_t* filesize,
1001 const char* filename,
1002 const struct cdpatch_options* opt
1003 ) {
1004 int returncode = 0;
1005 uint8_t* data = NULL;
1006 FILE* f = NULL;
1007 uint32_t newfilesize;
1008 uint32_t sectors = sectorcount(*filesize);
1009
1010 f = fopen(filename, "rb");
1011 if(!f) { goto error_f; }
1012
1013 //
1014 // Get the replacement file size
1015 //
1016 { off_t size;
1017 if(fseeko(f, 0, SEEK_END) != 0) { goto error_f; }
1018 size = ftello(f);
1019 if(size == -1) { goto error_f; }
1020 if(fseeko(f, 0, SEEK_SET) != 0) { goto error_f; }
1021 // Verify size is not out of uint32_t range
1022 if(sizeof(size) > 4 && (size >> 31) > 1) {
1023 printf("Error: %s: Too large for ISO9660 (> 4GiB)\n", filename);
1024 goto error;
1025 }
1026 newfilesize = (uint32_t)size;
1027 }
1028
1029 //
1030 // Check for RIFF format
1031 //
1032 if(bin->type == BINTYPE_2352) {
1033 data = read_raw_sector(bin, sector);
1034 if(!data) { goto error; }
1035 }
1036 if(data && should_use_riff_format(data)) {
1037 //
1038 // Insert in RIFF format
1039 //
1040 if(sectors > 1826091LU) {
1041 sectors = 1826091LU; // Exceeds uint32_t - just cap it
1042 }
1043 if(opt->verbose) {
1044 printf(
1045 "Insert %7lu %10lu %s (CDXA)\n",
1046 (unsigned long)sector,
1047 (unsigned long)newfilesize,
1048 filename
1049 );
1050 }
1051 if(
1052 (newfilesize < 0x2C) ||
1053 ((newfilesize - 0x2C) % 2352) != 0
1054 ) {
1055 printf("Error: %s: CDXA file has invalid size\n", filename);
1056 goto error;
1057 }
1058 //
1059 // Make sure we're not expanding the file, at all
1060 //
1061 if(newfilesize > (2352 * sectors + 0x2C)) {
1062 printf("Error: %s: Cannot expand CDXA data beyond %lu bytes\n",
1063 filename, (unsigned long)(2352 * sectors)
1064 );
1065 goto error;
1066 }
1067 //
1068 // Read and verify header
1069 //
1070 { uint8_t hdr[0x2C];
1071 if(fread(hdr, 1, 0x2C, f) != 0x2C) { goto error_f; }
1072 if(
1073 memcmp(hdr + 0x00, "RIFF", 4) ||
1074 memcmp(hdr + 0x08, "CDXA", 4) ||
1075 anynonzero(hdr + 0x10, 0x1C)
1076 ) {
1077 printf("Error: %s: RIFF header is invalid\n", filename);
1078 goto error;
1079 }
1080 if(
1081 get32lsb(hdr + 0x04) != (newfilesize ) ||
1082 get32lsb(hdr + 0x0C) != (newfilesize - 0x2C)
1083 ) {
1084 printf("Error: %s: RIFF header mismatches actual file size\n",
1085 filename
1086 );
1087 goto error;
1088 }
1089 }
1090 //
1091 // Read contents
1092 //
1093 newfilesize -= 0x2C;
1094 *filesize = (newfilesize / 2352) * 2048;
1095 for(; newfilesize >= 2352; sector++) {
1096 data = read_raw_sector(bin, sector);
1097 if(!data) { goto error; }
1098
1099 // Ignore sync and address
1100 if(fread(data + 0x00F, 1, 0x00F, f) != 0x00F) { goto error_f; }
1101 // Read mode and everything else
1102 if(fread(data + 0x00F, 1, 0x921, f) != 0x921) { goto error_f; }
1103 // Regenerate sync and ECC/EDC
1104 memmove(data, sync_header, sizeof(sync_header));
1105 eccedc_generate(data);
1106
1107 if(writeback_raw_sector(bin, sector)) { goto error; }
1108 newfilesize -= 2352;
1109 }
1110
1111 } else {
1112 //
1113 // Make sure we're not expanding the file too much
1114 //
1115 uint32_t bytelimit = (sectors >= 0x200000LU) ?
1116 ((uint32_t)(0xFFFFFFFFLU)) :
1117 ((uint32_t)(sectors << 11));
1118 if(newfilesize > bytelimit) {
1119 printf("Error: %s: Cannot expand file beyond %lu bytes\n",
1120 filename, (unsigned long)bytelimit
1121 );
1122 goto error;
1123 }
1124 if(opt->verbose) {
1125 printf(
1126 "Insert %7lu %10lu %s\n",
1127 (unsigned long)sector,
1128 (unsigned long)newfilesize,
1129 filename
1130 );
1131 }
1132 //
1133 // Insert normally
1134 //
1135 *filesize = newfilesize;
1136 for(; newfilesize; sector++) {
1137 size_t remain = newfilesize < 2048 ? newfilesize : 2048;
1138
1139 data = alloc_cooked_sector(bin, sector, opt);
1140 if(!data) { goto error; }
1141
1142 if(fread(data, 1, remain, f) != remain) { goto error_f; }
1143 if(remain < 2048) { memset(data + remain, 0, 2048 - remain); }
1144
1145 if(writeback_cooked_sector(bin, sector, 1, newfilesize <= 2048)) {
1146 goto error;
1147 }
1148 newfilesize -= remain;
1149 }
1150 }
1151
1152 goto done;
1153
1154 error_f:
1155 printfileerror(f, filename);
1156 goto error;
1157 error:
1158 returncode = 1;
1159 goto done;
1160 done:
1161 if(f) { fclose(f); }
1162 return returncode;
1163 }
1164
1165 ////////////////////////////////////////////////////////////////////////////////
1166 //
1167 // ISO9660 data structure offsets
1168 //
1169 enum {
1170 PD_type = 0,
1171 PD_id = 1,
1172 PD_version = 6,
1173 PD_unused1 = 7,
1174 PD_system_id = 8,
1175 PD_volume_id = 40,
1176 PD_unused2 = 72,
1177 PD_volume_space_size = 80,
1178 PD_unused3 = 88,
1179 PD_volume_set_size = 120,
1180 PD_volume_sequence_number = 124,
1181 PD_logical_block_size = 128,
1182 PD_path_table_size = 132,
1183 PD_type_l_path_table = 140,
1184 PD_opt_type_l_path_table = 144,
1185 PD_type_m_path_table = 148,
1186 PD_opt_type_m_path_table = 152,
1187 PD_root_dir_record = 156,
1188 PD_volume_set_id = 190,
1189 PD_publisher_id = 318,
1190 PD_preparer_id = 446,
1191 PD_application_id = 574,
1192 PD_copyright_file_id = 702,
1193 PD_abstract_file_id = 739,
1194 PD_bibliographic_file_id = 776,
1195 PD_creation_date = 813,
1196 PD_modification_date = 830,
1197 PD_expiration_date = 847,
1198 PD_effective_date = 864,
1199 PD_file_structure_version = 881,
1200 PD_unused4 = 882,
1201 PD_application_data = 883,
1202 PD_unused5 = 1395
1203 };
1204
1205 enum {
1206 DR_length = 0,
1207 DR_ext_attr_length = 1,
1208 DR_extent = 2,
1209 DR_size = 10,
1210 DR_date = 18,
1211 DR_flags = 25,
1212 DR_file_unit_size = 26,
1213 DR_interleave = 27,
1214 DR_volume_sequence_number = 28,
1215 DR_name_len = 32,
1216 DR_name = 33
1217 };
1218
1219 ////////////////////////////////////////////////////////////////////////////////
1220
printsafestring(const uint8_t * src,size_t size)1221 static void printsafestring(const uint8_t* src, size_t size) {
1222 size_t i;
1223 for(i = 0; i < size; i++) {
1224 int c = src[i];
1225 if(!c) { break; }
1226 if(isprint(c)) {
1227 fputc(c, stdout);
1228 }
1229 }
1230 }
1231
1232 ////////////////////////////////////////////////////////////////////////////////
1233 //
1234 // Node: Info about a ISO9660 directory or file
1235 //
1236 struct node {
1237 //
1238 // Location of the ISO DR representing this node
1239 //
1240 uint32_t dr_sector;
1241 uint32_t dr_ofs;
1242 //
1243 // Info copied from the ISO DR
1244 //
1245 uint8_t name[256];
1246 int8_t isdir;
1247 uint32_t sector;
1248 uint32_t size;
1249 time_t modtime;
1250 //
1251 // Internal data
1252 //
1253 uint32_t depth;
1254 struct node* up;
1255 //
1256 // Current state, if this is a directory and we're reading it
1257 //
1258 uint32_t dirread;
1259 };
1260
rewindnode(struct node * n)1261 static void rewindnode(struct node* n) { n->dirread = 0; }
1262
freesubnodes(struct node * n,struct node * root)1263 static void freesubnodes(struct node* n, struct node* root) {
1264 while(n && n != root) {
1265 struct node* up = n->up;
1266 free(n);
1267 n = up;
1268 }
1269 }
1270
printnodename(struct node * n)1271 static void printnodename(struct node* n) {
1272 struct node* prev = NULL;
1273 //
1274 // Special case root directory
1275 //
1276 if(n && !n->up) {
1277 printf("/");
1278 } else {
1279 int num = 0;
1280 //
1281 // Momentarily reverse node order
1282 //
1283 while(n) {
1284 struct node* up = n->up;
1285 n->up = prev;
1286 prev = n;
1287 n = up;
1288 }
1289 n = prev;
1290 prev = NULL;
1291 //
1292 // Reverse node order again while printing names
1293 //
1294 while(n) {
1295 struct node* up = n->up;
1296 n->up = prev;
1297 if(strcmp((const char*)(n->name), ".")) {
1298 if(num++) { printf("/"); }
1299 printsafestring(n->name, strlen((const char*)(n->name)));
1300 }
1301 prev = n;
1302 n = up;
1303 }
1304 }
1305 }
1306
nodenamelen(const struct node * n)1307 static size_t nodenamelen(const struct node* n) {
1308 size_t len = 0;
1309 for(; n && n->up; n = n->up) {
1310 len += strlen((const char*)(n->name));
1311 if(n->up->up) {
1312 len++; // directory separator
1313 }
1314 }
1315 return len;
1316 }
1317
copynodename(char * end,const struct node * n)1318 static void copynodename(char* end, const struct node* n) {
1319 for(; n && n->up; n = n->up) {
1320 size_t len = strlen((const char*)(n->name));
1321 memmove(end - len, n->name, len);
1322 end -= len;
1323 if(n->up->up) {
1324 *(--end) = '/';
1325 }
1326 }
1327 }
1328
1329 ////////////////////////////////////////////////////////////////////////////////
1330 //
1331 // Read an ISO9660 directory record
1332 //
1333 // Returns the number of bytes in the record, 0 on end, or -1 on error
1334 //
read_iso_dr(struct binfile * bin,struct node * n,uint32_t sector,uint32_t ofs,uint32_t size,const struct cdpatch_options * opt)1335 static int read_iso_dr(
1336 struct binfile* bin,
1337 struct node* n,
1338 uint32_t sector,
1339 uint32_t ofs,
1340 uint32_t size,
1341 const struct cdpatch_options* opt
1342 ) {
1343 uint8_t dr[256];
1344 uint32_t little;
1345 uint32_t big;
1346 size_t i, namelen;
1347
1348 n->dr_sector = sector;
1349 n->dr_ofs = ofs;
1350 n->name[0] = 0;
1351 n->isdir = 0;
1352 n->sector = 0;
1353 n->size = 0;
1354 n->modtime = (time_t)(-1);
1355 rewindnode(n);
1356
1357 if(ofs >= size) { return 0; }
1358 //
1359 // Read DR length
1360 //
1361 if(read_cooked_data(bin, sector, ofs, dr, 1, opt)) { return -1; }
1362 if(dr[DR_length] == 0) { return 0; }
1363 if(dr[DR_length] > (size - ofs)) {
1364 dr[DR_length] = (uint8_t)(size - ofs);
1365 goto malformed;
1366 }
1367 if(dr[DR_length] < DR_name) { goto malformed; }
1368 //
1369 // Read DR
1370 //
1371 if(read_cooked_data(bin, sector, ofs+1, dr+1, dr[DR_length]-1, opt)) {
1372 return -1;
1373 }
1374 if(dr[DR_name_len] > (dr[DR_length] - DR_name)) { goto malformed; }
1375 if(dr[DR_name_len] == 0) { goto malformed; }
1376 namelen = dr[DR_name_len];
1377
1378 //
1379 // Get name (but don't normalize yet)
1380 //
1381 memmove(n->name, dr + DR_name, namelen);
1382 n->name[namelen] = 0;
1383 //
1384 // Get directory flag
1385 //
1386 n->isdir = (dr[DR_flags] & 0x02) != 0;
1387
1388 //
1389 // Normalize name, checking it for errors in the process
1390 //
1391 if(namelen == 1 && n->name[0] == 0) {
1392 n->name[0] = '.';
1393 } else if(namelen == 1 && n->name[0] == 1) {
1394 n->name[0] = '.';
1395 n->name[1] = '.';
1396 n->name[2] = 0;
1397 namelen = 2;
1398 } else {
1399 for(i = 0; i < namelen; i++) {
1400 uint8_t c = n->name[i];
1401 if(
1402 (c >= 'a' && c <= 'z') ||
1403 (c >= '0' && c <= '9') ||
1404 (c == '_')
1405 ) {
1406 // acceptable character
1407 } else if(c >= 'A' && c <= 'Z') {
1408 // uppercase alpha - convert to lowercase
1409 c += ('a' - 'A');
1410 } else if(c == '.') {
1411 // if the next character is the end, or version number, then
1412 // eat the dot
1413 if(n->name[i + 1] == 0 || n->name[i + 1] == ';') {
1414 memmove(n->name + i, n->name + i + 1, namelen - i);
1415 namelen--;
1416 i--;
1417 continue;
1418 }
1419 } else if(c == ';') {
1420 // semicolon - strip the rest of the name if ";1"
1421 if(i == (namelen - 2) && n->name[i + 1] == '1') {
1422 c = 0;
1423 namelen = i;
1424 }
1425 } else {
1426 // not ok - just replace with an underscore
1427 c = '_';
1428 }
1429 n->name[i] = c;
1430 }
1431 }
1432 //
1433 // Get sector
1434 //
1435 little = get32lsb(dr + DR_extent + 0);
1436 big = get32msb(dr + DR_extent + 4);
1437 if(little == big || opt->little) {
1438 n->sector = little;
1439 } else if(opt->big) {
1440 n->sector = big;
1441 } else {
1442 goto error_mismatch;
1443 }
1444 //
1445 // Get size
1446 //
1447 little = get32lsb(dr + DR_size + 0);
1448 big = get32msb(dr + DR_size + 4);
1449 if(little == big || opt->little) {
1450 n->size = little;
1451 } else if(opt->big) {
1452 n->size = big;
1453 } else {
1454 goto error_mismatch;
1455 }
1456 //
1457 // Get modified time
1458 //
1459 { int32_t year = ((uint8_t)(dr[DR_date + 0]));
1460 int32_t month = ((uint8_t)(dr[DR_date + 1]));
1461 int32_t day = ((uint8_t)(dr[DR_date + 2]));
1462 int32_t hour = ((uint8_t)(dr[DR_date + 3]));
1463 int32_t minute = ((uint8_t)(dr[DR_date + 4]));
1464 int32_t second = ((uint8_t)(dr[DR_date + 5]));
1465 int32_t gmtofs = (( int8_t)(dr[DR_date + 6]));
1466 year -= 70; // year = Years since 1970
1467 if(year < 0) {
1468 // Before 1970: Invalid
1469 n->modtime = (time_t)(-1);
1470 } else {
1471 int32_t i;
1472 // Calculate modtime = days since 1970
1473 n->modtime = year;
1474 n->modtime *= 365;
1475 // Adjust for leap years
1476 if(year > 2) {
1477 n->modtime += (year + 1) / 4;
1478 }
1479 if(((((year+2) % 4)) == 0) && (month > 2)) {
1480 n->modtime += 1;
1481 }
1482 // Add days from previous months
1483 for(i = 1; i < month; i++) {
1484 static const int32_t md[] = {
1485 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1486 };
1487 n->modtime += md[i - 1];
1488 }
1489 // Add days from this month
1490 n->modtime += day - 1;
1491 // Multiply out modtime from days into seconds
1492 n->modtime *= 24;
1493 n->modtime += hour;
1494 n->modtime *= 60;
1495 n->modtime += minute;
1496 n->modtime *= 60;
1497 n->modtime += second;
1498 // Adjust modtime into GMT using the provided offset
1499 if(gmtofs >= -52 && gmtofs <= 52) {
1500 n->modtime -= gmtofs * 15 * 60;
1501 }
1502 }
1503 }
1504 //
1505 // Success: Return the length of the directory record
1506 //
1507 return dr[DR_length];
1508
1509 malformed:
1510 if(opt->enforce_fscheck || opt->verbose) {
1511 printf("%s: ",
1512 opt->enforce_fscheck ? "Error" : "Warning"
1513 );
1514 printnodename(n);
1515 printf(": Malformed directory record%s\n",
1516 opt->enforce_fscheck ? fsoverride : ""
1517 );
1518 }
1519 if(opt->enforce_fscheck) { return -1; }
1520 return dr[DR_length];
1521 error_mismatch:
1522 printf("Error: ");
1523 printnodename(n);
1524 printf(": Mismatched little vs. big-endian metadata\n");
1525 printf("Use -le or -be to override\n");
1526 return -1;
1527 }
1528
1529 ////////////////////////////////////////////////////////////////////////////////
1530 //
1531 // Get the next directory entry in a directory
1532 // Returns nonzero on error
1533 // Returns zero, but NULL node, if nothing was found
1534 //
findnext(struct binfile * bin,struct node * n,struct node ** out,const struct cdpatch_options * opt)1535 static int findnext(
1536 struct binfile* bin,
1537 struct node* n,
1538 struct node** out,
1539 const struct cdpatch_options* opt
1540 ) {
1541 int returncode = 0;
1542 //
1543 // Allocate a new node
1544 //
1545 *out = malloc(sizeof(struct node));
1546 if(!(*out)) { goto error_mem; }
1547 (*out)->up = n;
1548 (*out)->depth = n->depth + 1;
1549 //
1550 // Read node data from DR
1551 //
1552 returncode = read_iso_dr(bin, *out, n->sector, n->dirread, n->size, opt);
1553 if(returncode < 0) { goto error; }
1554 if(returncode == 0) { goto notfound; }
1555 //
1556 // Advance
1557 //
1558 n->dirread += returncode;
1559 returncode = 0;
1560 goto done;
1561
1562 error_mem:
1563 printf("%s", oom);
1564 goto error;
1565 error:
1566 returncode = 1;
1567 goto notfound;
1568 notfound:
1569 if(*out) { free(*out); *out = NULL; }
1570 goto done;
1571 done:
1572 return returncode;
1573 }
1574
1575 ////////////////////////////////////////////////////////////////////////////////
1576
pathsep(char c)1577 static int pathsep(char c) { return c == '/' || c == '\\'; }
pathend(char c)1578 static int pathend(char c) { return c == 0 || pathsep(c); }
1579
1580 ////////////////////////////////////////////////////////////////////////////////
1581 //
1582 // Pass f=NULL to get the boot area
1583 //
dofile(struct binfile * bin,struct node * filenode,const struct cdpatch_options * opt,int automatic,uint32_t * numerrors,uint32_t * numsuccesses)1584 static void dofile(
1585 struct binfile* bin,
1586 struct node* filenode,
1587 const struct cdpatch_options* opt,
1588 int automatic,
1589 uint32_t* numerrors,
1590 uint32_t* numsuccesses
1591 ) {
1592 //
1593 // Construct base filename from base name and node name
1594 //
1595 char* filename = NULL;
1596 size_t basedirlen = strlen(opt->basedir);
1597 size_t addsep = !(basedirlen && pathsep(opt->basedir[basedirlen - 1]));
1598 size_t filenamelen = basedirlen + addsep +
1599 (filenode ? nodenamelen(filenode) : 4);
1600
1601 filename = malloc(filenamelen + 1);
1602 if(!filename) { goto error_mem; }
1603
1604 memmove(filename, opt->basedir, basedirlen);
1605 if(addsep) { filename[basedirlen] = '/'; }
1606 if(filenode) {
1607 copynodename(filename + filenamelen, filenode);
1608 } else {
1609 memmove(filename + filenamelen - 4, "boot", 4);
1610 }
1611 filename[filenamelen] = 0;
1612
1613 if(opt->extract) {
1614 //
1615 // Ensure that all parent directories are created
1616 //
1617 char* t = filename;
1618 while(*t) {
1619 while(pathsep(*t)) { t++; }
1620 while(!pathend(*t)) { t++; }
1621 if(pathsep(*t)) {
1622 char c = *t;
1623 *t = 0;
1624 mkdir(filename); // OK if it doesn't succeed
1625 *t = c;
1626 }
1627 }
1628 //
1629 // Extract
1630 //
1631 if(filenode) {
1632 if(extract_file(
1633 bin,
1634 filenode->sector,
1635 filenode->size,
1636 filenode->modtime,
1637 filename,
1638 opt
1639 )) { goto error; }
1640 } else {
1641 if(extract_file(bin, 0, 32768, (time_t)(-1), filename, opt)) {
1642 goto error;
1643 }
1644 }
1645 (*numsuccesses)++;
1646
1647 } else if(opt->insert && (!automatic || exists(filename))) {
1648 //
1649 // Insert
1650 //
1651 if(filenode) {
1652 uint32_t newsize = filenode->size;
1653 if(insert_file(bin, filenode->sector, &newsize, filename, opt)) {
1654 goto error;
1655 }
1656 //
1657 // If the size changed, update the size in the DR
1658 //
1659 if(newsize != filenode->size) {
1660 uint8_t sz[8];
1661 set32lsb(sz + 0, newsize);
1662 set32msb(sz + 4, newsize);
1663 if(write_cooked_data(
1664 bin,
1665 filenode->dr_sector,
1666 filenode->dr_ofs + DR_size,
1667 sz,
1668 8,
1669 opt
1670 )) { goto error; }
1671 }
1672 } else {
1673 uint32_t newsize = 32768;
1674 if(insert_file(bin, 0, &newsize, filename, opt)) {
1675 goto error;
1676 }
1677 }
1678 (*numsuccesses)++;
1679 }
1680
1681 goto done;
1682
1683 error_mem:
1684 printf("%s", oom);
1685 goto error;
1686 error:
1687 (*numerrors)++;
1688 goto done;
1689 done:
1690 if(filename) { free(filename); }
1691 }
1692
1693 ////////////////////////////////////////////////////////////////////////////////
1694 //
1695 // Recursively walk a directory
1696 //
walkdirectory(struct binfile * bin,struct node * root,const struct cdpatch_options * opt,uint32_t * numerrors,uint32_t * numsuccesses)1697 static void walkdirectory(
1698 struct binfile* bin,
1699 struct node* root,
1700 const struct cdpatch_options* opt,
1701 uint32_t* numerrors,
1702 uint32_t* numsuccesses
1703 ) {
1704 struct node* n = root;
1705 struct node* f = NULL;
1706
1707 rewindnode(n);
1708 for(;;) {
1709 if(findnext(bin, n, &f, opt)) { goto error; }
1710 if(!f) {
1711 if(n == root) {
1712 // Done with entire tree walk
1713 break;
1714 } else {
1715 // Back to previous directory
1716 f = n;
1717 n = n->up;
1718 freesubnodes(f, n);
1719 f = NULL;
1720 }
1721 } else if(!f->name[0]) {
1722 //
1723 // Probably a malformed entry which was ignored
1724 //
1725
1726 } else if(f->isdir) {
1727 if(
1728 strcmp((const char*)(f->name), ".") &&
1729 strcmp((const char*)(f->name), "..")
1730 ) {
1731 // Ensure this directory didn't appear anywhere up the chain
1732 struct node* t;
1733 for(t = n; t != root; t = t->up) {
1734 if(t->sector == f->sector) { break; }
1735 }
1736 if(t->sector == f->sector) {
1737 if(opt->enforce_fscheck || opt->verbose) {
1738 printf("%s: Infinite recursion: ",
1739 opt->enforce_fscheck ? "Error" : "Warning"
1740 );
1741 printnodename(f);
1742 printf(" points to ");
1743 printnodename(t);
1744 printf("%s\n",
1745 opt->enforce_fscheck ? fsoverride : ""
1746 );
1747 }
1748 if(opt->enforce_fscheck) { goto error; }
1749 // Ignore the error, but we still can't descend into it
1750 } else {
1751 // Check depth limit.
1752 // Allow out-of-ISO9660 spec, but impose our own limit
1753 if(f->depth > max_path_depth) {
1754 printf("Error: ");
1755 printnodename(f);
1756 printf(": Path is too deep\n");
1757 goto error;
1758 }
1759 // Descend into this directory
1760 n = f;
1761 }
1762 }
1763 } else {
1764 //
1765 // This is a file
1766 //
1767 dofile(bin, f, opt, 1, numerrors, numsuccesses);
1768 }
1769 freesubnodes(f, n);
1770 f = NULL;
1771 }
1772 goto done;
1773 error:
1774 (*numerrors)++;
1775 goto done;
1776 done:
1777 freesubnodes(f, n);
1778 freesubnodes(n, root);
1779 }
1780
1781 ////////////////////////////////////////////////////////////////////////////////
1782
arenamesequal(const char * a,const char * b)1783 static int arenamesequal(const char* a, const char* b) {
1784 for(;;) {
1785 int ca = (*a++) & 0xff;
1786 int cb = (*b++) & 0xff;
1787 if(pathend(ca) && pathend(cb)) { return 1; }
1788 if(pathend(ca)) { return 0; }
1789 if(pathend(cb)) { return 0; }
1790 ca = tolower(ca);
1791 cb = tolower(cb);
1792 if(ca != cb) { return 0; }
1793 }
1794 }
1795
1796 ////////////////////////////////////////////////////////////////////////////////
1797 //
1798 // Find a file or directory in the ISO9660 filesystem
1799 // Returns NULL if not found
1800 //
findnode(struct binfile * bin,struct node * root,const char * filename,const struct cdpatch_options * opt)1801 static struct node* findnode(
1802 struct binfile* bin,
1803 struct node* root,
1804 const char* filename,
1805 const struct cdpatch_options* opt
1806 ) {
1807 struct node* n = root;
1808 struct node* f = NULL;
1809 const char* p = filename;
1810 const char* next = p;
1811
1812 while(pathsep(*p)) { p++; }
1813
1814 for(; *p; p = next) {
1815 //
1816 // Figure out the next path component, if any
1817 //
1818 next = p;
1819 while(!pathend(*next)) { next++; }
1820 while(pathsep(*next)) { next++; }
1821 //
1822 // Special case "." and ".."
1823 //
1824 if(p[0] == '.' && pathend(p[1])) {
1825 continue;
1826 }
1827 if(p[0] == '.' && p[1] == '.' && pathend(p[2])) {
1828 if(n != root && n->up) {
1829 f = n;
1830 n = n->up;
1831 freesubnodes(f, n);
1832 f = NULL;
1833 }
1834 continue;
1835 }
1836 //
1837 // Find n = path component p in directory node n
1838 //
1839 rewindnode(n);
1840 for(;;) {
1841 if(findnext(bin, n, &f, opt)) { goto error; }
1842 if(!f) { goto error_pathnotfound; }
1843 if(
1844 arenamesequal(p, (const char*)(f->name)) &&
1845 (f->isdir || !(*next))
1846 ) {
1847 n = f;
1848 break;
1849 }
1850 freesubnodes(f, n);
1851 f = NULL;
1852 }
1853 }
1854
1855 return n;
1856
1857 error_pathnotfound:
1858 printf("Error: %s: Path not found in ISO\n", filename);
1859 goto error;
1860 error:
1861 freesubnodes(f, n);
1862 freesubnodes(n, root);
1863 return NULL;
1864 }
1865
1866 ////////////////////////////////////////////////////////////////////////////////
1867
visit_arg(struct binfile * bin,struct node * root,const char * filename,const struct cdpatch_options * opt,uint32_t * numerrors,uint32_t * numsuccesses)1868 static void visit_arg(
1869 struct binfile* bin,
1870 struct node* root,
1871 const char* filename,
1872 const struct cdpatch_options* opt,
1873 uint32_t* numerrors,
1874 uint32_t* numsuccesses
1875 ) {
1876 struct node* n = NULL;
1877
1878 //
1879 // First, find the node in the ISO9660 filesystem
1880 //
1881 n = findnode(bin, root, filename, opt);
1882 if(!n) { goto error; }
1883
1884 if(n->isdir) {
1885 //
1886 // If it's a directory:
1887 //
1888 // If we're not recursing, that's an error
1889 //
1890 if(!opt->recurse) {
1891 printf("Error: %s: Is a directory\n", filename);
1892 goto error;
1893 }
1894 //
1895 // Walk the directory
1896 //
1897 walkdirectory(bin, n, opt, numerrors, numsuccesses);
1898
1899 } else {
1900 //
1901 // If it's a file, visit it
1902 //
1903 dofile(bin, n, opt, 0, numerrors, numsuccesses);
1904 }
1905
1906 goto done;
1907
1908 error:
1909 (*numerrors)++;
1910 goto done;
1911 done:
1912 freesubnodes(n, root);
1913 }
1914
1915 ////////////////////////////////////////////////////////////////////////////////
1916
cdpatch(const struct cdpatch_options * opt)1917 static int cdpatch(const struct cdpatch_options* opt) {
1918 int returncode = 0;
1919 struct binfile bin;
1920 struct node* root = NULL;
1921 int i;
1922 uint32_t numerrors = 0;
1923 uint32_t numsuccesses = 0;
1924
1925 if(bin_init(&bin)) { goto error; }
1926 bin.name = opt->binname;
1927
1928 //
1929 // Attempt to open bin/iso file
1930 //
1931 bin.f = fopen(bin.name, opt->insert ? "r+b" : "rb");
1932 if(!bin.f) { goto error_bin; }
1933
1934 if(bintype_detect(&bin)) { goto error; }
1935
1936 if(opt->verbose) {
1937 printf("Image file: %s\n", opt->binname);
1938 printf("Format: ");
1939 switch(bin.type) {
1940 case BINTYPE_2048: printf("ISO (2048-byte sectors)\n"); break;
1941 case BINTYPE_2352: printf("BIN (2352-byte sectors)\n"); break;
1942 }
1943 }
1944
1945 //
1946 // Read primary descriptor
1947 //
1948 { uint8_t* data = read_cooked_sector(&bin, 16, opt);
1949 if(!data) { goto error; }
1950 if(opt->verbose) {
1951 printf("System ID: ");
1952 printsafestring(data + PD_system_id, 32);
1953 printf("\nVolume ID: ");
1954 printsafestring(data + PD_volume_id, 32);
1955 printf("\n");
1956 }
1957 }
1958
1959 //
1960 // Insert or extract boot area, if desired
1961 //
1962 if(opt->boot) {
1963 dofile(&bin, NULL, opt, 0, &numerrors, &numsuccesses);
1964 }
1965
1966 //
1967 // Retrive root directory info
1968 //
1969 root = malloc(sizeof(struct node));
1970 if(!root) { goto error_mem; }
1971 root->depth = 0;
1972 root->up = NULL;
1973 i = read_iso_dr(&bin, root, 16, PD_root_dir_record, 2048, opt);
1974 if(i < 0) { goto error; }
1975 if(i == 0) {
1976 printf("Error: Root directory descriptor is missing\n");
1977 goto error;
1978 }
1979
1980 //
1981 // Visit each of the arguments
1982 //
1983 for(i = 0; i < opt->files_count; i++) {
1984 const char* file = opt->files[i];
1985 if(*file) { // If non-empty
1986 visit_arg(&bin, root, file, opt, &numerrors, &numsuccesses);
1987 }
1988 }
1989
1990 if(numsuccesses || !numerrors) {
1991 printf("%lu file%s %s\n",
1992 (unsigned long)numsuccesses,
1993 numsuccesses != 1 ? "s" : "",
1994 opt->extract ? "extracted" : "inserted"
1995 );
1996 }
1997 if(numerrors) {
1998 printf("%lu error%s encountered\n",
1999 (unsigned long)numerrors,
2000 numerrors != 1 ? "s" : ""
2001 );
2002 }
2003
2004 returncode = (numerrors != 0);
2005 goto done;
2006
2007 error_mem:
2008 printf("%s", oom);
2009 goto error;
2010 error_bin:
2011 printfileerror(bin.f, bin.name);
2012 goto error;
2013 error:
2014 returncode = 1;
2015 goto done;
2016 done:
2017 if(root) { free(root); }
2018 bin_quit(&bin);
2019 return returncode;
2020 }
2021
2022 ////////////////////////////////////////////////////////////////////////////////
2023
checkboth(int a,int b,const char * opa,const char * opb)2024 static int checkboth(int a, int b, const char* opa, const char* opb) {
2025 if(a && b) {
2026 printf("Error: Cannot specify both %s and %s\n", opa, opb);
2027 return 1;
2028 }
2029 return 0;
2030 }
2031
checkeither(int a,int b,const char * opa,const char * opb)2032 static int checkeither(int a, int b, const char* opa, const char* opb) {
2033 if((!a) && (!b)) {
2034 printf("Error: Must specify either %s or %s\n", opa, opb);
2035 return 1;
2036 }
2037 return 0;
2038 }
2039
2040 ////////////////////////////////////////////////////////////////////////////////
2041
main(int argc,char ** argv)2042 int main(int argc, char** argv) {
2043 int returncode = 0;
2044 static const char* default_files[1] = { "." };
2045 static const int default_files_count = 1;
2046 const char* warn_missing = NULL;
2047
2048 struct cdpatch_options opt;
2049 int i;
2050
2051 normalize_argv0(argv[0]);
2052
2053 memset(&opt, 0, sizeof(opt));
2054 //
2055 // Enforce filesystem checks by default (unless overridden with -f)
2056 //
2057 opt.enforce_fscheck = 1;
2058
2059 //
2060 // Check options
2061 //
2062 if(argc == 1) { goto usage; }
2063 for(i = 1; i < argc; i++) {
2064 if(argv[i][0] == '-') {
2065 // An option
2066 if(!strcmp(argv[i], "--")) {
2067 // No more options
2068 i++;
2069 break;
2070 } else if(!strcmp(argv[i], "-i")) {
2071 if(opt.insert) { goto error_dup; }
2072 if(i >= (argc - 1)) { goto error_missing; }
2073 if(argv[i+1][0] == '-') { warn_missing = argv[i]; }
2074 opt.insert = 1;
2075 opt.binname = argv[++i];
2076 continue;
2077 } else if(!strcmp(argv[i], "-x")) {
2078 if(opt.extract) { goto error_dup; }
2079 if(i >= (argc - 1)) { goto error_missing; }
2080 if(argv[i+1][0] == '-') { warn_missing = argv[i]; }
2081 opt.extract = 1;
2082 opt.binname = argv[++i];
2083 continue;
2084 } else if(!strcmp(argv[i], "-d")) {
2085 if(opt.basedir) { goto error_dup; }
2086 if(i >= (argc - 1)) { goto error_missing; }
2087 if(argv[i+1][0] == '-') { warn_missing = argv[i]; }
2088 opt.basedir = argv[++i];
2089 continue;
2090 } else if(!strcmp(argv[i], "-be")) {
2091 opt.big = 1;
2092 continue;
2093 } else if(!strcmp(argv[i], "-le")) {
2094 opt.little = 1;
2095 continue;
2096 } else if(!strcmp(argv[i], "-boot")) {
2097 opt.boot = 1;
2098 continue;
2099 } else if(!strcmp(argv[i], "-f")) {
2100 opt.enforce_fscheck = 0;
2101 continue;
2102 } else if(!strcmp(argv[i], "-o")) {
2103 opt.overwrite = 1;
2104 continue;
2105 } else if(!strcmp(argv[i], "-v")) {
2106 opt.verbose = 1;
2107 continue;
2108 } else if(!strcmp(argv[i], "-r")) {
2109 opt.recurse = 1;
2110 continue;
2111 }
2112 printf("Unknown option: %s\n", argv[i]);
2113 goto error_usage;
2114 } else {
2115 // Not an option - stop here
2116 break;
2117 }
2118 }
2119
2120 if(checkeither(opt.insert, opt.extract ,"-i","-x")) { goto error_usage; }
2121 warn_missing = NULL;
2122 if(checkboth (opt.big , opt.little ,"-be","-le")) { goto error_usage; }
2123 if(checkboth (opt.insert, opt.extract ,"-i","-x")) { goto error_usage; }
2124 if(checkboth (opt.insert, opt.overwrite,"-i","-o")) { goto error_usage; }
2125
2126 //
2127 // If base directory wasn't specified, default to "."
2128 //
2129 if(!opt.basedir) { opt.basedir = "."; }
2130
2131 //
2132 // If no files or -boot were specified, default to "-r ."
2133 //
2134 if(i >= argc && !opt.boot) {
2135 opt.recurse = 1;
2136 opt.files = default_files;
2137 opt.files_count = default_files_count;
2138 } else {
2139 opt.files = (const char**)(argv + i);
2140 opt.files_count = (argc - i);
2141 }
2142
2143 //
2144 // Initialize ECC/EDC tables
2145 //
2146 eccedc_init();
2147
2148 //
2149 // Go
2150 //
2151 returncode = cdpatch(&opt);
2152
2153 goto done;
2154
2155 error_dup:
2156 printf("Error: Specified %s twice\n", argv[i]);
2157 goto error_usage;
2158 error_missing:
2159 printf("Error: Missing parameter for %s\n", argv[i]);
2160 goto error_usage;
2161 error_usage:
2162 if(warn_missing) {
2163 printf("(Missing parameter after %s?)\n", warn_missing);
2164 }
2165 printf("\n");
2166 goto usage;
2167 usage:
2168 banner();
2169 printf(
2170 "Usage:\n"
2171 " To insert: %s -i bin_or_iso [options] [files...]\n"
2172 " To extract: %s -x bin_or_iso [options] [files...]\n"
2173 "\nOptions:\n"
2174 " -be Favor big-endian values in ISO9660 metadata\n"
2175 " -boot Insert or extract boot area\n"
2176 " -d dir Set the base directory for inserted or extracted files\n"
2177 " (defaults to .)\n"
2178 " -f Skip filesystem consistency checks\n"
2179 " -le Favor little-endian values in ISO9660 metadata\n"
2180 " -o Force overwrite when extracting files\n"
2181 " -r Recurse into subdirectories\n"
2182 " -v Verbose\n",
2183 argv[0],
2184 argv[0]
2185 );
2186 goto error;
2187
2188 error:
2189 returncode = 1;
2190 goto done;
2191
2192 done:
2193 return returncode;
2194 }
2195
2196 ////////////////////////////////////////////////////////////////////////////////
2197