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 "rs03-includes.h"
26 
27 
28 /***
29  *** Read and buffer CRC information from RS03 file
30  ***/
31 
main(int,char **)32 CrcBuf *RS03GetCrcBuf(Image *image)
33 {  RS03CksumClosure *csc;
34    CrcBuf *cbuf;
35    RS03Layout *lay;
36    EccHeader *eh;
37    AlignedBuffer *ab = CreateAlignedBuffer(2048);
38    guint32 *crc_buf = (guint32*)ab->buf;
39    gint64 block_idx[256];
40    gint64 crc_sector,s;
41    int i;
42    int crc_valid = 1;
43 
44    /* Allocate buffer for ascending sector order CRCs */
45 
46    if(image->eccFileHeader)
47    {  eh = image->eccFileHeader;
48       csc = (RS03CksumClosure*)image->eccFileMethod->ckSumClosure;
49 
50       lay = CalcRS03Layout(image, ECC_FILE);
51       cbuf = CreateCrcBuf((lay->ndata-1)*lay->sectorsPerLayer);
52    }
53    else
54    {  eh = image->eccHeader;
55       csc = (RS03CksumClosure*)image->eccMethod->ckSumClosure;
56       lay = CalcRS03Layout(image, ECC_IMAGE);
57       cbuf = CreateCrcBuf((lay->ndata-1)*lay->sectorsPerLayer);
58    }
59 
60    csc->signatureErrors=0;
61    if(csc->lay) g_free(csc->lay);
62    csc->lay = lay;
63 
64    /* First sector containing crc data */
65 
66    crc_sector = lay->firstCrcPos;
67 
68    /* Initialize ecc block index pointers.
69       Note that CRC blocks are shifted by one
70       (each ECC block contains the CRC for the next ECC block) */
71 
72    for(s=0, i=0; i<lay->ndata; s+=lay->sectorsPerLayer, i++)
73      block_idx[i] = s+1;
74 
75    /* Cycle through the ecc blocks.
76       Each ecc block contains the CRCs for the following ecc block;
77       these are rearranged in ascending sector order. */
78 
79    for(s=0; s<lay->sectorsPerLayer; s++)
80    {  int err;
81 
82       /* Get CRC sector for current ecc block */
83 
84       if(image->eccFile && image->eccFileState == ECCFILE_PRESENT)  /* read from separate ecc file */
85       {  if(!LargeSeek(image->eccFile, (gint64)(2048*(lay->firstCrcPos+s))))
86 	    CreateMissingSector(ab->buf, crc_sector, image->imageFP, FINGERPRINT_SECTOR, NULL);
87 	 else
88 	   if(LargeRead(image->eccFile, ab->buf, 2048) != 2048)
89 	     CreateMissingSector(ab->buf, crc_sector, image->imageFP, FINGERPRINT_SECTOR, NULL);
90       }
91       else /* read from augmented image */
92       {  int n = ImageReadSectors(image, ab->buf, crc_sector, 1);
93 	 if(n!=1)
94 	    CreateMissingSector(ab->buf, crc_sector, image->imageFP, FINGERPRINT_SECTOR, NULL);
95       }
96 
97       err = CheckForMissingSector(ab->buf, crc_sector, eh->mediumFP, eh->fpSector);
98 #if 0
99       if(err != SECTOR_PRESENT)
100       {  int source_type;
101 
102 	 if(image->eccFile && image->eccFileState == ECCFILE_PRESENT)
103 	      source_type = SOURCE_ECCFILE;
104 	 else source_type = image->type == IMAGE_FILE ? SOURCE_IMAGE : SOURCE_MEDIUM;
105 
106 	 if(!unrecoverable_sectors && err != SECTOR_MISSING)
107 	    PrintLog("\n");
108          ExplainMissingSector(ab->buf, crc_sector, err, source_type, &unrecoverable_sectors);
109       }
110 #endif
111       crc_sector++;
112       crc_valid = (err == SECTOR_PRESENT);
113 
114       /* Check the CrcBlock data structure */
115 
116       if(crc_valid)
117       {  CrcBlock *cb = (CrcBlock*)ab->buf;
118 
119 	 if(  memcmp(cb->cookie, "*dvdisaster*", 12)
120 	    ||memcmp(cb->method, "RS03", 4))
121 	 {  crc_valid = FALSE;
122 	    csc->signatureErrors++;
123          }
124 	 else
125          {  guint32 recorded_crc = cb->selfCRC;
126             guint32 real_crc;
127 
128 #ifdef HAVE_BIG_ENDIAN
129             cb->selfCRC = 0x47504c00;
130 #else
131             cb->selfCRC = 0x4c5047;
132 #endif
133 
134             real_crc = Crc32((unsigned char*)cb, 2048);
135 
136             if(real_crc != recorded_crc)
137             {  crc_valid = FALSE;
138 	       csc->signatureErrors++;
139             }
140          }
141       }
142 
143       /* Go through all data sectors of current ecc block;
144 	 distribute the CRC values */
145 
146       for(i=0; i<lay->ndata-1; i++)
147       {
148 	 /* CRC sums for the first ecc block are contained in the last
149 	    CRC sector. Wrap the block_idx accordingly. */
150 
151 	 if(s == lay->sectorsPerLayer-1)
152 	    block_idx[i] = i*lay->sectorsPerLayer;
153 
154 	 /* Sort crc into appropriate place if CRC block is valid */
155 
156 	 if(crc_valid)
157 	 {  cbuf->crcbuf[block_idx[i]] = crc_buf[i];
158 	    SetBit(cbuf->valid,block_idx[i]);
159 	 }
160 
161 	 block_idx[i]++;
162       }
163    }
164 
165    FreeAlignedBuffer(ab);
166    return cbuf;
167 }
168 
169 /***
170  *** Read one or more image sectors from the .iso file.
171  ***/
172 
173 void RS03ReadSectors(Image *image, RS03Layout *lay, unsigned char *buf,
174 		     gint64 layer, gint64 layer_sector, gint64 how_many, int flags)
175 {  LargeFile *target_file = NULL;
176    gint64 start_sector=0;
177    gint64 stop_sector=0;
178    gint64 byte_size = how_many * 2048;
179    gint64 img_file_sector_size;
180    gint64 ecc_file_sector_size=0;
181    gint64 target_file_sector_size;
182    int in_last;
183    gint64 n;
184 
185    if(layer < 0 || layer > 255)
186       Stop("RS03ReadSectors: layer %lld out of range 0 .. 255\n", layer);
187    if(layer_sector < 0 || layer_sector >= lay->sectorsPerLayer)
188       Stop("RS03ReadSectors: offset %lld out of range 0 .. %lld)\n",
189 	   layer_sector, lay->sectorsPerLayer-1);
190 
191    /* "Image" file size may not be a multiple of 2048 */
192 
193    in_last = image->file->size % 2048;
194    img_file_sector_size = image->file->size/2048;
195    if(in_last) img_file_sector_size++;
196 
197    /* Ignore trailing garbage in the image file */
198 
199    if(lay->target == ECC_FILE)
200    {  /* If the image is longer as expected in the ecc file,
201 	 truncate sizes to the values recorded in the ecc file. */
202       if(img_file_sector_size > lay->dataSectors)
203       {  img_file_sector_size = lay->dataSectors;
204 	 in_last = lay->eh->inLast;
205       }
206 
207       /* If the image has the right sector size, but contains
208 	 a few bytes more in this sector as expected, truncate
209 	 the value. However if the last sector contains some
210 	 bytes less than expected, keep the smaller value
211 	 to prevent reading past the image later on. */
212       if(   img_file_sector_size == lay->dataSectors
213 	    && in_last > lay->eh->inLast)
214       {   in_last = lay->eh->inLast;
215       }
216 
217       /* Ecc file size is currently considered to be a multiple
218 	 of the sector size (which is normally the case).
219 	 If the ecc file is tuncated by a few bytes,
220 	 the last incomplete sector is ignored. */
221 
222       ecc_file_sector_size = image->eccFile->size/2048;
223    }
224 
225    /* Read out of the data layer */
226 
227    if(layer < lay->ndata-1)
228    {  if(!(flags & RS03_READ_DATA))
229 	 Stop("RS03ReadSectors: trying to read data layer, but flag not set\n");
230 
231       start_sector = layer*lay->sectorsPerLayer + layer_sector;
232       stop_sector  = start_sector + how_many - 1;
233 
234       if(stop_sector >= (layer+1)*lay->sectorsPerLayer)
235 	Stop("RS03ReadSectors: range %lld..%lld crosses layer boundary\n",
236 	     start_sector, stop_sector);
237       target_file = image->file;
238    }
239 
240    /* Read out of the crc layer */
241 
242    if(layer == lay->ndata-1)
243    {  if(!(flags & RS03_READ_CRC))
244 	 Stop("RS03ReadSectors: trying to read crc layer, but flag not set\n");
245 
246       start_sector = lay->firstCrcPos + layer_sector;
247       stop_sector  = start_sector + how_many - 1;
248 
249       if(lay->target == ECC_IMAGE)
250 	   target_file = image->file;
251       else target_file = image->eccFile;
252    }
253 
254    /*** Read out of the ecc layers */
255 
256    target_file_sector_size = img_file_sector_size;
257 
258    if(layer >= lay->ndata)
259    {  if(!(flags & RS03_READ_ECC))
260 	 Stop("RS03ReadSectors: trying to read ecc layer, but flag not set\n");
261 
262       start_sector = lay->firstEccPos + (layer-lay->ndata)*lay->sectorsPerLayer + layer_sector;
263       stop_sector  = start_sector + how_many - 1;
264 
265       if(lay->target == ECC_IMAGE)
266 	   target_file = image->file;
267       else
268       {    target_file = image->eccFile;
269 	   target_file_sector_size = ecc_file_sector_size;
270 	   in_last = 0; /* Ecc file size if always a multiple of 2048 */
271       }
272    }
273 
274    /* Reading beyond the image returns
275       - dead sectors if the image was truncated
276       - padding sectors if the real end of the image is exceeded.
277       Create them in memory; shorten read range accordingly */
278 
279    if(stop_sector >= target_file_sector_size)
280    {  unsigned char *bufptr = buf;
281       char *volume_label = NULL;
282       guint64 expected_sectors;
283 
284 #if 0  //FIXME
285       if(rc->image->isoInfo && rc->image->isoInfo->volumeLabel[0])
286       rc->volumeLabel = g_strdup(rc->image->isoInfo->volumeLabel);
287 #endif
288 
289       if(lay->target == ECC_FILE)
290 	 expected_sectors = lay->dataSectors;
291       else
292 	 expected_sectors = lay->totalSectors;
293 
294       for(n=start_sector; n<=stop_sector; n++)
295       {
296 	 if(n>=target_file_sector_size)
297 	 {  guint8 *fp = lay->eh ? lay->eh->mediumFP : NULL;
298 	    if(n>=expected_sectors)
299 	    {  CreatePaddingSector(bufptr, n, fp, FINGERPRINT_SECTOR);
300 	    }
301 	    else
302 	    {  CreateMissingSector(bufptr, n, fp, FINGERPRINT_SECTOR, volume_label);
303 	    }
304 	    byte_size -= 2048;
305 	 }
306 	 bufptr += 2048;
307       }
308    }
309 
310    if(byte_size<=0)
311       return;
312 
313    /* Image with ecc files may have an incomplete last sector.
314       Deal with it appropriately. */
315 
316    if(lay->target == ECC_FILE && in_last)
317    {  if(start_sector <= target_file_sector_size-1
318 	 && target_file_sector_size-1 <= stop_sector)
319       {
320 	 memset(buf, 0, byte_size);
321 	 byte_size = byte_size - 2048 + in_last;
322       }
323    }
324 
325    /* All sectors are consecutively readable in image case */
326 
327    if(!LargeSeek(target_file, (gint64)(2048*start_sector)))
328       Stop(_("Failed seeking to sector %lld in image: %s"),
329 	   start_sector, strerror(errno));
330 
331    n = LargeRead(target_file, buf, byte_size);
332    if(n != byte_size)
333       Stop(_("Failed reading sector %lld in image: %s"),
334 	   start_sector, strerror(errno));
335 }
336 
337 /***
338  *** Calculate position of n-th sector of the given layer in the image.
339  ***/
340 
341 gint64 RS03SectorIndex(RS03Layout *lay, gint64 layer, gint64 n)
342 {
343    if(lay->target == ECC_IMAGE)
344       return layer*lay->sectorsPerLayer+n;
345 
346    /* Image portion in ecc file case */
347 
348    if(layer < lay->ndata-1)
349       return layer*lay->sectorsPerLayer+n;
350 
351    /* Layers located in the ecc file */
352 
353    if(layer == lay->ndata-1) /* CRC layer */
354       return lay->firstCrcPos + n;
355 
356    /* Ecc layers */
357 
358    return lay->firstEccPos + (layer-lay->ndata)*lay->sectorsPerLayer + n;
359 }
360 
361 
362 /***
363  *** Calculation of the image layout
364  ***/
365 
366 static int get_roots(gint64 data_sectors, gint64 medium_capacity)
367 {  gint64 sectors_per_layer = medium_capacity/GF_FIELDMAX;
368    int ndata = (data_sectors + 2 +sectors_per_layer - 1) / sectors_per_layer;
369 
370    return GF_FIELDMAX - ndata - 1;
371 }
372 
373 static gint64 ecc_file_size(gint64 sectors, int nr)
374 {  int nd = GF_FIELDMAX - nr;
375    gint64 bytesize;
376 
377    bytesize = 4096 + 2048*(nr+1)*((sectors+nd-1)/nd);
378 
379    return (bytesize+0xfffff)/0x100000;   /* size in MiB */
380 }
381 
382 
383 RS03Layout *CalcRS03Layout(Image *image, int target)
384 {  RS03Layout *lay = g_malloc0(sizeof(RS03Layout));
385 
386    /* See if layout has already been cached in the image */
387 
388    if(image->cachedLayout)
389    {  RS03Layout *ptr = (RS03Layout*)image->cachedLayout;
390       if(strncmp((char*)(ptr->eh->method), "RS03", 4))
391       {  Verbose("CalcRS03Layout(): removed cached layout from other codec\n");
392 	 g_free(image->cachedLayout);
393       }
394       else
395       {  if(((RS03Layout*)image->cachedLayout)->target != target)
396 	 {  Verbose("CalcRS03Layout(): removed cached layout from RS03, wrong target\n");
397 	    g_free(image->cachedLayout);
398 	 }
399 	 {  Verbose("CalcRS03Layout(): returning cached layout (%s)\n",
400 		    ((RS03Layout*)image->cachedLayout)->target == ECC_FILE ? "file" : "augmented");
401 	    memcpy(lay, image->cachedLayout, sizeof(RS03Layout));
402 	    return lay;
403 	 }
404       }
405    }
406 
407    lay->target = target;
408 
409    /* We are going to create an error correction file */
410 
411    if(target == ECC_FILE)
412    {  guint64 filesize;
413       int n_roots = 0;
414       char last = 0;
415 
416       lay->eh = image->eccFileHeader;
417 
418       if(lay->eh)  /* Header given; get number of roots from there */
419       {  n_roots = lay->eh->eccBytes;
420 	 lay->dataSectors = uchar_to_gint64(lay->eh->sectors);
421 	 lay->inLast = lay->eh->inLast;
422       }
423       else    /* Calculate number of roots */
424       {
425 	 /* Calculate image size in sectors */
426 
427 	 if(!LargeStat(Closure->imageName, &filesize))
428 	    Stop(_("Image file %s not present."),Closure->imageName);
429 
430 	 CalcSectors(filesize, &lay->dataSectors, &lay->inLast);
431 
432 	 /* Calculate wanted redundancy from Closure->redundancy */
433 
434 	 if(Closure->redundancy) /* get last char of redundancy parameter */
435 	 {  int len = strlen(Closure->redundancy);
436 
437 	    if(len) last = Closure->redundancy[len-1];
438 	 }
439 
440 	 switch(last)
441 	 {  case '%':
442 	    {  double p = atof(Closure->redundancy);
443 
444 	       if(p<3.2 || p>200.0)
445 		  Stop(_("Redundancy %4.1f%% out of useful range [3.2%%..200%%]"),p);
446 	       n_roots = (int)round((GF_FIELDMAX*p) / (100.0+p));
447 	       break;
448 	    }
449 	    case 'm':
450 	    {  gint64 ecc_size;
451 
452 	       ecc_size = strtoll(Closure->redundancy, NULL, 10);
453 	       if(   ecc_size < ecc_file_size(lay->dataSectors, 8)
454 		  || ecc_size > ecc_file_size(lay->dataSectors, 170))
455 		  Stop(_("Ecc file size %lldm out of useful range [%lld .. %lld]"),
456 		       ecc_size,
457 		       ecc_file_size(lay->dataSectors, 8),
458 		       ecc_file_size(lay->dataSectors, 170));
459 
460 	       for(n_roots=170; n_roots>8; n_roots--)
461 		  if(ecc_size >= ecc_file_size(lay->dataSectors, n_roots))
462 		     break;
463 	       break;
464 	    }
465 
466 	    default:
467 	       if(!Closure->redundancy || !strcmp(Closure->redundancy, "normal")) n_roots = 32;
468 	       else if(!strcmp(Closure->redundancy, "high")) n_roots = 64;
469 	       else n_roots = atoi(Closure->redundancy);
470 	       break;
471 	 }
472       }
473 
474       if(n_roots < 8 || n_roots > 170)
475 	 Stop(_("Redundancy %d out of useful range [8..170]."),n_roots);
476 
477       /* Now we have settled for the number of roots,
478 	 so calculate the layout. */
479 
480       lay->dataPadding = 0; /* always zero for ecc files */
481       lay->nroots = n_roots;
482       lay->ndata = GF_FIELDMAX - n_roots;
483 
484       lay->sectorsPerLayer = (lay->dataSectors + lay->ndata - 2)/(lay->ndata-1);
485       lay->totalSectors = lay->dataSectors + 2 + (lay->nroots+1)*lay->sectorsPerLayer;
486 
487       lay->mediumCapacity   = 0;  /* unused for ecc files */
488       lay->eccHeaderPos     = 0;
489       lay->firstCrcPos      = 2;
490       lay->firstEccPos      = lay->firstCrcPos + lay->sectorsPerLayer;
491       lay->redundancy = ((double)lay->nroots*100.0)/(double)lay->ndata;
492    }
493 
494    /* We are going to augment an image file */
495 
496    if(target == ECC_IMAGE)
497    {  gint64 dataSectors;
498 
499       /* Determine smallest possible medium format which
500 	 can hold the image plus at least 8 roots for ecc.
501 	 Overriding the medium size via --debug is not recommended
502 	 as it may render the image irrecoverable in the error case. */
503 
504       lay->eh = image->eccHeader;
505 
506       if(lay->eh)
507       {  dataSectors = uchar_to_gint64(lay->eh->sectors);
508       }
509       else
510       {  dataSectors = image->sectorSize;
511 	 if(Closure->debugMode && Closure->mediumSize)
512 	 {   if(dataSectors >= Closure->mediumSize)
513 	       Stop(_("Medium size smaller than image size (%lld < %lld)"), Closure->mediumSize, dataSectors);
514 	     lay->mediumCapacity = Closure->mediumSize;
515          }
516 	 else
517 	 {  if(get_roots(dataSectors, CDR_SIZE) >= 8)
518 	       lay->mediumCapacity = CDR_SIZE;          /* CDR */
519 	    else if(get_roots(dataSectors, DVD_SL_SIZE) >= 8)
520 	       lay->mediumCapacity = DVD_SL_SIZE;       /* Single layered DVD */
521 	    else if(get_roots(dataSectors, DVD_DL_SIZE) >= 8)
522 	       lay->mediumCapacity = DVD_DL_SIZE;       /* Double layered DVD */
523 	    else if(get_roots(dataSectors, BD_SL_SIZE) >= 8)
524 	       lay->mediumCapacity = BD_SL_SIZE;        /* Single layered BD */
525 	    else  lay->mediumCapacity = BD_DL_SIZE;     /* Double layered BD */
526 	 }
527       }
528 
529       /* Calculate the image layout */
530 
531       if(lay->eh) lay->sectorsPerLayer = lay->eh->sectorsPerLayer;
532       else        lay->sectorsPerLayer = lay->mediumCapacity/GF_FIELDMAX;
533       lay->dataSectors      = dataSectors;
534       lay->totalSectors     = GF_FIELDMAX*lay->sectorsPerLayer;
535 
536       lay->ndata       = (dataSectors + 2 + lay->sectorsPerLayer - 1) / lay->sectorsPerLayer;
537       if(lay->ndata < 84) /* we clip redundancy at 170 roots */
538       {  Verbose("Redundancy clipped from %d to %d\n", lay->ndata, 84);
539 	 lay->ndata = 84;
540       }
541       lay->dataPadding = lay->ndata * lay->sectorsPerLayer - lay->dataSectors - 2;
542       lay->ndata++;    /* CRC layer is also protected and counted as part of the data portion */
543       lay->nroots      = GF_FIELDMAX-lay->ndata;
544       lay->redundancy = ((double)lay->nroots*100.0)/(double)lay->ndata;
545 
546       lay->eccHeaderPos     = lay->dataSectors;
547       lay->firstCrcPos      = (lay->ndata-1)*lay->sectorsPerLayer;
548       lay->firstEccPos      = lay->firstCrcPos + lay->sectorsPerLayer;
549    }
550 
551    /* Debugging output */
552 
553    if(target == ECC_FILE)
554         Verbose("Calculated layout for RS03 file:\n");
555    else Verbose("Calculated layout for RS03 image:\n");
556 
557    Verbose("data sectors      = %lld\n", lay->dataSectors);
558    Verbose("data padding      = %lld\n", lay->dataPadding);
559    Verbose("layer size        = %lld\n", lay->sectorsPerLayer);
560    Verbose("total sectors     = %lld\n", lay->totalSectors);
561    Verbose("medium capacity   = %lld\n", lay->mediumCapacity);
562    Verbose("header position   = %lld\n", lay->eccHeaderPos);
563    Verbose("first CRC sector  = %lld\n", lay->firstCrcPos);
564    Verbose("first ECC sector  = %lld\n", lay->firstEccPos);
565    Verbose("ndata             = %d\n", lay->ndata);
566    Verbose("nroots            = %d (%4.1f%%)\n", lay->nroots, lay->redundancy);
567    Verbose("\n");
568 
569    image->cachedLayout = g_malloc(sizeof(RS03Layout));
570    memcpy(image->cachedLayout, lay, sizeof(RS03Layout));
571 
572    return lay;
573 }
574 
575 /*
576  * Determine expected size of image.
577  * In case of ecc files, only the iso image size is reported.
578  */
579 
580 guint64 RS03ExpectedImageSize(Image *image)
581 {  EccHeader *eh=image->eccHeader;
582    guint64 size = 0;
583 
584    if(!eh && image->eccFileHeader)
585      eh=image->eccFileHeader;
586 
587    if(!eh) return 0;
588 
589    if(eh->methodFlags[0] & MFLAG_ECC_FILE)
590      size = uchar_to_gint64(eh->sectors); /* ecc file */
591    else
592      size = 255*eh->sectorsPerLayer;      /* augmented image */
593 
594    return size;
595 }
596 
597 
598 /***
599  *** Write the RS03 header into the image.
600  ***/
601 
602 void WriteRS03Header(LargeFile *file, RS03Layout *lay, EccHeader *eh)
603 {  int n;
604 
605    if(!LargeSeek(file, 2048*lay->eccHeaderPos))
606      Stop(_("Failed seeking to ecc header at %lld: %s\n"), lay->eccHeaderPos, strerror(errno));
607 
608    n = LargeWrite(file, eh, sizeof(EccHeader));
609    if(n != sizeof(EccHeader))
610      Stop(_("Failed writing ecc header at %lld: %s\n"), lay->eccHeaderPos, strerror(errno));
611 }
612 
613 /***
614  *** Reconstruct the RS03 header from a CRC block
615  ***/
616 
617 void ReconstructRS03Header(EccHeader *eh, CrcBlock *cb)
618 {  int i;
619 
620 #ifdef HAVE_BIG_ENDIAN
621    SwapCrcBlockBytes(cb);
622 #endif
623 
624    memset(eh, 0, sizeof(EccHeader));
625 
626    memcpy(eh->cookie, "*dvdisaster*", 12);
627    memcpy(eh->method, "RS03", 4);
628    for(i=0; i<4; i++)
629       eh->methodFlags[i] = cb->methodFlags[i];
630    memcpy(eh->mediumFP, cb->mediumFP, 16);
631    memcpy(eh->mediumSum, cb->mediumSum, 16);
632    gint64_to_uchar(eh->sectors, cb->dataSectors);
633    eh->dataBytes = cb->dataBytes;
634    eh->eccBytes = cb->eccBytes;
635    eh->creatorVersion = cb->creatorVersion;
636    eh->neededVersion = cb->neededVersion;
637    eh->fpSector = cb->fpSector;
638    eh->inLast = cb->inLast;
639    eh->sectorsPerLayer = cb->sectorsPerLayer;
640 
641    eh->selfCRC = 0x4c5047;
642 
643 #ifdef HAVE_BIG_ENDIAN
644    eh->selfCRC = 0x47504c00;
645 #endif
646 
647    eh->selfCRC = Crc32((unsigned char*)eh, 4096);
648 }
649