/* dvdisaster: Additional error correction for optical media. * Copyright (C) 2004-2017 Carsten Gnoerlich. * * Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org * Project homepage: http://www.dvdisaster.org * * This file is part of dvdisaster. * * dvdisaster is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * dvdisaster is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with dvdisaster. If not, see . */ #include "dvdisaster.h" #include "rs02-includes.h" #include "scsi-layer.h" /*** *** Read and buffer CRC information from RS02 file ***/ CrcBuf *RS02GetCrcBuf(Image *image) { RS02CksumClosure *csc; AlignedBuffer *ab = CreateAlignedBuffer(2048); RS02Layout *lay; CrcBuf *cb; gint64 block_idx[256]; gint64 crc_sector; gint64 s,i; int crc_idx, crc_valid = FALSE; csc = (RS02CksumClosure*)image->eccMethod->ckSumClosure; if(csc->lay) g_free(csc->lay); lay = csc->lay = RS02LayoutFromImage(image); cb = CreateCrcBuf(image); /* Initialize ecc block index pointers. The first CRC set (of lay->ndata checksums) relates to ecc block lay->firstCrcLayerIndex + 1. */ for(s=0, i=0; indata; s+=lay->sectorsPerLayer, i++) block_idx[i] = s + lay->firstCrcLayerIndex + 1; crc_idx = 512; /* force crc buffer reload */ crc_sector = lay->dataSectors+2; /* first crc data sector on medium */ /* Cycle through the ecc blocks and descramble CRC sums in ascending sector numbers. */ for(s=0; ssectorsPerLayer; s++) { gint64 si = (s + lay->firstCrcLayerIndex + 1) % lay->sectorsPerLayer; /* Wrap the block_idx[] ptrs at si == 0 */ if(!si) { gint64 bs; for(bs=0, i=0; indata; bs+=lay->sectorsPerLayer, i++) block_idx[i] = bs; } /* Go through all data sectors of current ecc block */ for(i=0; indata; i++) { gint64 bidx = block_idx[i]; if(bidx < lay->dataSectors) /* only data sectors have CRCs */ { /* Refill crc cache if needed */ if(crc_idx >= 512) { crc_valid = ImageReadSectors(image, ab->buf, crc_sector++, 1); crc_idx = 0; } /* Sort crc into appropriate place */ if(crc_valid) { cb->crcbuf[bidx] = ((guint32*)ab->buf)[crc_idx]; SetBit(cb->valid, bidx); } crc_idx++; block_idx[i]++; } } } FreeAlignedBuffer(ab); /* The ecc header records only the md5 sum of the data portion, but not that of the whole image, so flag the md5 sums as missing. */ memcpy(cb->dataMD5sum, image->eccHeader->mediumSum, 16); cb->md5State = MD5_BUILDING | MD5_DATA_COMPLETE; return cb; } /*** *** Internal checksum handling. ***/ void RS02ResetCksums(Image *image) { RS02CksumClosure *csc = (RS02CksumClosure*)image->eccMethod->ckSumClosure; MD5Init(&csc->md5ctxt); MD5Init(&csc->dataCtxt); MD5Init(&csc->crcCtxt); MD5Init(&csc->eccCtxt); MD5Init(&csc->metaCtxt); } void RS02UpdateCksums(Image *image, gint64 sector, unsigned char *buf) { RS02CksumClosure *csc = (RS02CksumClosure*)image->eccMethod->ckSumClosure; MD5Update(&csc->md5ctxt, buf, 2048); /* md5sum the data portion */ if(sector < csc->lay->dataSectors) { if(sector < csc->lay->dataSectors - 1) MD5Update(&csc->dataCtxt, buf, 2048); else MD5Update(&csc->dataCtxt, buf, image->eccHeader->inLast); } /* md5sum the crc portion */ if(sector >= csc->lay->dataSectors+2 && sector < csc->lay->protectedSectors) MD5Update(&csc->crcCtxt, buf, 2048); /* md5sum the ecc layers */ if(sector >= csc->lay->protectedSectors) { gint64 layer, n; RS02SliceIndex(csc->lay, sector, &layer, &n); if(layer != -1) /* not an ecc header? */ { if(n < csc->lay->sectorsPerLayer-1) /* not at layer end? */ MD5Update(&csc->eccCtxt, buf, 2048); else /* layer end; update meta md5 and skip to next layer */ { guint8 sum[16]; MD5Update(&csc->eccCtxt, buf, 2048); MD5Final(sum, &csc->eccCtxt); MD5Update(&csc->metaCtxt, sum, 16); MD5Init(&csc->eccCtxt); } } /* maybe add ...else { check ecc header } */ } } int RS02FinalizeCksums(Image *image) { RS02CksumClosure *csc = (RS02CksumClosure*)image->eccMethod->ckSumClosure; guint8 image_fp[16]; guint8 data_md5[16],crc_md5[16],meta_md5[16]; char ascii_digest[33]; int result = 0; MD5Final(image_fp, &csc->md5ctxt); MD5Final(data_md5, &csc->dataCtxt); MD5Final(crc_md5, &csc->crcCtxt); MD5Final(meta_md5, &csc->metaCtxt); /* Data (payload) checksum */ if(memcmp(data_md5, image->eccHeader->mediumSum, 16)) { AsciiDigest(ascii_digest, data_md5); Verbose("BAD Data md5sum: %s\n", ascii_digest); result |= DATA_MD5_BAD; } else Verbose("GOOD Data md5sum\n"); /* Crc layer checksum */ if(memcmp(crc_md5, image->eccHeader->crcSum, 16)) { AsciiDigest(ascii_digest, crc_md5); Verbose("BAD CRC md5sum: %s\n", ascii_digest); result |= CRC_MD5_BAD; } else Verbose("GOOD CRC md5sum\n"); /* Ecc meta checksum */ if(memcmp(meta_md5, image->eccHeader->eccSum, 16)) { AsciiDigest(ascii_digest, meta_md5); Verbose("BAD ECC md5sum: %s\n", ascii_digest); result |= ECC_MD5_BAD; } else Verbose("GOOD ECC md5sum\n"); return result; } /*** *** Read an image sector from the .iso file. **** * Reading sectors beyond lay->protectedSectors always returns a zero padding sector. */ void RS02ReadSector(Image *image, RS02Layout *lay, unsigned char *buf, gint64 s) { int n; /* Padding sector for ecc calculation */ if(s >= lay->protectedSectors) { memset(buf, 0, 2048); return; } /* There is a circular dependence between the first EccHeader and the error correction because of the eccSum. Simply return a null sector instead. */ if( s == lay->firstEccHeader || s == lay->firstEccHeader + 1) { memset(buf, 0, 2048); return; } /* Reading beyond the image returns dead sectors */ if(s >= image->sectorSize) { CreateMissingSector(buf, s, NULL, 0, NULL); return; } /* Read a real sector */ if(!LargeSeek(image->file, (gint64)(2048*s))) Stop(_("Failed seeking to sector %lld in image: %s"), s, strerror(errno)); n = LargeRead(image->file, buf, 2048); if(n != 2048) Stop(_("Failed reading sector %lld in image: %s"),s,strerror(errno)); } /*** *** Calculate position of n-th Ecc sector of the given slice in the image. *** * Deprecated; use RS02SectorIndex() instead. */ gint64 RS02EccSectorIndex(RS02Layout *lay, gint64 slice, gint64 n) { gint64 ecc_idx; gint64 fr,base; gint64 s,nh; /* Index of ecc sectors if numbering were continuos and starting from 0 */ ecc_idx = slice*lay->sectorsPerLayer + n; /* Index of first Ecc header which is interleaved with ecc sectors */ fr = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo; fr *= lay->headerModulo; /* Number of ecc sectors before first interleaved Ecc header */ base = fr - lay->protectedSectors; if(ecc_idx < base) return lay->protectedSectors + ecc_idx; /* Calculate index of ecc sectors with interleaved headers taken into account */ s = fr+2; /* first available ecc sector behind first interleaved header */ ecc_idx -= base; /* number of ecc sectors behind first interleaved header */ nh = ecc_idx/(lay->headerModulo-2); /* number of interleaved headers crossed */ s += ecc_idx; /* add ecc sector index */ s += 2*nh; /* add two for each interleaved header crossed */ return s; } /*** *** Calculate position of n-th sector of the given slice in the image. ***/ gint64 RS02SectorIndex(RS02Layout *lay, gint64 slice, gint64 n) { gint64 ecc_idx; gint64 fr,base; gint64 s,nh; /* Easy case: Sector is a data or crc sector */ if(slice < lay->ndata) { gint64 sector = slice*lay->sectorsPerLayer + n; if(sector < lay->protectedSectors) return sector; else return -1; /* padding sector (invalid)! */ } /* else calculate position of ecc sector */ slice -= lay->ndata; /* Index of ecc sectors if numbering were continuos and starting from 0 */ ecc_idx = slice*lay->sectorsPerLayer + n; /* Index of first Ecc header which is interleaved with ecc sectors */ fr = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo; fr *= lay->headerModulo; /* Number of ecc sectors before first interleaved Ecc header */ base = fr - lay->protectedSectors; if(ecc_idx < base) return lay->protectedSectors + ecc_idx; /* Calculate index of ecc sectors with interleaved headers taken into account */ s = fr+2; /* first available ecc sector behind first interleaved header */ ecc_idx -= base; /* number of ecc sectors behind first interleaved header */ nh = ecc_idx/(lay->headerModulo-2); /* number of interleaved headers crossed */ s += ecc_idx; /* add ecc sector index */ s += 2*nh; /* add two for each interleaved header crossed */ return s; } /*** *** Calculate position of given sector within its Ecc slice. *** * E.g. if s = RS02SectorIndex(lay, slice, n) * then RS02SliceIndex(lay, s, &slice, &n) * returns the slice and n values for s. */ void RS02SliceIndex(RS02Layout *lay, gint64 sector, gint64 *slice, gint64 *n) { gint64 remainder; gint64 first_repeat; gint64 base; /* Sector comes from data or crc section */ if(sector < lay->protectedSectors) { *slice = sector / lay->sectorsPerLayer; *n = sector % lay->sectorsPerLayer; return; } /* Position of first ecc header repeat */ first_repeat = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo; first_repeat *= lay->headerModulo; /* Querying a header returns -1 for the slice and the header repeat number in n */ remainder = sector % lay->headerModulo; if(remainder < 2) { *slice = -1; *n = (sector-first_repeat) / lay->headerModulo; return; } /* Sector is an ecc sector and lies before first interleaved Ecc header */ if(sector < first_repeat) { *slice = lay->ndata + (sector-lay->protectedSectors)/lay->sectorsPerLayer; *n = (sector - lay->protectedSectors) % lay->sectorsPerLayer; return; } /* Sector is an ecc sector and lies behind the first interleaved Ecc header */ base = first_repeat - lay->protectedSectors; /* ecc sectors before first repeat */ sector -= first_repeat; sector -= 2; /* subtract first repeated header */ sector -= 2*(sector/(lay->headerModulo-0)); /* and other crossed repeats */ sector += base; /* add sectors before first repeat */ *slice = lay->ndata + sector / lay->sectorsPerLayer; *n = sector % lay->sectorsPerLayer; } /*** *** Calculation of the image layout ***/ /* * Calculate new layout for either a given medium size, * or from default media sizes. */ RS02Layout *CalcRS02Layout(Image *image) { RS02Layout *lay = g_malloc0(sizeof(RS02Layout)); guint64 ecc_area; int requested_roots = 0; lay->eh = image->eccHeader; /* If no medium size is given by the user, pick the smallest possible among CDR, single layer DVD and two layer DVD. */ if(Closure->mediumSize) lay->mediumCapacity = Closure->mediumSize; else { if(image->sectorSize < Closure->cdSize) lay->mediumCapacity = Closure->cdSize; /* CDR */ else if(image->sectorSize < Closure->dvdSize1) lay->mediumCapacity = Closure->dvdSize1; /* Single layered DVD */ else if(image->sectorSize < Closure->dvdSize2) lay->mediumCapacity = Closure->dvdSize2; /* Double layered DVD */ else if(image->sectorSize < Closure->bdSize1) lay->mediumCapacity = Closure->bdSize1; /* Single layered BD */ else if(image->sectorSize < Closure->bdSize2) lay->mediumCapacity = Closure->bdSize2; /* Double layered BD */ else if(image->sectorSize < Closure->bdSize3) lay->mediumCapacity = Closure->bdSize3; /* Triple layered BDXL */ else lay->mediumCapacity = Closure->bdSize4; /* Quadruple layered BDXL */ } lay->dataSectors = image->sectorSize; lay->firstEccHeader = lay->dataSectors; lay->crcSectors = (sizeof(guint32)*lay->dataSectors+2047)/2048; lay->protectedSectors = lay->dataSectors + 2 + lay->crcSectors; /* two sectors for header */ /* See if user wants to pick a certain redundancy */ #ifndef CLI if(!Closure->guiMode && Closure->redundancy) #else if(Closure->redundancy) #endif { int len = strlen(Closure->redundancy); switch(Closure->redundancy[len-1]) { case 'r': /* pick number of roots */ { char buf[len+1]; memcpy(buf, Closure->redundancy, len); buf[len] = '\0'; requested_roots = atoi(buf); break; } case '%': /* pick redundancy directly */ { char buf[len]; int percent; memcpy(buf, Closure->redundancy, len-1); buf[len-1] = '\0'; percent = atoi(buf); for(requested_roots = 7; requested_roots < 171; requested_roots++) { double redundancy = ((double)requested_roots*100.0)/((double)(GF_FIELDMAX-requested_roots)); if(redundancy >= percent) break; } if(requested_roots >170) requested_roots = 0; break; } } } /* Calculate starting value for the redundancy */ if(requested_roots > 0) lay->nroots = requested_roots; else { lay->rsSectors = lay->mediumCapacity - lay->protectedSectors; /* just to start */ lay->nroots = (GF_FIELDMAX*lay->rsSectors) / lay->mediumCapacity; /* iteration below */ } if(lay->nroots > 170) /* Cap redundancy to 200% */ lay->nroots = 170; if(lay->nroots < 0) lay->nroots = 0; /* Calculate the header repeat value so that we get about 20 to 40 copies of the header in the ecc section. */ lay->headerModulo = 32; lay->ndata = GF_FIELDMAX-lay->nroots; ecc_area = lay->nroots * ((lay->protectedSectors + lay->ndata - 1) / lay->ndata); while(ecc_area / lay->headerModulo > 40) lay->headerModulo <<= 1; /* Now assemble everything together and make sure it fits on the medium */ while(lay->nroots > 7) { gint64 first_repeat; /* first header which is interleaved with ecc sectors */ gint64 interleaved; /* number of ecc sectors after first header */ lay->ndata = GF_FIELDMAX-lay->nroots; lay->rsSectors = lay->nroots * ((lay->protectedSectors + lay->ndata - 1) / lay->ndata); first_repeat = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo; first_repeat *= lay->headerModulo; interleaved = lay->rsSectors + lay->protectedSectors - first_repeat; lay->headers = interleaved / (lay->headerModulo-2) + 1; lay->eccSectors = 2 + lay->crcSectors + lay->rsSectors + 2*lay->headers; lay->sectorsPerLayer = (lay->protectedSectors + lay->ndata - 1) / lay->ndata; lay->firstCrcLayerIndex = (2 + lay->dataSectors) % lay->sectorsPerLayer; if(requested_roots > 0) break; if(lay->eccSectors + lay->dataSectors <= lay->mediumCapacity) break; lay->nroots--; } lay->redundancy = ((double)lay->nroots*100.0)/(double)lay->ndata; Verbose("Calculated layout for RS02 image:\n"); Verbose("data sectors = %lld\n", lay->dataSectors); Verbose("crc sectors = %lld\n", lay->crcSectors); Verbose("protected sectors = %lld (incl. 2 hdr sectors)\n", lay->protectedSectors); Verbose("reed solomon secs = %lld (%d roots, %d data)\n", lay->rsSectors,lay->nroots,lay->ndata); Verbose("header repeats = %lld (using modulo %lld)\n", lay->headers, lay->headerModulo); Verbose("added sectors = %lld\n", lay->eccSectors); Verbose("total image size = %lld\n", lay->eccSectors+lay->dataSectors); if(requested_roots > 0) Verbose("medium capacity = n.a.\n"); else Verbose("medium capacity = %lld\n", lay->mediumCapacity); Verbose("\nInterleaving layout:\n"); Verbose("%lld sectors per ecc layer\n",lay->sectorsPerLayer); Verbose("first layer sector with CRC data %lld (sector# %lld)\n", lay->firstCrcLayerIndex, lay->dataSectors+2); Verbose("\n"); return lay; } /* * Determine expected size of image. */ guint64 RS02ExpectedImageSize(Image *image) { EccHeader *eh = image->eccHeader; RS02Layout *lay; guint64 size; if(!eh) return 0; lay = RS02LayoutFromImage(image); size = lay->eccSectors+lay->dataSectors; g_free(lay); return size; } /*** *** Write the RS02 headers into the image. ***/ void WriteRS02Headers(LargeFile *file, RS02Layout *lay, EccHeader *eh) { guint64 hpos; // guint64 end = lay->eccSectors+lay->dataSectors-2; guint64 end = lay->eccSectors+lay->dataSectors; int n; if(!LargeSeek(file, 2048*lay->firstEccHeader)) Stop(_("Failed seeking to ecc header at %lld: %s\n"), lay->firstEccHeader, strerror(errno)); n = LargeWrite(file, eh, sizeof(EccHeader)); if(n != sizeof(EccHeader)) Stop(_("Failed writing ecc header at %lld: %s\n"), lay->firstEccHeader, strerror(errno)); hpos = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo; hpos *= lay->headerModulo; while(hpos < end) { if(!LargeSeek(file, 2048*hpos)) Stop(_("Failed seeking to ecc header at %lld: %s\n"), hpos, strerror(errno)); n = LargeWrite(file, eh, sizeof(EccHeader)); if(n != sizeof(EccHeader)) Stop(_("Failed writing ecc header at %lld: %s\n"), hpos, strerror(errno)); hpos += lay->headerModulo; } } /* * Calculate layout properties from a given image and ecc header. */ static void calc_headers(RS02Layout *lay) { gint64 first_repeat; /* first header which is interleaved with ecc sectors */ gint64 interleaved; /* number of ecc sectors after first header */ first_repeat = (lay->protectedSectors + lay->headerModulo - 1) / lay->headerModulo; first_repeat *= lay->headerModulo; interleaved = lay->rsSectors + lay->protectedSectors - first_repeat; lay->headers = interleaved / (lay->headerModulo-2) + 1; lay->eccSectors = 2 + lay->crcSectors + lay->rsSectors + 2*lay->headers; } RS02Layout *RS02LayoutFromImage(Image *image) { RS02Layout *lay = g_malloc0(sizeof(RS02Layout)); EccHeader *eh = image->eccHeader; guint64 expected_size=0; guint64 expected_size2=0; /* See if layout has already been cached in the image */ if(image->cachedLayout) { Verbose("RS02LayoutFromImage(): returning cached layout\n"); memcpy(lay, image->cachedLayout, sizeof(RS02Layout)); return lay; } /* Invariant values taken from Image/EccHeader */ lay->eh = image->eccHeader; lay->dataSectors = uchar_to_gint64(eh->sectors); lay->firstEccHeader = lay->dataSectors; lay->crcSectors = (sizeof(guint32)*lay->dataSectors+2047)/2048; lay->protectedSectors = lay->dataSectors + 2 + lay->crcSectors; /* two sectors for header */ lay->nroots = eh->eccBytes; lay->ndata = eh->dataBytes; lay->redundancy = ((double)lay->nroots*100.0)/(double)lay->ndata; lay->sectorsPerLayer = (lay->protectedSectors + lay->ndata - 1) / lay->ndata; lay->rsSectors = lay->nroots * lay->sectorsPerLayer; lay->firstCrcLayerIndex = (2 + lay->dataSectors) % lay->sectorsPerLayer; /* Calculate the header repeat value so that we get about 20 to 40 copies of the header in the ecc section. */ lay->headerModulo = 32; while(lay->rsSectors / lay->headerModulo > 40) lay->headerModulo <<= 1; /* Now assemble everything together and make sure it fits on the medium */ calc_headers(lay); /* Due to a glitch in the layout calculation code when creating the image, lay->headerModulo is ambigous in a very few cases. See if this one is plausible, otherwise try the neighboring modulo. */ /* Size info is available since 0.79.5, allowing us to pick an authoritative choice. */ if(eh->sectorsAddedByEcc > 0) { expected_size = lay->dataSectors + eh->sectorsAddedByEcc; Verbose("Expected size calculated from ecc header: %lld\n", (long long int)expected_size); if(expected_size == lay->dataSectors+lay->eccSectors) { Verbose("--> confirmed layout variant 1\n"); } else { RS02Layout *lay2=g_malloc0(sizeof(RS02Layout)); memcpy(lay2, lay, sizeof(RS02Layout)); lay2->headerModulo <<=1; calc_headers(lay2); if(expected_size == lay2->dataSectors+lay2->eccSectors) { Verbose("--> confirmed layout variant 2\n"); memcpy(lay, lay2, sizeof(RS02Layout)); g_free(lay2); } else Verbose("--> FAIL: did not map to expected variants!\n"); } goto finish; } else Verbose("Pre-0.79.5 RS02 header.\n"); /* Decide heuristically. */ if(image->type == IMAGE_FILE) { expected_size = image->file->size>>11; Verbose("Expected size taken from image->file: %lld\n", (long long int)expected_size); } if(image->type == IMAGE_MEDIUM) { expected_size = image->dh->readCapacity+1; expected_size2 = image->dh->userAreaSize+1; Verbose("Expected size taken from image->dh: %lld/%lld\n", (long long int)expected_size, (long long int)expected_size2); } if( lay->eccSectors+lay->dataSectors != expected_size && lay->eccSectors+lay->dataSectors != expected_size2) { RS02Layout *lay2=g_malloc0(sizeof(RS02Layout)); int modulo_decided = FALSE; memcpy(lay2, lay, sizeof(RS02Layout)); lay2->headerModulo <<=1; calc_headers(lay2); if( lay2->eccSectors+lay2->dataSectors == expected_size || lay2->eccSectors+lay2->dataSectors == expected_size2) { memcpy(lay, lay2, sizeof(RS02Layout)); Verbose("NOTE: header modulo glitch fixed\n"); } else /* does not match either; probe at both modulos for headers */ { AlignedBuffer *ab = CreateAlignedBuffer(4096); gint64 s,remainder; gint64 max_size; /* We do not need to search further than to the predicted end of both possible layouts. */ expected_size = lay->eccSectors+lay->dataSectors; expected_size2 = lay2->eccSectors+lay2->dataSectors; max_size = MAX(expected_size, expected_size2); /* Position of first possible header (lay->headerModulo is less than lay2->headerModulo) */ remainder=lay->protectedSectors%lay->headerModulo; if(!remainder) s=lay->protectedSectors; else s=lay->protectedSectors-remainder+lay->headerModulo; if(!(s%lay2->headerModulo)) /* we want the smaller modulos "between" the larger ones */ s += lay->headerModulo; Verbose("Probing from %lld to %lld, modulos %lld, %lld\n", (long long int)s, (long long int)max_size, (long long int)lay->headerModulo, (long long int)lay2->headerModulo); /* Probe headers at the smaller modulo. */ while(s <= max_size) { if(ImageReadSectors(image, ab->buf, s, 2) != 2) { Verbose("... sector %lld not present\n", (long long int)s); } else { #ifdef HAVE_BIG_ENDIAN SwapEccHeaderBytes((EccHeader*)ab->buf); #endif if(!memcmp(eh, (EccHeader*)ab->buf, sizeof(EccHeader))) { Verbose("... sector %lld is a header -> choosing modulo %lld\n", (long long int)s, (long long int)lay->headerModulo); modulo_decided=TRUE; break; } else /* rewriteable media might contain garbage behind the actual image */ { if(s <= expected_size2) { Verbose("... sector %lld is NOT a header -> choosing modulo %lld\n", (long long int)s, (long long int)lay2->headerModulo); memcpy(lay, lay2, sizeof(RS02Layout)); modulo_decided=TRUE; break; } } } s += lay2->headerModulo; } if(!modulo_decided) /* did not resolve; continue with first modulo */ { Verbose("NOTE: possible UNRESOLVED header modulo glitch\n"); } FreeAlignedBuffer(ab); } g_free(lay2); /* either lay has won or has been copied over with lay2 */ } /* Generate debugging output in verbose mode */ finish: Verbose("Calculated layout for RS02 image:\n"); Verbose("data sectors = %lld\n", lay->dataSectors); Verbose("crc sectors = %lld\n", lay->crcSectors); Verbose("protected sectors = %lld (incl. 2 hdr sectors)\n", lay->protectedSectors); Verbose("reed solomon secs = %lld (%d roots, %d data)\n", lay->rsSectors,lay->nroots,lay->ndata); Verbose("header repeats = %lld (using modulo %lld)\n", lay->headers, lay->headerModulo); Verbose("added sectors = %lld\n", lay->eccSectors); Verbose("total image size = %lld\n", lay->eccSectors+lay->dataSectors); Verbose("medium capacity = n.a.\n"); Verbose("\nInterleaving layout:\n"); Verbose("%lld sectors per ecc layer\n",lay->sectorsPerLayer); Verbose("first layer sector with CRC data %lld (sector# %lld)\n", lay->firstCrcLayerIndex, lay->dataSectors+2); Verbose("\n"); image->cachedLayout = g_malloc(sizeof(RS02Layout)); memcpy(image->cachedLayout, lay, sizeof(RS02Layout)); return lay; }