"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "rs01-common.c" between
dvdisaster-0.79.3.tar.gz and dvdisaster-0.79.5.tar.gz

About: dvdisaster provides a margin of safety against data loss on CD, DVD and BD media caused by aging or scratches. Development version.

rs01-common.c  (dvdisaster-0.79.3):rs01-common.c  (dvdisaster-0.79.5)
/* dvdisaster: Additional error correction for optical media. /* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2010 Carsten Gnoerlich. * Copyright (C) 2004-2015 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
* *
* The Reed-Solomon error correction draws a lot of inspiration - and even code * Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org
- * Project homepage: http://www.dvdisaster.org
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fe
c/
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * dvdisaster is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/ */
#include "dvdisaster.h" #include "dvdisaster.h"
#include "rs01-includes.h" #include "rs01-includes.h"
/*** /***
*** Recognize a RS01 error correction file *** Recognize a RS01 error correction file
***/ ***/
int RS01Recognize(Method *self, LargeFile *ecc_file) int RS01Recognize(LargeFile *ecc_file, EccHeader **eh)
{ EccHeader eh; { int n;
int n;
*eh = g_malloc(sizeof(EccHeader));
LargeSeek(ecc_file, 0); LargeSeek(ecc_file, 0);
n = LargeRead(ecc_file, &eh, sizeof(EccHeader)); n = LargeRead(ecc_file, *eh, sizeof(EccHeader));
if(n != sizeof(EccHeader)) if(n != sizeof(EccHeader))
return FALSE; { g_free(*eh);
return ECCFILE_INVALID;
}
if(strncmp((char*)eh.cookie, "*dvdisaster*", 12)) if(strncmp((char*)(*eh)->cookie, "*dvdisaster*", 12))
return FALSE; { g_free(*eh);
return ECCFILE_DEFECTIVE_HEADER;
}
if(!strncmp((char*)eh.method, "RS01", 4)) if(!strncmp((char*)(*eh)->method, "RS01", 4))
return TRUE; {
#ifdef HAVE_BIG_ENDIAN
SwapEccHeaderBytes(*eh);
#endif
return ECCFILE_PRESENT;
}
return FALSE; g_free(*eh);
return ECCFILE_WRONG_CODEC;
}
/***
*** Read and buffer CRC information from RS01 file
***/
CrcBuf *RS01GetCrcBuf(Image *image)
{ LargeFile *file = image->eccFile;
CrcBuf *cb;
guint32 *buf;
guint64 image_sectors;
guint64 crc_sectors,crc_remainder;
guint64 i,j,sec_idx;
image_sectors = uchar_to_gint64(image->eccFileHeader->sectors);
cb = CreateCrcBuf(image_sectors);
buf = cb->crcbuf;
/* Seek to beginning of CRC sums */
if(!LargeSeek(file, (gint64)sizeof(EccHeader)))
Stop(_("Failed skipping the ecc header: %s"),strerror(errno));
/* Read crc sums. A sector of 2048 bytes contains 512 CRC sums. */
crc_sectors = image_sectors / 512;
sec_idx = 0;
for(i=0; i<crc_sectors; i++)
{ if(LargeRead(file, buf, 2048) != 2048)
Stop(_("Error reading CRC information: %s"),strerror(errno));
buf += 512;
for(j=0; j<512; j++, sec_idx++)
SetBit(cb->valid, sec_idx);
}
crc_remainder = sizeof(guint32)*(image_sectors % 512);
if(crc_remainder)
{ if(LargeRead(file, buf, crc_remainder) != crc_remainder)
Stop(_("Error reading CRC information: %s"),strerror(errno));
for( ; sec_idx<image_sectors; sec_idx++)
SetBit(cb->valid, sec_idx);
}
return cb;
}
/***
*** Internal checksum handling.
***
* Not overly complicated as we just have a global md5sum.
*/
void RS01ResetCksums(Image *image)
{ RS01CksumClosure *csc = (RS01CksumClosure*)image->eccFileMethod->ckSumClosure
;
MD5Init(&csc->md5ctxt);
}
void RS01UpdateCksums(Image *image, gint64 sector, unsigned char *buf)
{ RS01CksumClosure *csc = (RS01CksumClosure*)image->eccFileMethod->ckSumClosure
;
MD5Update(&csc->md5ctxt, buf, 2048);
}
int RS01FinalizeCksums(Image *image)
{ Method *self = image->eccFileMethod;
RS01CksumClosure *csc = (RS01CksumClosure*)self->ckSumClosure;
guint8 image_fp[16];
int good_fp;
MD5Final(image_fp, &csc->md5ctxt);
good_fp = !(memcmp(image_fp, image->eccFileHeader->mediumSum ,16));
if(good_fp)
return 0;
else return DATA_MD5_BAD;
} }
/*** /***
*** Read an image sector from the .iso file. *** Read an image sector from the .iso file.
**** ***
* Two special cases here: * Two special cases here:
* - Missing sectors (beyond the range recorded in eh->sectors) will be padded w ith zeros, * - Missing sectors (beyond the range recorded in eh->sectors) will be padded w ith zeros,
* since we need a multiple of ndata sectors for the parity generation. * since we need a multiple of ndata sectors for the parity generation.
* - Missing sectors beyond the range recorded in ii->sectors, but before the re al end * - Missing sectors beyond the range recorded in ii->sectors, but before the re al end
* as defined above are treated as "dead sectors". * as defined above are treated as "dead sectors".
*/ */
void RS01ReadSector(ImageInfo *ii, EccHeader *eh, unsigned char *buf, gint64 s) void RS01ReadSector(Image *image, unsigned char *buf, gint64 s)
{ gint64 eh_sectors = uchar_to_gint64(eh->sectors); { gint64 eh_sectors = uchar_to_gint64(image->eccFileHeader->sectors);
if(s >= ii->sectors && s < eh_sectors) if(s >= image->sectorSize && s < eh_sectors)
{ {
CreateMissingSector(buf, s, NULL, 0, NULL); /* truncated image */ CreateMissingSector(buf, s, NULL, 0, NULL); /* truncated image */
} }
else if(s >= eh_sectors) else if(s >= eh_sectors)
{ {
memset(buf, 0, 2048); /* zero padding for reads past the image * / memset(buf, 0, 2048); /* zero padding for reads past the image * /
} }
else /* else normal read within the image */ else /* else normal read within the image */
{ int n,expected; { int n,expected;
if(!LargeSeek(ii->file, (gint64)(2048*s))) if(!LargeSeek(image->file, (gint64)(2048*s)))
Stop(_("Failed seeking to sector %lld in image: %s"), Stop(_("Failed seeking to sector %lld in image: %s"),
s, strerror(errno)); s, strerror(errno));
/* Prepare for short reads at the last image sector. /* Prepare for short reads at the last image sector.
Doesn't happen for CD and DVD media, but perhaps for future media? */ Doesn't happen for CD and DVD media, but perhaps for future media? */
if(s < ii->sectors-1) expected = 2048; if(s < image->sectorSize-1) expected = 2048;
else else
{ memset(buf, 0, 2048); { memset(buf, 0, 2048);
expected = ii->inLast; expected = image->inLast;
} }
/* Finally, read the sector */ /* Finally, read the sector */
n = LargeRead(ii->file, buf, expected); n = LargeRead(image->file, buf, expected);
if(n != expected) if(n != expected)
Stop(_("Failed reading sector %lld in image: %s"),s,strerror(errno)); Stop(_("Failed reading sector %lld in image: %s"),s,strerror(errno));
} }
} }
/* /*
* Scan the image for missing blocks. * Scan the image for missing blocks.
* If the ecc file is present, also compare the CRC sums. * If the ecc file is present, also compare the CRC sums.
* If CREATE_CRC is requested, calculate the CRC sums. * If CREATE_CRC is requested, calculate the CRC sums.
* *
* Actually this should be usable for all RS01 type ecc files. * Actually this should be usable for all RS01 type ecc files.
* But unless we have more than one codec, we'll label it as * But unless we have more than one codec, we'll label it as
* as RS01 specific method. * as RS01 specific method.
*/ */
#define CRCBUFSIZE (1024*256) #define CRCBUFSIZE (1024*256)
void RS01ScanImage(Method *method, ImageInfo *ii, EccInfo *ei, int mode) void RS01ScanImage(Method *method, Image* image, struct MD5Context *ecc_ctxt, in t mode)
{ RS01Widgets *wl = NULL; { RS01Widgets *wl = NULL;
EccHeader eh;
unsigned char buf[2048]; unsigned char buf[2048];
guint32 *crcbuf = NULL; guint32 *crcbuf = NULL;
int unrecoverable_sectors = 0;
int crcidx = 0; int crcidx = 0;
struct MD5Context image_md5; struct MD5Context image_md5;
gint64 eh_sectors = 0;
gint64 s, first_missing, last_missing; gint64 s, first_missing, last_missing;
gint64 prev_missing = 0; gint64 prev_missing = 0;
gint64 prev_crc_errors = 0; gint64 prev_crc_errors = 0;
int last_percent,current_missing; int last_percent,current_missing;
int fp_sector = FINGERPRINT_SECTOR;
char *msg; char *msg;
/* Extract widget list from method */ /* Extract widget list from method */
if(method->widgetList) if(method->widgetList)
wl = (RS01Widgets*)method->widgetList; wl = (RS01Widgets*)method->widgetList;
/* Read the ecc file header */
if(ei && mode != CREATE_CRC)
{ LargeSeek(ei->file, 0);
LargeRead(ei->file, &eh, sizeof(EccHeader));
eh_sectors = uchar_to_gint64(eh.sectors);
fp_sector = eh.fpSector;
}
/* Position behind the ecc file header, /* Position behind the ecc file header,
initialize CRC buffer pointers */ initialize CRC buffer pointers */
if(ei) if(image->eccFile)
{ if(!LargeSeek(ei->file, (gint64)sizeof(EccHeader))) { if(!LargeSeek(image->eccFile, (gint64)sizeof(EccHeader)))
Stop(_("Failed skipping the ecc header: %s"),strerror(errno)); Stop(_("Failed skipping the ecc header: %s"),strerror(errno));
crcbuf = g_malloc(sizeof(guint32) * CRCBUFSIZE); crcbuf = g_malloc(sizeof(guint32) * CRCBUFSIZE);
crcidx = (mode & CREATE_CRC) ? 0 : CRCBUFSIZE; crcidx = (mode & CREATE_CRC) ? 0 : CRCBUFSIZE;
MD5Init(&ei->md5Ctxt); /* md5sum of CRC portion of ecc file */ if(mode & CREATE_CRC)
MD5Init(ecc_ctxt); /* md5sum of CRC portion of ecc file */
} }
/* Prepare for scanning the image and calculating its md5sum */ /* Prepare for scanning the image and calculating its md5sum */
MD5Init(&image_md5); /* md5sum of image file itself */ MD5Init(&image_md5); /* md5sum of image file itself */
LargeSeek(ii->file, 0); /* rewind image file */ LargeSeek(image->file, 0); /* rewind image file */
if(mode & PRINT_MODE) if(mode & PRINT_MODE)
msg = _("- testing sectors : %3d%%"); msg = _("- testing sectors : %3d%%");
else msg = _("Scanning image sectors: %3d%%"); else msg = _("Scanning image sectors: %3d%%");
last_percent = 0; last_percent = 0;
ii->sectorsMissing = 0; image->sectorsMissing = 0;
first_missing = last_missing = -1; first_missing = last_missing = -1;
/* Go through all sectors and look for the "dead sector marker" */ /* Go through all sectors and look for the "dead sector marker" */
for(s=0; s<ii->sectors; s++) for(s=0; s<image->sectorSize; s++)
{ int n,percent,err; { int n,percent,err;
/* Check for user interruption */ /* Check for user interruption */
if(Closure->stopActions) if(Closure->stopActions)
{ ii->sectorsMissing += ii->sectors - s; { image->sectorsMissing += image->sectorSize - s;
if(crcbuf) g_free(crcbuf); if(crcbuf) g_free(crcbuf);
return; return;
} }
/* Read the next sector */ /* Read the next sector */
n = LargeRead(ii->file, buf, 2048); n = LargeRead(image->file, buf, 2048);
if(n != 2048) if(n != 2048)
{ if(s != ii->sectors - 1 || n != ii->inLast) { if(s != image->sectorSize - 1 || n != image->inLast)
{ if(crcbuf) g_free(crcbuf); { if(crcbuf) g_free(crcbuf);
Stop(_("premature end in image (only %d bytes): %s\n"),n,strerror(err no)); Stop(_("premature end in image (only %d bytes): %s\n"),n,strerror(err no));
} }
else /* Zero unused sectors for CRC generation */ else /* Zero unused sectors for CRC generation */
memset(buf+ii->inLast, 0, 2048-ii->inLast); memset(buf+image->inLast, 0, 2048-image->inLast);
} }
/* Look for the dead sector marker */ /* Look for the dead sector marker */
err = CheckForMissingSector(buf, s, ii->fpValid ? ii->mediumFP : NULL, FIN err = CheckForMissingSector(buf, s, image->fpState == 2 ? image->imageFP :
GERPRINT_SECTOR); NULL,
FINGERPRINT_SECTOR);
if(err != SECTOR_PRESENT) if(err != SECTOR_PRESENT)
{ current_missing = TRUE; { current_missing = TRUE;
ExplainMissingSector(buf, s, err, TRUE); ExplainMissingSector(buf, s, err, SOURCE_IMAGE, &unrecoverable_sectors);
} }
else current_missing = FALSE; else current_missing = FALSE;
if(current_missing) if(current_missing)
{ if(first_missing < 0) first_missing = s; { if(first_missing < 0) first_missing = s;
last_missing = s; last_missing = s;
ii->sectorsMissing++; image->sectorsMissing++;
} }
/* Report dead sectors. Combine subsequent missing sectors into one report . */ /* Report dead sectors. Combine subsequent missing sectors into one report . */
if(mode & PRINT_MODE) if(mode & PRINT_MODE)
if(!current_missing || s==ii->sectors-1) if(!current_missing || s==image->sectorSize-1)
{ if(first_missing>=0) { if(first_missing>=0)
{ if(first_missing == last_missing) { if(first_missing == last_missing)
PrintCLI(_("* missing sector : %lld\n"), first_missing); PrintCLI(_("* missing sector : %lld\n"), first_missing);
else PrintCLI(_("* missing sectors : %lld - %lld\n"), first_miss ing, last_missing); else PrintCLI(_("* missing sectors : %lld - %lld\n"), first_miss ing, last_missing);
first_missing = -1; first_missing = -1;
} }
} }
if(ei) /* Do something with the CRC portion of the .ecc file */ if(image->eccFile) /* Do something with the CRC portion of the .ecc file * /
{ {
/* If creation of the CRC32 is requested, do that. */ /* If creation of the CRC32 is requested, do that. */
if(mode & CREATE_CRC) if(mode & CREATE_CRC)
{ crcbuf[crcidx++] = Crc32(buf, 2048); { crcbuf[crcidx++] = Crc32(buf, 2048);
if(crcidx >= CRCBUFSIZE) /* write out CRC buffer contents */ if(crcidx >= CRCBUFSIZE) /* write out CRC buffer contents */
{ size_t size = CRCBUFSIZE*sizeof(guint32); { size_t size = CRCBUFSIZE*sizeof(guint32);
MD5Update(&ei->md5Ctxt, (unsigned char*)crcbuf, size); MD5Update(ecc_ctxt, (unsigned char*)crcbuf, size);
if(LargeWrite(ei->file, crcbuf, size) != size) if(LargeWrite(image->eccFile, crcbuf, size) != size)
{ if(crcbuf) g_free(crcbuf); { if(crcbuf) g_free(crcbuf);
Stop(_("Error writing CRC information: %s"),strerror(errno)); Stop(_("Error writing CRC information: %s"),strerror(errno));
} }
crcidx = 0; crcidx = 0;
} }
} }
/* else do the CRC32 check. Missing sectors are skipped in the CRC repor t. */ /* else do the CRC32 check. Missing sectors are skipped in the CRC repor t. */
else if(s < eh_sectors) else if(s < image->expectedSectors)
{ guint32 crc = Crc32(buf, 2048); { guint32 crc = Crc32(buf, 2048);
/* If the CRC buf is exhausted, refill. */ /* If the CRC buf is exhausted, refill. */
if(crcidx >= CRCBUFSIZE) if(crcidx >= CRCBUFSIZE)
{ size_t remain = ii->sectors-s; { size_t remain = image->sectorSize-s;
size_t size; size_t size;
if(remain < CRCBUFSIZE) if(remain < CRCBUFSIZE)
size = remain*sizeof(guint32); size = remain*sizeof(guint32);
else size = CRCBUFSIZE*sizeof(guint32); else size = CRCBUFSIZE*sizeof(guint32);
if(LargeRead(ei->file, crcbuf, size) != size) if(LargeRead(image->eccFile, crcbuf, size) != size)
{ if(crcbuf) g_free(crcbuf); { if(crcbuf) g_free(crcbuf);
Stop(_("Error reading CRC information: %s"),strerror(errno)); Stop(_("Error reading CRC information: %s"),strerror(errno));
} }
crcidx = 0; crcidx = 0;
} }
if(crc != crcbuf[crcidx++] && !current_missing) if(crc != crcbuf[crcidx++] && !current_missing)
{ PrintCLI(_("* CRC error, sector: %lld\n"), s); { PrintCLI(_("* CRC error, sector: %lld\n"), s);
ii->crcErrors++; image->crcErrors++;
} }
} }
} }
MD5Update(&image_md5, buf, n); /* update image md5sum */ MD5Update(&image_md5, buf, n); /* update image md5sum */
if(Closure->guiMode && mode & PRINT_MODE) if(Closure->guiMode && mode & PRINT_MODE)
percent = (VERIFY_IMAGE_SEGMENTS*(s+1))/ii->sectors; percent = (VERIFY_IMAGE_SEGMENTS*(s+1))/image->sectorSize;
else percent = (100*(s+1))/ii->sectors; else percent = (100*(s+1))/image->sectorSize;
if(last_percent != percent) if(last_percent != percent)
{ PrintProgress(msg,percent); { PrintProgress(msg,percent);
if(Closure->guiMode && mode & CREATE_CRC) if(Closure->guiMode && mode & CREATE_CRC)
SetProgress(wl->encPBar1, percent, 100); SetProgress(wl->encPBar1, percent, 100);
if(Closure->guiMode && mode & PRINT_MODE) if(Closure->guiMode && mode & PRINT_MODE)
{ RS01AddVerifyValues(method, percent, ii->sectorsMissing, ii->crcError { RS01AddVerifyValues(method, percent, image->sectorsMissing, image->cr
s, cErrors,
ii->sectorsMissing - prev_missing, image->sectorsMissing - prev_missing,
ii->crcErrors - prev_crc_errors); image->crcErrors - prev_crc_errors);
prev_missing = ii->sectorsMissing; prev_missing = image->sectorsMissing;
prev_crc_errors = ii->crcErrors; prev_crc_errors = image->crcErrors;
} }
last_percent = percent; last_percent = percent;
} }
} }
/*** Flush the rest of the CRC buffer */ /*** Flush the rest of the CRC buffer */
if((mode & CREATE_CRC) && crcidx) if((mode & CREATE_CRC) && crcidx)
{ size_t size = crcidx*sizeof(guint32); { size_t size = crcidx*sizeof(guint32);
MD5Update(&ei->md5Ctxt, (unsigned char*)crcbuf, size); MD5Update(ecc_ctxt, (unsigned char*)crcbuf, size);
if(LargeWrite(ei->file, crcbuf, size) != size) if(LargeWrite(image->eccFile, crcbuf, size) != size)
{ if(crcbuf) g_free(crcbuf); { if(crcbuf) g_free(crcbuf);
Stop(_("Error writing CRC information: %s"),strerror(errno)); Stop(_("Error writing CRC information: %s"),strerror(errno));
} }
} }
/*** The image md5sum can only be calculated if all blocks have been successf ully read. */ /*** The image md5sum can only be calculated if all blocks have been successf ully read. */
MD5Final(ii->mediumSum, &image_md5); MD5Final(image->mediumSum, &image_md5);
LargeSeek(ii->file, 0); LargeSeek(image->file, 0);
if(crcbuf) g_free(crcbuf); if(crcbuf) g_free(crcbuf);
} }
/***
*** Determine expected size of image
***/
guint64 RS01ExpectedImageSize(Image *image)
{ EccHeader *eh = image->eccFileHeader;
if(!eh) return 0;
return uchar_to_gint64(eh->sectors);
}
 End of changes. 51 change blocks. 
78 lines changed or deleted 158 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS