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, &sectors); 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, &sectors); 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