1 /* dvdisaster: Additional error correction for optical media.
2 * Copyright (C) 2004-2015 Carsten Gnoerlich.
3 *
4 * Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org
5 * Project homepage: http://www.dvdisaster.org
6 *
7 * This file is part of dvdisaster.
8 *
9 * dvdisaster is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * dvdisaster is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "dvdisaster.h"
24
25 #include "rs02-includes.h"
26 #include "rs03-includes.h"
27 #include "udf.h"
28
29 #include <time.h>
30
31 /***
32 *** Debugging functions.
33 ***/
34
35 /*
36 * Debugging function to seed the image with random correctable errors
37 */
38
39 /* RS01-style files */
40
random_error1(Image * image,char * arg)41 static void random_error1(Image *image, char *arg)
42 { EccHeader *eh;
43 gint64 block_idx[255];
44 gint64 s,si;
45 int block_sel[255];
46 int i,percent,last_percent = 0;
47 int n_data,n_errors;
48 double eras_scale, blk_scale;
49
50 SRandom(Closure->randomSeed);
51 eh = image->eccFileHeader;
52
53 n_errors = atoi(arg);
54
55 if(n_errors < 1|| n_errors > eh->eccBytes)
56 Stop(_("Number of erasures must be > 0 and <= %d\n"), eh->eccBytes);
57
58 n_data = 255-eh->eccBytes;
59 eras_scale = (n_errors+1)/((double)MY_RAND_MAX+1.0);
60 blk_scale = (double)n_data/((double)MY_RAND_MAX+1.0);
61
62
63 /*** Setup block pointers */
64
65 s = (image->sectorSize+n_data-1)/n_data;
66
67 for(si=0, i=0; i<n_data; si+=s, i++)
68 block_idx[i] = si;
69
70 PrintLog(_("\nGenerating random correctable erasures (%s; for %d roots, max erasures = %d).\n"),
71 "RS01", eh->eccBytes, n_errors);
72
73 /*** Randomly delete the blocks */
74
75 for(si=0; si<s; si++)
76 { int n_erasures = (int)(eras_scale*(double)Random());
77
78 /* Reset the block selector */
79
80 for(i=0; i<n_data; i++)
81 block_sel[i] = 0;
82
83 /* Randomly pick n blocks */
84
85 for(i=0; i<n_erasures; i++)
86 { int idx;
87
88 do
89 { idx = (int)(blk_scale*(double)Random());
90 } while(block_sel[idx]);
91
92 block_sel[idx] = 1;
93 }
94
95 /* Delete the randomly picked blocks */
96
97 for(i=0; i<n_data; i++)
98 { unsigned char missing[2048];
99 int write_size = 2048;
100
101 if(block_sel[i] && block_idx[i]<image->sectorSize)
102 { if(!LargeSeek(image->file, (gint64)(2048*block_idx[i])))
103 Stop(_("Failed seeking to sector %lld in image: %s"),block_idx[i],strerror(errno));
104
105 CreateMissingSector(missing, block_idx[i], image->imageFP, FINGERPRINT_SECTOR, NULL);
106
107 if(block_idx[i] == image->sectorSize - 1 && image->inLast < 2048)
108 write_size = image->inLast;
109
110 if(LargeWrite(image->file, missing, write_size) != write_size)
111 Stop(_("Failed writing to sector %lld in image: %s"),block_idx[i],strerror(errno));
112 }
113
114 block_idx[i]++;
115 }
116
117 percent = (100*si)/s;
118 if(last_percent != percent)
119 { PrintProgress(_("Progress: %3d%%"),percent);
120 last_percent = percent;
121 }
122 }
123
124 PrintProgress(_("Progress: 100%%\n"
125 "Recover the image using the --fix option before doing another --random-errors run.\n"
126 "Otherwise you'll accumulate >= %d erasures/ECC block and the image will be lost.\n"),
127 n_errors);
128 }
129
130 /* RS02 ecc images */
131
random_error2(Image * image,char * arg)132 static void random_error2(Image *image, char *arg)
133 { EccHeader *eh = image->eccHeader;
134 RS02Layout *lay;
135 gint64 si;
136 guint64 hpos;
137 guint64 end;
138 guint64 header[42];
139 int block_sel[255];
140 int i,percent,last_percent = 0;
141 int hidx,n_errors,erase_max = 0;
142 double eras_scale, blk_scale, hdr_scale;
143
144 SRandom(Closure->randomSeed);
145 lay = RS02LayoutFromImage(image);
146
147 n_errors = atoi(arg);
148
149 if(n_errors < 0)
150 { erase_max = 1;
151 n_errors = -n_errors;
152 }
153
154 if(n_errors <= 0 || n_errors > eh->eccBytes)
155 Stop(_("Number of erasures must be > 0 and <= %d\n"), eh->eccBytes);
156
157 eras_scale = (n_errors+1)/((double)MY_RAND_MAX+1.0);
158 blk_scale = (double)255.0/((double)MY_RAND_MAX+1.0);
159
160 PrintLog(_("\nGenerating random correctable erasures (%s; for %d roots, max erasures = %d).\n"),
161 "RS02", eh->eccBytes, n_errors);
162
163 /*** Randomly delete some ecc headers */
164
165 header[0] = lay->firstEccHeader;
166 hidx = 1;
167
168 hpos = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo;
169 hpos *= lay->headerModulo;
170
171 end = lay->eccSectors+lay->dataSectors-2;
172
173 while(hpos < end) /* Calculate positions of all headers */
174 {
175 header[hidx++] = hpos;
176 hpos += lay->headerModulo;
177 }
178
179 /* Pick one header to remain intact.
180 Currently this must be one of the repeated headers */
181
182 hdr_scale = (double)(hidx-1)/((double)MY_RAND_MAX+1.0);
183 header[(int)(hdr_scale*(double)Random())+1] = 0;
184
185 for(i=0; i<hidx; i++)
186 { gint64 s = header[i];
187 if(s>0)
188 { unsigned char missing[2048];
189
190 if(!LargeSeek(image->file, (gint64)(2048*s)))
191 Stop(_("Failed seeking to sector %lld in image: %s"), s, strerror(errno));
192
193 CreateMissingSector(missing, s, image->imageFP, image->fpSector, NULL);
194
195 if(LargeWrite(image->file, missing, 2048) != 2048)
196 Stop(_("Failed writing to sector %lld in image: %s"), s, strerror(errno));
197 }
198 }
199
200 /*** Randomly delete the blocks */
201
202 for(si=0; si<lay->sectorsPerLayer; si++)
203 { int n_erasures = (int)(eras_scale*(double)Random());
204 if(erase_max)
205 n_erasures = n_errors;
206
207 /* Reset the block selector */
208
209 for(i=0; i<255; i++)
210 block_sel[i] = 0;
211
212 /* Randomly pick n blocks */
213
214 for(i=0; i<n_erasures; i++)
215 { int idx;
216
217 do
218 { idx = (int)(blk_scale*(double)Random());
219 } while(block_sel[idx]);
220
221 block_sel[idx] = 1;
222 }
223
224 /* Delete the randomly picked blocks */
225
226 for(i=0; i<255; i++)
227 { if(block_sel[i])
228 { unsigned char missing[2048];
229 gint64 s;
230
231 if(i<eh->dataBytes)
232 { s = si + i * lay->sectorsPerLayer;
233 if(s >= lay->protectedSectors) /* exclude the padding area */
234 continue; /* respective sectors do not exist */
235 }
236 else s = RS02EccSectorIndex(lay, i-eh->dataBytes, si);
237
238 if(!LargeSeek(image->file, (gint64)(2048*s)))
239 Stop(_("Failed seeking to sector %lld in image: %s"), s, strerror(errno));
240
241 CreateMissingSector(missing, s, image->imageFP, image->fpSector, NULL);
242 if(LargeWrite(image->file, missing, 2048) != 2048)
243 Stop(_("Failed writing to sector %lld in image: %s"), s, strerror(errno));
244 }
245 }
246
247 percent = (100*si)/lay->sectorsPerLayer;
248 if(last_percent != percent)
249 { PrintProgress(_("Progress: %3d%%"),percent);
250 last_percent = percent;
251 }
252 }
253
254 PrintProgress(_("Progress: 100%%\n"
255 "Recover the image using the --fix option before doing another --random-errors run.\n"
256 "Otherwise you'll accumulate >= %d erasures/ECC block and the image will be lost.\n"),
257 n_errors);
258
259 g_free(lay);
260 }
261
262 /* RS03 ecc images */
263
random_error3(Image * image,char * arg)264 static void random_error3(Image *image, char *arg)
265 { EccHeader *eh;
266 RS03Layout *lay;
267 gint64 si;
268 int block_sel[255];
269 int i,percent,last_percent = 0;
270 int n_errors,erase_max = 0;
271 double eras_scale, blk_scale;
272
273 SRandom(Closure->randomSeed);
274
275 /*** Calculate the layout */
276
277 if(image->eccFileState == ECCFILE_PRESENT)
278 { eh = image->eccFileHeader;
279 lay = CalcRS03Layout(image, ECC_FILE);
280 }
281 else
282 { eh = image->eccHeader;
283 lay = CalcRS03Layout(image, ECC_IMAGE);
284 }
285 n_errors = atoi(arg);
286
287 if(n_errors < 0)
288 { erase_max = 1;
289 n_errors = -n_errors;
290 }
291
292 if(n_errors <= 0 || n_errors > eh->eccBytes)
293 Stop(_("Number of erasures must be > 0 and <= %d\n"), eh->eccBytes);
294
295 eras_scale = (n_errors+1)/((double)MY_RAND_MAX+1.0);
296 blk_scale = (double)255.0/((double)MY_RAND_MAX+1.0);
297
298 if(lay->target == ECC_FILE)
299 PrintLog(_("\nRS03 error correction file with %d roots.\n"), eh->eccBytes);
300 else PrintLog(_("\nRS03 augmented image with %d roots.\n"), eh->eccBytes);
301 PrintLog(_("Generating at most %d random correctable erasures.\n"), n_errors);
302
303 /*** Randomly delete the blocks */
304
305 for(si=0; si<lay->sectorsPerLayer; si++)
306 { int n_erasures = (int)(eras_scale*(double)Random());
307 if(erase_max)
308 n_erasures = n_errors;
309
310 /* Reset the block selector */
311
312 for(i=0; i<255; i++)
313 block_sel[i] = 0;
314
315 /* Randomly pick n blocks */
316
317 for(i=0; i<n_erasures; i++)
318 { int idx;
319
320 do
321 { idx = (int)(blk_scale*(double)Random());
322 } while(block_sel[idx]);
323
324 block_sel[idx] = 1;
325 }
326
327 /* Delete the randomly picked blocks */
328
329 for(i=0; i<255; i++)
330 { if(block_sel[i])
331 { LargeFile *file;
332 unsigned char missing[2048];
333 gint64 s,file_s;
334
335 s = RS03SectorIndex(lay, i, si);
336
337 if(s == 16) /* FIXME: not implemented */
338 continue;
339
340 if(s == lay->eccHeaderPos || s == lay->eccHeaderPos+1)
341 continue; /* FIXME: not implemented */
342
343 /* Do not write out the virtual padding sectors
344 in ecc file case */
345
346 if(lay->target == ECC_FILE
347 && i<=lay->ndata-1
348 && s>=lay->dataSectors)
349 continue;
350
351 if(lay->target == ECC_FILE && i>=lay->ndata-1)
352 { file = image->eccFile;
353 if(i == lay->ndata-1)
354 file_s = lay->firstCrcPos + si;
355 else file_s = lay->firstEccPos + (i-lay->ndata)*lay->sectorsPerLayer + si;
356 }
357 else
358 { file = image->file;
359 file_s = s;
360 }
361
362 if(!LargeSeek(file, (gint64)(2048*file_s))) // FIXME: wrong for ecc files
363 Stop(_("Failed seeking to sector %lld in image: %s"), s, strerror(errno));
364
365 CreateMissingSector(missing, s, image->imageFP, image->fpSector, NULL);
366
367 if(LargeWrite(file, missing, 2048) != 2048)
368 Stop(_("Failed writing to sector %lld in image: %s"), s, strerror(errno));
369 }
370 }
371
372 percent = (100*si)/lay->sectorsPerLayer;
373 if(last_percent != percent)
374 { PrintProgress(_("Progress: %3d%%"),percent);
375 last_percent = percent;
376 }
377 }
378
379 PrintProgress(_("Progress: 100%%\n"
380 "Recover the image using the --fix option before doing another --random-errors run.\n"
381 "Otherwise you'll accumulate >= %d erasures/ECC block and the image will be lost.\n"),
382 n_errors);
383
384 g_free(lay);
385 }
386
RandomError(char * arg)387 void RandomError(char *arg)
388 { Image *image;
389 Method *method = NULL;
390 char buf[5];
391
392 image = OpenImageFromFile(Closure->imageName, O_RDWR, IMG_PERMS);
393 image = OpenEccFileForImage(image, Closure->eccName, O_RDWR, IMG_PERMS);
394 ReportImageEccInconsistencies(image);
395
396 /* Determine method. Ecc files win over augmented ecc. */
397
398 if(image && image->eccFileMethod) method = image->eccFileMethod;
399 else if(image && image->eccMethod) method = image->eccMethod;
400 else Stop("Internal error: No ecc method identified.");
401
402 if(!strncmp(method->name, "RS01", 4))
403 { random_error1(image, arg);
404 CloseImage(image);
405 return;
406 }
407
408 if(!strncmp(method->name, "RS02", 4))
409 { random_error2(image, arg);
410 CloseImage(image);
411 return;
412 }
413
414 if(!strncmp(method->name, "RS03", 4))
415 { random_error3(image, arg);
416 CloseImage(image);
417 return;
418 }
419
420 CloseImage(image);
421 strncpy(buf, method->name, 4); buf[4] = 0;
422 Stop("Don't know how to handle codec %s\n", buf);
423
424 }
425
426 /*
427 * Debugging function to simulate images with single
428 * byte errors (except for faulty cabling and/or controllers,
429 * this should never happen)
430 */
431
Byteset(char * arg)432 void Byteset(char *arg)
433 { Image *image;
434 gint64 s;
435 int i,byte;
436 char *cpos = NULL;
437 unsigned char buf[1];
438
439 /*** Open the image file */
440
441 image = OpenImageFromFile(Closure->imageName, O_RDWR, IMG_PERMS);
442 if(!image)
443 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
444
445 /*** See which byte to set */
446
447 cpos = strchr(arg,',');
448 if(!cpos) Stop(_("2nd argument is missing"));
449 *cpos = 0;
450
451 s = atoi(arg);
452 arg = cpos+1;
453
454 cpos = strchr(arg,',');
455 if(!cpos) Stop(_("3rd argument is missing"));
456 *cpos = 0;
457
458 i = atoi(arg);
459 byte = atoi(cpos+1);
460
461 if(s<0 || s>=image->sectorSize)
462 Stop(_("Sector must be in range [0..%lld]\n"),image->sectorSize-1);
463
464 if(i<0 || i>=2048)
465 Stop(_("Byte position must be in range [0..2047]"));
466
467 if(byte<0 || byte>=256)
468 Stop(_("Byte value must be in range [0..255]"));
469
470 PrintLog(_("Setting byte %d in sector %lld to value %d.\n"), i, s, byte);
471
472 /*** Set the byte */
473
474 s = 2048*s + i;
475
476 if(!LargeSeek(image->file, (gint64)s))
477 Stop(_("Failed seeking to start of image: %s\n"),strerror(errno));
478
479 buf[0] = byte;
480 if(LargeWrite(image->file, buf, 1) != 1)
481 Stop(_("Could not write the new byte value"));
482
483 CloseImage(image);
484 }
485
486 /*
487 * Debugging function to simulate medium with unreadable sectors
488 */
489
Erase(char * arg)490 void Erase(char *arg)
491 { Image *image;
492 gint64 start,end,s;
493 char *dashpos = NULL;
494 char *colonpos = NULL;
495 char *simulation_hint = NULL;
496
497 /*** Open the image file */
498
499 image = OpenImageFromFile(Closure->imageName, O_RDWR, IMG_PERMS);
500 if(!image)
501 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
502 ExamineUDF(image); /* get the volume label */
503
504 /** See if there is a special debugging option following
505 the sector range. This is intentionally an undocumented feature. */
506
507 colonpos = strchr(arg,':');
508 if(colonpos)
509 { *colonpos = 0;
510 simulation_hint=colonpos+1;
511 }
512
513 /*** See which sectors to erase */
514
515 dashpos = strchr(arg,'-');
516 if(dashpos)
517 { *dashpos = 0;
518 start = atoi(arg);
519 end = atoi(dashpos+1);
520 }
521 else start = end = atoi(arg);
522
523 if(start>end || start < 0 || end >= image->sectorSize)
524 Stop(_("Sectors must be in range [0..%lld].\n"),image->sectorSize-1);
525
526 PrintLog(_("Erasing sectors [%lld,%lld]\n"),start,end);
527
528 /*** Erase them. */
529
530 if(!LargeSeek(image->file, (gint64)(2048*start)))
531 Stop(_("Failed seeking to start of image: %s\n"),strerror(errno));
532
533 for(s=start; s<=end; s++)
534 { unsigned char missing[2048];
535 int m = (end == image->sectorSize-1) ? image->inLast : 2048;
536 int n;
537
538 CreateDebuggingSector(missing, s, image->imageFP, FINGERPRINT_SECTOR,
539 image->isoInfo ? image->isoInfo->volumeLabel : NULL,
540 simulation_hint);
541
542 n = LargeWrite(image->file, missing, m);
543
544 if(n != m)
545 Stop(_("Failed writing to sector %lld in image: %s"),s,strerror(errno));
546 }
547
548 /*** Clean up */
549
550 CloseImage(image);
551 }
552
553 /*
554 * Debugging function for truncating images
555 */
556
TruncateImageFile(char * arg)557 void TruncateImageFile(char *arg)
558 { Image *image;
559 gint64 end;
560
561 /*** Open the image file */
562
563 image = OpenImageFromFile(Closure->imageName, O_RDWR, IMG_PERMS);
564 if(!image)
565 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
566
567 /*** Determine last sector */
568
569 end = atoi(arg);
570
571 if(end >= image->sectorSize)
572 Stop(_("New length must be in range [0..%lld].\n"),image->sectorSize-1);
573
574 PrintLog(_("Truncating image to %lld sectors.\n"),end);
575
576 /*** Truncate it. */
577
578 if(!LargeTruncate(image->file, (gint64)(2048*end)))
579 Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
580
581 /*** Clean up */
582
583 CloseImage(image);
584 }
585
586 /*
587 * Debugging function to create an ISO image filled with random numbers
588 */
589
RandomImage(char * image_name,char * n_sectors,int mark)590 void RandomImage(char *image_name, char *n_sectors, int mark)
591 { LargeFile *image;
592 IsoHeader *ih;
593 gint64 sectors;
594 gint64 s = 25; /* number of ISO headers */
595 int percent, last_percent = 0;
596 guint32 size,invert;
597
598 sectors = atoi(n_sectors);
599 if(sectors < 64) sectors = 64;
600
601 /*** Open the image file */
602
603 LargeUnlink(image_name);
604
605 if(!(image = LargeOpen(image_name, O_RDWR | O_CREAT, IMG_PERMS)))
606 Stop(_("Can't open %s:\n%s"),image_name,strerror(errno));
607
608 /*** Print banner */
609
610 PrintLog(_("\nCreating random image with %lld sectors.\n\n"
611 "There is no need for permanently storing this image;\n"
612 "you can always reproduce it by calling\n"
613 "dvdisaster --debug %s %lld --random-seed %d\n\n"),
614 sectors,
615 mark ? "--marked-image" : "--random-image",
616 sectors, Closure->randomSeed);
617
618 if(Closure->randomSeed >= 0)
619 { SRandom(Closure->randomSeed);
620 invert = 0;
621 }
622 else
623 { SRandom(-Closure->randomSeed);
624 invert = 0xffffffff;
625 }
626
627 /*** Create and write the ISO file system.
628 Otherwise some writing software will not recognize the image. */
629
630 ih = InitIsoHeader();
631 size = sectors-s;
632 if(size>=2048*1024)
633 size=2048*1024-1;
634 AddFile(ih, "random.data", 2048*size);
635 WriteIsoHeader(ih, image);
636 FreeIsoHeader(ih);
637
638 /*** Create it */
639
640 while(s<sectors)
641 { guint32 buf[512];
642 int i=511;
643 int n;
644
645 #ifdef HAVE_LITTLE_ENDIAN
646 do buf[i--] = (Random32() ^ invert); while(i>=0);
647 #else
648 do buf[i--] = SwapBytes32(Random32() ^ invert); while(i>=0);
649 #endif
650
651 if(mark) /* Mark the sector with its number. */
652 { int i;
653
654 for(i=0; i<2048; i+=128)
655 sprintf(((char*)buf)+i, "Sector %8lld", (long long int)s);
656 }
657
658 n = LargeWrite(image, buf, 2048);
659 s++;
660
661 if(n != 2048)
662 Stop(_("Failed writing to sector %lld in image: %s"),s,strerror(errno));
663
664 percent = (100*s)/sectors;
665 if(last_percent != percent)
666 { PrintProgress(_("Progress: %3d%%"),percent);
667 last_percent = percent;
668 }
669 }
670
671 /*** Clean up */
672
673 if(!LargeClose(image))
674 Stop(_("Error closing image file:\n%s"), strerror(errno));
675 }
676
677 /*
678 * Replaces the "unreadable sector" marker with zeros.
679 */
680
ZeroUnreadable(void)681 void ZeroUnreadable(void)
682 { Image *image;
683 unsigned char buf[2048],zeros[2048];
684 gint64 s,cnt=0;
685 int percent, last_percent = 0;
686
687 image = OpenImageFromFile(Closure->imageName, O_RDWR, IMG_PERMS);
688 if(!image)
689 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
690 PrintLog(_("Replacing the \"unreadable sector\" markers with zeros.\n"));
691 memset(zeros, 0, 2048);
692
693 if(!LargeSeek(image->file, (gint64)0))
694 Stop(_("Failed seeking to start of image: %s\n"),strerror(errno));
695
696 for(s=0; s<image->sectorSize; s++)
697 { int n = LargeRead(image->file, buf, 2048);
698
699 if(n != 2048)
700 Stop(_("Could not read image sector %lld:\n%s\n"),s,strerror(errno));
701
702 /* Replace the dead sector marker */
703
704 if(CheckForMissingSector(buf, s, image->imageFP, FINGERPRINT_SECTOR) != SECTOR_PRESENT)
705 {
706 if(!LargeSeek(image->file, (gint64)(2048*s)))
707 Stop(_("Failed seeking to sector %lld in image: %s"),s,strerror(errno));
708
709 n = LargeWrite(image->file, zeros, 2048);
710 n=2048;
711
712 if(n != 2048)
713 Stop(_("Failed writing to sector %lld in image: %s"),s,strerror(errno));
714
715 cnt++;
716 }
717
718 percent = (100*s)/image->sectorSize;
719 if(last_percent != percent)
720 { PrintProgress(_("Progress: %3d%%"),percent);
721 last_percent = percent;
722 }
723 }
724
725 PrintProgress(_("%lld \"unreadable sector\" markers replaced.\n"), cnt);
726
727 CloseImage(image);
728 }
729
730 /**
731 ** Debugging functions to show contents of a given sector
732 **/
733
734 /*
735 * produce a hex dump
736 */
737
HexDump(unsigned char * buf,int len,int step)738 void HexDump(unsigned char *buf, int len, int step)
739 { int i,j;
740
741 for(i=0; i<len; i+=step)
742 { PrintLog("%04x: ",i);
743 for(j=0; j<step; j++)
744 if(i+j >= len) PrintLog((j&0x07) == 0x07 ? " " : " ");
745 else PrintLog("%02x%s", buf[i+j], (j&0x07) == 0x07 ? " " : " ");
746
747 for(j=0; j<step; j++)
748 { if(i+j >= len) break;
749 if((j&0x07) == 0x07)
750 PrintLog("%c ", isprint(buf[i+j]) ? buf[i+j] : '.');
751 else PrintLog("%c", isprint(buf[i+j]) ? buf[i+j] : '.');
752 }
753
754 PrintLog("\n");
755 }
756 }
757
758 /*
759 * produce a C #include file
760 */
761
CDump(unsigned char * buf,int lba,int len,int step)762 void CDump(unsigned char *buf, int lba, int len, int step)
763 { int i;
764
765 g_printf("#define SECTOR_LENGTH %d\n"
766 "#define SECTOR_LBA %d\n"
767 "unsigned char sector_frame[%d] = {\n",
768 len, lba, len);
769
770 len--;
771 for(i=0; i<=len; i++)
772 { g_printf("%3d%c ", *buf++, i==len ? ' ' : ',');
773
774 if(i%step == (step-1))
775 g_printf("\n");
776 }
777
778 printf("};\n");
779 }
780
781 /*
782 * Show Ecc header from image file
783 */
784
ShowHeader(char * arg)785 void ShowHeader(char *arg)
786 { Image *image;
787 gint64 sector;
788 int n;
789 EccHeader *eh = alloca(4096);
790
791 /*** Open the image file */
792
793 image = OpenImageFromFile(Closure->imageName, O_RDONLY, IMG_PERMS);
794 if(!image)
795 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
796
797 /*** Determine sector to show */
798
799 sector = atoi(arg);
800
801 if(sector < 0 || sector >= image->sectorSize)
802 Stop(_("Sector must be in range [0..%lld]\n"),image->sectorSize-1);
803
804 /*** Load it. */
805
806 if(!LargeSeek(image->file, (gint64)(2048*sector)))
807 Stop(_("Failed seeking to sector %lld in image: %s"),sector,strerror(errno));
808
809 n = LargeRead(image->file, eh, 2048);
810 if(n != 2048)
811 Stop(_("Failed reading sector %lld in image: %s"),sector,strerror(errno));
812
813 /*** Clean up */
814
815 CloseImage(image);
816
817 /*** Show it */
818
819 PrintEccHeader(eh);
820 }
821
822 /*
823 * Show sector from image file
824 */
825
ShowSector(char * arg)826 void ShowSector(char *arg)
827 { Image *image;
828 gint64 sector;
829 int n;
830 unsigned char buf[2048];
831
832 /*** Open the image file */
833
834 image = OpenImageFromFile(Closure->imageName, O_RDONLY, IMG_PERMS);
835 if(!image)
836 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
837
838 /*** Determine sector to show */
839
840 sector = atoi(arg);
841
842 if(sector < 0 || sector >= image->sectorSize)
843 Stop(_("Sector must be in range [0..%lld]\n"),image->sectorSize-1);
844
845 PrintLog(_("Contents of sector %lld:\n\n"),sector);
846
847 /*** Show it. */
848
849 if(!LargeSeek(image->file, (gint64)(2048*sector)))
850 Stop(_("Failed seeking to sector %lld in image: %s"),sector,strerror(errno));
851
852 n = LargeRead(image->file, buf, 2048);
853 if(n != 2048)
854 Stop(_("Failed reading sector %lld in image: %s"),sector,strerror(errno));
855
856 if(Closure->debugCDump)
857 CDump(buf, sector, 2048, 16);
858 else
859 { HexDump(buf, 2048, 32);
860 g_printf("CRC32 = %04x\n", Crc32(buf, 2048));
861 }
862
863 /*** Clean up */
864
865 CloseImage(image);
866 }
867
868 /*
869 * Read sector from drive
870 */
871
ReadSector(char * arg)872 void ReadSector(char *arg)
873 { AlignedBuffer *ab = CreateAlignedBuffer(2048);
874 Image *image;
875 gint64 sector;
876 int status;
877
878 /*** Open the device */
879
880 image = OpenImageFromDevice(Closure->device);
881 if(!image)
882 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
883
884 /*** Determine sector to show */
885
886 sector = atoi(arg);
887
888 if(sector < 0 || sector >= image->dh->sectors)
889 { CloseImage(image);
890 FreeAlignedBuffer(ab);
891 Stop(_("Sector must be in range [0..%lld]\n"),image->dh->sectors-1);
892 }
893
894 PrintLog(_("Contents of sector %lld:\n\n"),sector);
895
896 /*** Read it. */
897
898 status = ReadSectors(image->dh, ab->buf, sector, 1);
899
900 /*** Print results */
901
902 if(status)
903 { CloseImage(image);
904 FreeAlignedBuffer(ab);
905 Stop(_("Failed reading sector %lld: %s"),sector,strerror(errno));
906 }
907
908 if(Closure->debugCDump)
909 CDump(ab->buf, sector, 2048, 16);
910 else
911 { HexDump(ab->buf, 2048, 32);
912 g_printf("CRC32 = %04x\n", Crc32(ab->buf, 2048));
913 }
914
915 CloseImage(image);
916 FreeAlignedBuffer(ab);
917 }
918
919 /***
920 *** Read a raw CD sector
921 ***/
922
RawSector(char * arg)923 void RawSector(char *arg)
924 { AlignedBuffer *ab = CreateAlignedBuffer(4096);
925 Sense *sense;
926 unsigned char cdb[MAX_CDB_SIZE];
927 Image *image;
928 gint64 lba;
929 int length=0,status;
930 int offset=16;
931
932 /*** Open the device */
933
934 image = OpenImageFromDevice(Closure->device);
935 if(!image)
936 Stop(_("Can't open %s:\n%s"), Closure->imageName, strerror(errno));
937 sense = &image->dh->sense;
938
939 /*** Only CD can be read in raw mode */
940
941 if(image->dh->mainType != CD)
942 { CloseImage(image);
943 FreeAlignedBuffer(ab);
944 Stop(_("Raw reading only possible on CD media\n"));
945 }
946
947 /*** Determine sector to show */
948
949 lba = atoi(arg);
950
951 if(lba < 0 || lba >= image->dh->sectors)
952 { CloseImage(image);
953 FreeAlignedBuffer(ab);
954 Stop(_("Sector must be in range [0..%lld]\n"),image->dh->sectors-1);
955 }
956
957 PrintLog(_("Contents of sector %lld:\n\n"),lba);
958
959 /*** Try the raw read */
960
961 memset(cdb, 0, MAX_CDB_SIZE);
962 cdb[0] = 0xbe; /* READ CD */
963 switch(image->dh->subType) /* Expected sector type */
964 { case DATA1: /* data mode 1 */
965 cdb[1] = 2<<2;
966 #if 1
967 cdb[9] = 0xb8; /* we want Sync + Header + User data + EDC/ECC */
968 length=MAX_RAW_TRANSFER_SIZE;
969 #else
970 cdb[9] = 0xba; /* we want Sync + Header + User data + EDC/ECC + C2 */
971 length=2646;
972 #endif
973 offset=16;
974 break;
975
976 case XA21: /* xa mode 2 form 1 */
977 cdb[1] = 4<<2;
978 cdb[9] = 0xf8;
979 length=MAX_RAW_TRANSFER_SIZE;
980 offset=24;
981 break;
982 }
983
984 cdb[2] = (lba >> 24) & 0xff;
985 cdb[3] = (lba >> 16) & 0xff;
986 cdb[4] = (lba >> 8) & 0xff;
987 cdb[5] = lba & 0xff;
988 cdb[6] = 0; /* number of sectors to read (3 bytes) */
989 cdb[7] = 0;
990 cdb[8] = 1; /* read nsectors */
991
992 cdb[10] = 0; /* reserved stuff */
993 cdb[11] = 0; /* no special wishes for the control byte */
994
995 CreateMissingSector(ab->buf, lba, NULL, 0, NULL);
996 status = SendPacket(image->dh, cdb, 12, ab->buf, length, sense, DATA_READ);
997
998 if(status<0) /* Read failed */
999 { RememberSense(sense->sense_key, sense->asc, sense->ascq);
1000 CloseImage(image);
1001 FreeAlignedBuffer(ab);
1002 Stop("Sector read failed: %s\n", GetLastSenseString(FALSE));
1003 }
1004 else
1005 { if(Closure->debugCDump)
1006 CDump(ab->buf, lba, length, 16);
1007 else
1008 { HexDump(ab->buf, length, 32);
1009 g_printf("CRC32 = %04x\n", Crc32(ab->buf+offset, 2048));
1010 }
1011 }
1012
1013 FreeAlignedBuffer(ab);
1014 }
1015
1016 /***
1017 *** Send a CDB to the drive and report what happens
1018 ***
1019 * Sending ill-formed cdbs may kill your system
1020 * and/or damage yout drive permanently.
1021 *
1022 * Example command line call for sending an inquiry:
1023 *
1024 * ./dvdisaster --debug --send-cdb 12,00,00,00,24,00:24
1025 *
1026 * The first six bytes make up the cdb; cdbs with upto 12 bytes are possible.
1027 * The :24 arg is the allocation length.
1028 * Note that the allocation length must match those specified in the cdb;
1029 * differing values may crash the system.
1030 */
1031
1032 enum { SHIFT0, SHIFT4, ALLOC };
1033
SendCDB(char * cdb_raw)1034 void SendCDB(char *cdb_raw)
1035 { AlignedBuffer *ab = CreateAlignedBuffer(MAX_CLUSTER_SIZE);
1036 int cdb_len = 0;
1037 int alloc_len = 0;
1038 unsigned char cdb[16];
1039 int mode = SHIFT4;
1040 int nibble=0;
1041 int status;
1042 char *c = cdb_raw;
1043
1044 while(*c && cdb_len<16)
1045 { if(*c == ',' || *c== ':')
1046 { if(*c == ':')
1047 mode = ALLOC;
1048 c++; continue;
1049 }
1050
1051 if(*c >= '0' && *c <= '9')
1052 nibble = *c - '0';
1053 else if(*c >= 'a' && *c <= 'f')
1054 nibble = *c - 'a' + 10;
1055 else if(*c >= 'A' && *c <= 'F')
1056 nibble = *c - 'A' + 10;
1057 else Stop("illegal char '%c' in cdb \"%s\"\n",*c,cdb_raw);
1058
1059 switch(mode)
1060 { case SHIFT0:
1061 cdb[cdb_len] |= nibble;
1062 mode = SHIFT4;
1063 cdb_len++;
1064 break;
1065
1066 case SHIFT4:
1067 cdb[cdb_len] = nibble << 4;
1068 mode = SHIFT0;
1069 break;
1070
1071 case ALLOC:
1072 alloc_len = (alloc_len << 4) | nibble;
1073 break;
1074 }
1075
1076 c++;
1077 }
1078
1079 PrintLog("\n");
1080 status = SendReadCDB(Closure->device, ab->buf, cdb, cdb_len, alloc_len);
1081
1082 if(!status)
1083 { g_printf("\nDrive returned:\n\n");
1084 HexDump(ab->buf, alloc_len, 16);
1085 }
1086
1087 FreeAlignedBuffer(ab);
1088 }
1089
1090 /***
1091 *** Create a bitmap of simulated defects
1092 ***/
1093
SimulateDefects(gint64 size)1094 Bitmap* SimulateDefects(gint64 size)
1095 { Bitmap *bm = CreateBitmap0(size);
1096 gint64 defects = (size*(gint64)Closure->simulateDefects)/(gint64)100;
1097
1098 SRandom(Closure->randomSeed);
1099
1100 /* Create sequences of n sectors until the number of defects is reached. */
1101
1102 while(defects)
1103 { double scale, size_scale;
1104 int n, bit;
1105
1106 scale = (double)defects/((double)MY_RAND_MAX+1.0);
1107 if(defects > 32)
1108 n = (int)(scale*(double)Random());
1109 else n = defects;
1110
1111 size_scale = (double)(size-n)/((double)MY_RAND_MAX+1.0);
1112 bit = (int)(size_scale*(double)Random());
1113
1114 while(n--)
1115 { if(!GetBit(bm, bit))
1116 { SetBit(bm, bit);
1117 defects--;
1118 }
1119 bit++;
1120 }
1121 }
1122
1123 return bm;
1124 }
1125
1126 /***
1127 *** Copy a sector between two image files.
1128 ***/
1129
CopySector(char * arg)1130 void CopySector(char *arg)
1131 { LargeFile *from, *to;
1132 char *from_path, *to_path;
1133 guint64 from_sector, to_sector, sectors;
1134 unsigned char buf[2048];
1135 char *cpos = NULL;
1136
1137 /*** Evaluate arguments */
1138
1139 cpos = strchr(arg,',');
1140 if(!cpos) Stop(_("2nd argument is missing"));
1141 *cpos = 0;
1142 from_path = arg;
1143 arg = cpos+1;
1144
1145 cpos = strchr(arg,',');
1146 if(!cpos) Stop(_("3rd argument is missing"));
1147 *cpos = 0;
1148 from_sector = atoll(arg);
1149 arg = cpos+1;
1150
1151 cpos = strchr(arg,',');
1152 if(!cpos) Stop(_("4th argument is missing"));
1153 *cpos = 0;
1154 to_path = arg;
1155
1156 to_sector = atoll(cpos+1);
1157
1158 /*** Check the given files */
1159
1160 if(!(from = LargeOpen(from_path, O_RDONLY, IMG_PERMS)))
1161 Stop(_("Can't open %s:\n%s"), from_path, strerror(errno));
1162
1163 LargeStat(from_path, §ors); sectors /= 2048;
1164 if(from_sector<0 || from_sector>sectors-1)
1165 Stop(_("Source sector must be in range [0..%lld]\n"), sectors-1);
1166
1167
1168 if(!(to = LargeOpen(to_path, O_WRONLY, IMG_PERMS)))
1169 Stop(_("Can't open %s:\n%s"), to_path, strerror(errno));
1170
1171 LargeStat(to_path, §ors); sectors /= 2048;
1172 if(to_sector<0 || to_sector>sectors-1)
1173 Stop(_("Destination sector must be in range [0..%lld]\n"), sectors-1);
1174
1175 /*** Copy the sector */
1176
1177 PrintLog(_("Copying sector %lld from %s to sector %lld in %s.\n"),
1178 from_sector, from_path, to_sector, to_path);
1179
1180 if(!LargeSeek(from, (gint64)(2048*from_sector)))
1181 Stop(_("Failed seeking to sector %lld in image: %s"),
1182 from_sector, strerror(errno));
1183
1184 if(LargeRead(from, buf, 2048) != 2048)
1185 Stop(_("Failed reading sector %lld in image: %s"),
1186 from_sector, strerror(errno));
1187
1188 if(!LargeSeek(to, (gint64)(2048*to_sector)))
1189 Stop(_("Failed seeking to sector %lld in image: %s"),
1190 to_sector, strerror(errno));
1191
1192 if(LargeWrite(to, buf, 2048) != 2048)
1193 Stop(_("Failed writing to sector %lld in image: %s"),
1194 to_sector, strerror(errno));
1195
1196 /*** Clean up */
1197
1198 LargeClose(from);
1199 LargeClose(to);
1200 }
1201
1202 /***
1203 *** Compare or merge images
1204 ***/
1205
MergeImages(char * arg,int mode)1206 void MergeImages(char *arg, int mode)
1207 { LargeFile *left, *right;
1208 char *left_path, *right_path;
1209 guint64 left_sectors, right_sectors,min_sectors,s;
1210 int percent,last_percent = 0;
1211 char *cpos = NULL;
1212
1213 /*** Evaluate arguments */
1214
1215 cpos = strchr(arg,',');
1216 if(!cpos) Stop(_("2nd argument is missing"));
1217 *cpos = 0;
1218
1219 left_path = arg;
1220 right_path = cpos+1;
1221
1222 /*** Check the given files */
1223
1224 if(!(left = LargeOpen(left_path, mode ? O_RDWR : O_RDONLY, IMG_PERMS)))
1225 Stop(_("Can't open %s:\n%s"), left_path, strerror(errno));
1226
1227 LargeStat(left_path, &left_sectors); left_sectors /= 2048;
1228
1229 if(!(right = LargeOpen(right_path, O_RDONLY, IMG_PERMS)))
1230 Stop(_("Can't open %s:\n%s"), right_path, strerror(errno));
1231
1232 LargeStat(right_path, &right_sectors); right_sectors /= 2048;
1233
1234 /*** Compare/merge the images */
1235
1236 if(!mode) PrintLog("Comparing %s (%lld sectors) with %s (%lld sectors).\n",
1237 left_path, left_sectors, right_path, right_sectors);
1238 else PrintLog("Merging %s (%lld sectors) with %s (%lld sectors).\n",
1239 left_path, left_sectors, right_path, right_sectors);
1240
1241 /*** Compare them */
1242
1243 if(left_sectors < right_sectors)
1244 min_sectors = left_sectors;
1245 else min_sectors = right_sectors;
1246
1247
1248 for(s=0; s<min_sectors; s++)
1249 { unsigned char left_buf[2048], right_buf[2048];
1250
1251 if(LargeRead(left, left_buf, 2048) != 2048)
1252 Stop(_("Failed reading sector %lld in image: %s"),
1253 s, strerror(errno));
1254
1255 if(LargeRead(right, right_buf, 2048) != 2048)
1256 Stop(_("Failed reading sector %lld in image: %s"),
1257 s, strerror(errno));
1258
1259 if(memcmp(left_buf, right_buf, 2048))
1260 {
1261 if(CheckForMissingSector(left_buf, s, NULL, 0) != SECTOR_PRESENT)
1262 { if(!mode) PrintLog("< Sector %lld missing\n", s);
1263 else
1264 { PrintLog("< Sector %lld missing; copied from %s.\n", s, right_path);
1265 if(!LargeSeek(left, (2048*s)))
1266 Stop(_("Failed seeking to sector %lld in image: %s"),
1267 s, strerror(errno));
1268
1269 if(LargeWrite(left, right_buf, 2048) != 2048)
1270 Stop(_("Failed writing to sector %lld in image: %s"),
1271 s, strerror(errno));
1272 }
1273 }
1274 else if(CheckForMissingSector(right_buf, s, NULL, 0) != SECTOR_PRESENT)
1275 { PrintLog("> Sector %lld missing\n", s);
1276 }
1277 else
1278 { PrintLog("! Sector %lld differs in images\n", s);
1279 }
1280 }
1281
1282 percent = (100*s)/left_sectors;
1283 if(last_percent != percent)
1284 { PrintProgress(_("Progress: %3d%%"),percent);
1285 last_percent = percent;
1286 }
1287 }
1288
1289 if(left_sectors > right_sectors)
1290 { PrintLog("%lld sectors missing at the end of %s\n",
1291 left_sectors-right_sectors, right_path);
1292 }
1293
1294 if(left_sectors < right_sectors)
1295 { if(!mode)
1296 PrintLog("%lld sectors missing at the end of %s\n",
1297 right_sectors-left_sectors, left_path);
1298 else
1299 { unsigned char buf[2048];
1300
1301 PrintLog("Transferring %lld sectors from the end of %s to %s.\n",
1302 right_sectors-left_sectors, right_path, left_path);
1303
1304 for(s=left_sectors; s<right_sectors; s++)
1305 { if(LargeRead(right, buf, 2048) != 2048)
1306 Stop(_("Failed reading sector %lld in image: %s"),
1307 s, strerror(errno));
1308
1309 if(LargeWrite(left, buf, 2048) != 2048)
1310 Stop(_("Failed writing to sector %lld in image: %s"),
1311 s, strerror(errno));
1312 }
1313 }
1314 }
1315
1316 /*** Clean up */
1317
1318 LargeClose(left);
1319 LargeClose(right);
1320 }
1321
1322 /*
1323 * Print LaTeX'ed table of Galois fields and other matrices
1324 */
1325
LaTeXify(gint32 * table,int rows,int columns)1326 void LaTeXify(gint32 *table , int rows, int columns)
1327 { int x,y;
1328
1329 printf("\\begin{tabular}{|l||");
1330 for(x=0; x<columns; x++)
1331 printf("c|");
1332 printf("}\n\\hline\n");
1333
1334 printf("&");
1335 for(x=0; x<columns; x++)
1336 printf("%c %02x ", x==0?' ':'&', x);
1337 printf("\\\\\n\\hline\n\\hline\n");
1338
1339 for(y=0; y<rows; y++)
1340 { printf("%02x &",16*y);
1341 for(x=0; x<columns; x++)
1342 printf("%c %02x ", x==0?' ':'&', *table++);
1343 printf("\\\\\n\\hline\n");
1344 }
1345
1346 printf("\\end{tabular}\n");
1347 }
1348
1349 /*
1350 * Append a text to a file in printf() manner,
1351 * not keeping it open.
1352 */
1353
AppendToTextFile(char * filename,char * format,...)1354 void AppendToTextFile(char* filename, char *format, ...)
1355 { va_list argp;
1356 FILE *file;
1357
1358 file = fopen(filename, "a");
1359 if(!file)
1360 Stop("Could not open %s: %s\n", filename, strerror(errno));
1361
1362 va_start(argp, format);
1363 g_vfprintf(file, format, argp);
1364 va_end(argp);
1365
1366 if(fclose(file))
1367 Stop("Could not close %s: %s\n", filename, strerror(errno));
1368 }
1369