New upstream version 0.79.5
This commit is contained in:
157
rs01-fix.c
157
rs01-fix.c
@@ -1,25 +1,26 @@
|
||||
/* dvdisaster: Additional error correction for optical media.
|
||||
* Copyright (C) 2004-2012 Carsten Gnoerlich.
|
||||
* Project home page: http://www.dvdisaster.com
|
||||
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
||||
* Copyright (C) 2004-2015 Carsten Gnoerlich.
|
||||
*
|
||||
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
|
||||
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (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
|
||||
* 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
||||
* or direct your browser at http://www.gnu.org.
|
||||
* along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dvdisaster.h"
|
||||
@@ -56,10 +57,9 @@ typedef struct
|
||||
{ RS01Widgets *wl;
|
||||
GaloisTables *gt;
|
||||
ReedSolomonTables *rt;
|
||||
Image *image;
|
||||
int earlyTermination;
|
||||
char *msg;
|
||||
ImageInfo *ii;
|
||||
EccInfo *ei;
|
||||
unsigned char *imgBlock[256];
|
||||
guint32 *crcBuf[256];
|
||||
} fix_closure;
|
||||
@@ -68,7 +68,7 @@ static void fix_cleanup(gpointer data)
|
||||
{ fix_closure *fc = (fix_closure*)data;
|
||||
int i;
|
||||
|
||||
Closure->cleanupProc = NULL;
|
||||
UnregisterCleanup();
|
||||
|
||||
if(Closure->guiMode)
|
||||
{ if(fc->earlyTermination)
|
||||
@@ -81,9 +81,8 @@ static void fix_cleanup(gpointer data)
|
||||
|
||||
/** Clean up */
|
||||
|
||||
if(fc->image) CloseImage(fc->image);
|
||||
if(fc->msg) g_free(fc->msg);
|
||||
if(fc->ii) FreeImageInfo(fc->ii);
|
||||
if(fc->ei) FreeEccInfo(fc->ei);
|
||||
|
||||
for(i=0; i<256; i++)
|
||||
{ if(fc->imgBlock[i])
|
||||
@@ -105,23 +104,21 @@ static void fix_cleanup(gpointer data)
|
||||
* Try to repair the image
|
||||
*/
|
||||
|
||||
void RS01Fix(Method *method)
|
||||
{ RS01Widgets *wl = (RS01Widgets*)method->widgetList;
|
||||
void RS01Fix(Image *image)
|
||||
{ Method *method = FindMethod("RS01");
|
||||
RS01Widgets *wl = (RS01Widgets*)method->widgetList;
|
||||
GaloisTables *gt;
|
||||
ReedSolomonTables *rt;
|
||||
fix_closure *fc = g_malloc0(sizeof(fix_closure));
|
||||
ImageInfo *ii = NULL;
|
||||
EccInfo *ei = NULL;
|
||||
EccHeader *eh = NULL;
|
||||
unsigned char parity[256];
|
||||
int erasure_count,erasure_list[256],erasure_map[256];
|
||||
int unexpected_failure;
|
||||
gint64 block_idx[256];
|
||||
gint64 s,si;
|
||||
int i,j,k,n;
|
||||
gint64 corrected, uncorrected;
|
||||
gint64 last_corrected, last_uncorrected;
|
||||
gint64 parity_block = 0;
|
||||
guint64 expected_image_size;
|
||||
int worst_ecc,damaged_ecc,damaged_sec,percent,last_percent = -1;
|
||||
int cache_size,cache_sector,cache_offset = 0;
|
||||
int local_plot_max;
|
||||
@@ -133,20 +130,12 @@ void RS01Fix(Method *method)
|
||||
|
||||
/*** Register the cleanup procedure for GUI mode */
|
||||
|
||||
fc->image = image;
|
||||
fc->wl = wl;
|
||||
fc->earlyTermination = TRUE;
|
||||
RegisterCleanup(_("Repairing of image aborted"), fix_cleanup, fc);
|
||||
|
||||
/*** Open the image and ecc files */
|
||||
|
||||
if(Closure->guiMode)
|
||||
SetLabelText(GTK_LABEL(wl->fixHeadline),
|
||||
_("<big>Repairing the image.</big>\n<i>%s</i>"),
|
||||
_("Opening files..."));
|
||||
|
||||
ei = fc->ei = OpenEccFile(READABLE_ECC);
|
||||
eh = ei->eh;
|
||||
ii = fc->ii = OpenImageFile(eh, WRITEABLE_IMAGE);
|
||||
eh = image->eccFileHeader;
|
||||
|
||||
/*** Announce what we are going to do. */
|
||||
|
||||
@@ -157,19 +146,44 @@ void RS01Fix(Method *method)
|
||||
if(Closure->guiMode)
|
||||
{ SetLabelText(GTK_LABEL(wl->fixHeadline),
|
||||
_("<big>Repairing the image.</big>\n<i>%s</i>"),fc->msg);
|
||||
RS01SetFixMaxValues(wl, eh->dataBytes, eh->eccBytes, ii->sectors);
|
||||
RS01SetFixMaxValues(wl, eh->dataBytes, eh->eccBytes, image->sectorSize);
|
||||
}
|
||||
|
||||
PrintLog(_("\nFix mode: Repairable sectors will be fixed in the image.\n"));
|
||||
PrintLog(_("\nFix mode(%s): Repairable sectors will be fixed in the image.\n"),
|
||||
"RS01");
|
||||
|
||||
/*** Do some trivial comparisons between the .ecc file and the image file */
|
||||
|
||||
if(!eh->inLast) /* field is unused/zero in versions prior to 0.66 */
|
||||
eh->inLast = 2048;
|
||||
|
||||
if(ii->sectors > ei->sectors)
|
||||
{ gint64 diff = ii->sectors - ei->sectors;
|
||||
gint64 wanted_size = 2048LL*(ei->sectors-1LL) + (gint64)eh->inLast;
|
||||
expected_image_size = 2048*(image->expectedSectors-1)+eh->inLast;
|
||||
|
||||
/* Special case: If the iso file is a few bytes too short
|
||||
or too long, and the last bytes are zeroes, the
|
||||
codec won't discover the mismatch from the CRC sum.
|
||||
Fill up the missing bytes with zeroes here; this
|
||||
will either be correct or picked up by the CRC
|
||||
compare later. */
|
||||
|
||||
if(image->sectorSize == image->expectedSectors
|
||||
&& image->inLast < eh->inLast)
|
||||
{ int padding = eh->inLast - image->inLast;
|
||||
unsigned char buf[padding];
|
||||
int n;
|
||||
|
||||
memset(buf, 0, padding);
|
||||
LargeSeek(image->file, image->file->size);
|
||||
n = LargeWrite(image->file, buf, padding);
|
||||
image->file->size += n;
|
||||
image->inLast += n;
|
||||
if(n != padding)
|
||||
Stop(_("Failed writing to sector %lld in image [%s]: %s"),
|
||||
image->sectorSize, "SC", strerror(errno));
|
||||
}
|
||||
|
||||
if(image->file->size > expected_image_size)
|
||||
{ gint64 diff = image->sectorSize - image->expectedSectors;
|
||||
char *trans = _("The image file is %lld sectors longer as noted in the\n"
|
||||
"ecc file. This might simply be zero padding, especially\n"
|
||||
"on dual layer DVD media, but could also mean that\n"
|
||||
@@ -191,10 +205,10 @@ void RS01Fix(Method *method)
|
||||
goto terminate;
|
||||
}
|
||||
|
||||
ii->sectors -= diff;
|
||||
ii->inLast = eh->inLast;
|
||||
image->sectorSize -= diff;
|
||||
image->inLast = eh->inLast;
|
||||
|
||||
if(!LargeTruncate(ii->file, wanted_size))
|
||||
if(!LargeTruncate(image->file, expected_image_size))
|
||||
Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
|
||||
}
|
||||
|
||||
@@ -213,10 +227,10 @@ void RS01Fix(Method *method)
|
||||
goto terminate;
|
||||
}
|
||||
|
||||
ii->sectors -= diff;
|
||||
ii->inLast = eh->inLast;
|
||||
image->sectorSize -= diff;
|
||||
image->inLast = eh->inLast;
|
||||
|
||||
if(!LargeTruncate(ii->file, wanted_size))
|
||||
if(!LargeTruncate(image->file, expected_image_size))
|
||||
Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
|
||||
|
||||
PrintLog(_("Image has been truncated by %lld sectors.\n"), diff);
|
||||
@@ -229,24 +243,23 @@ void RS01Fix(Method *method)
|
||||
_("Add the --truncate option to the program call\n"
|
||||
"to have the superfluous sectors removed."));
|
||||
|
||||
ii->sectors -= diff;
|
||||
ii->inLast = eh->inLast;
|
||||
image->sectorSize -= diff;
|
||||
image->inLast = eh->inLast;
|
||||
|
||||
if(!LargeTruncate(ii->file, wanted_size))
|
||||
if(!LargeTruncate(image->file, expected_image_size))
|
||||
Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
|
||||
|
||||
PrintLog(_("Image has been truncated by %lld sectors.\n"), diff);
|
||||
}
|
||||
}
|
||||
|
||||
if(ii->sectors == ei->sectors && ii->inLast > eh->inLast)
|
||||
{ int difference = ii->inLast - eh->inLast;
|
||||
gint64 wanted_size = 2048LL*(ei->sectors-1LL) + (gint64)eh->inLast;
|
||||
if(image->sectorSize == image->expectedSectors && image->inLast > eh->inLast)
|
||||
{ int difference = image->inLast - eh->inLast;
|
||||
|
||||
if(Closure->guiMode)
|
||||
{ int answer = ModalDialog(GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, NULL,
|
||||
_("The image file is %d bytes longer than noted\n"
|
||||
"in the ecc file. Shall the superflous bytes\n"
|
||||
"in the ecc file. Shall the superfluous bytes\n"
|
||||
"be removed from the image file?\n"),
|
||||
difference);
|
||||
|
||||
@@ -267,14 +280,14 @@ void RS01Fix(Method *method)
|
||||
"to have the superfluous sectors removed."),
|
||||
difference);
|
||||
|
||||
if(!LargeTruncate(ii->file, wanted_size))
|
||||
if(!LargeTruncate(image->file, expected_image_size))
|
||||
Stop(_("Could not truncate %s: %s\n"),Closure->imageName,strerror(errno));
|
||||
|
||||
PrintLog(_("Image has been truncated by %d bytes.\n"), difference);
|
||||
ii->inLast = eh->inLast;
|
||||
image->inLast = eh->inLast;
|
||||
}
|
||||
|
||||
if(ii->sectors < ei->sectors)
|
||||
if(image->sectorSize < image->expectedSectors)
|
||||
{ int answer;
|
||||
|
||||
answer = ModalWarning(GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, NULL,
|
||||
@@ -290,7 +303,7 @@ void RS01Fix(Method *method)
|
||||
}
|
||||
}
|
||||
|
||||
if(!memcmp(ii->mediumFP, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16))
|
||||
if(image->fpState != FP_PRESENT)
|
||||
{ int answer;
|
||||
|
||||
answer = ModalWarning(GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, NULL,
|
||||
@@ -306,7 +319,7 @@ void RS01Fix(Method *method)
|
||||
goto terminate;
|
||||
}
|
||||
}
|
||||
else if(memcmp(ii->mediumFP, eh->mediumFP, 16))
|
||||
else if(memcmp(image->imageFP, eh->mediumFP, 16))
|
||||
Stop(_("Fingerprints of image and ecc file do not match.\n"
|
||||
"Image and ecc file do not belong together.\n"));
|
||||
|
||||
@@ -325,7 +338,7 @@ void RS01Fix(Method *method)
|
||||
Our ecc blocks are built from ndata medium sectors spread over the full medium size.
|
||||
We read cache_size * ndata medium sectors ahead. */
|
||||
|
||||
cache_size = 2*Closure->cacheMB; /* ndata medium sectors are approx. 0.5MB */
|
||||
cache_size = 2*Closure->cacheMiB; /* ndata medium sectors are approx. 0.5MiB */
|
||||
|
||||
for(i=0; i<ndata; i++)
|
||||
{ fc->imgBlock[i] = g_malloc(cache_size*2048);
|
||||
@@ -335,7 +348,7 @@ void RS01Fix(Method *method)
|
||||
/*** Setup the block counters for mapping medium sectors to
|
||||
ecc blocks */
|
||||
|
||||
s = (ei->sectors+ndata-1)/ndata;
|
||||
s = (image->expectedSectors+ndata-1)/ndata;
|
||||
|
||||
for(si=0, i=0; i<ndata; si+=s, i++)
|
||||
block_idx[i] = si;
|
||||
@@ -345,16 +358,16 @@ void RS01Fix(Method *method)
|
||||
/*** Verify ecc information for the medium image. */
|
||||
|
||||
corrected = uncorrected = 0;
|
||||
last_corrected = last_uncorrected = 0;
|
||||
worst_ecc = damaged_ecc = damaged_sec = local_plot_max = 0;
|
||||
|
||||
for(si=0; si<s; si++)
|
||||
{
|
||||
if(Closure->stopActions) /* User hit the Stop button */
|
||||
{ SwitchAndSetFootline(fc->wl->fixNotebook, 1,
|
||||
fc->wl->fixFootline,
|
||||
_("<span %s>Aborted by user request!</span>"),
|
||||
Closure->redMarkup);
|
||||
{ if(Closure->stopActions == STOP_CURRENT_ACTION) /* suppress memleak warning when closing window */
|
||||
SwitchAndSetFootline(fc->wl->fixNotebook, 1,
|
||||
fc->wl->fixFootline,
|
||||
_("<span %s>Aborted by user request!</span>"),
|
||||
Closure->redMarkup);
|
||||
fc->earlyTermination = FALSE; /* suppress respective error message */
|
||||
goto terminate;
|
||||
}
|
||||
@@ -369,10 +382,10 @@ void RS01Fix(Method *method)
|
||||
for(i=0; i<ndata; i++)
|
||||
{ int offset = 0;
|
||||
for(j=0; j<cache_size; j++)
|
||||
{ RS01ReadSector(ii, eh, fc->imgBlock[i]+offset, block_idx[i]+j);
|
||||
{ RS01ReadSector(image, fc->imgBlock[i]+offset, block_idx[i]+j);
|
||||
offset += 2048;
|
||||
}
|
||||
read_crc(ei->file, fc->crcBuf[i], block_idx[i], cache_size);
|
||||
read_crc(image->eccFile, fc->crcBuf[i], block_idx[i], cache_size);
|
||||
}
|
||||
cache_sector = cache_offset = 0;
|
||||
}
|
||||
@@ -380,14 +393,13 @@ void RS01Fix(Method *method)
|
||||
/* Determine erasures based on the "dead sector" marker */
|
||||
|
||||
erasure_count = 0;
|
||||
unexpected_failure = 0;
|
||||
|
||||
for(i=0; i<ndata; i++)
|
||||
{ guint32 crc = Crc32(fc->imgBlock[i]+cache_offset, 2048);
|
||||
|
||||
erasure_map[i] = 0;
|
||||
|
||||
if(block_idx[i] < ei->sectors) /* ignore the padding sectors! */
|
||||
if(block_idx[i] < image->expectedSectors) /* ignore the padding sectors! */
|
||||
{ int err=CheckForMissingSector(fc->imgBlock[i]+cache_offset, block_idx[i], NULL, 0);
|
||||
|
||||
if(err != SECTOR_PRESENT)
|
||||
@@ -440,16 +452,16 @@ void RS01Fix(Method *method)
|
||||
{ gint64 idx = block_idx[erasure_list[i]];
|
||||
unsigned char buf[2048];
|
||||
|
||||
if(idx < ii->sectors)
|
||||
if(idx < image->sectorSize)
|
||||
continue; /* It's (already) dead, Jim ;-) */
|
||||
|
||||
if(!LargeSeek(ii->file, (gint64)(2048*idx)))
|
||||
if(!LargeSeek(image->file, (gint64)(2048*idx)))
|
||||
Stop(_("Failed seeking to sector %lld in image [%s]: %s"),
|
||||
idx, "FD", strerror(errno));
|
||||
|
||||
CreateMissingSector(buf, idx, eh->mediumFP, eh->fpSector, NULL);
|
||||
|
||||
n = LargeWrite(ii->file, buf, 2048);
|
||||
n = LargeWrite(image->file, buf, 2048);
|
||||
if(n != 2048)
|
||||
Stop(_("Failed writing to sector %lld in image [%s]: %s"),
|
||||
idx, "WD", strerror(errno));
|
||||
@@ -469,10 +481,10 @@ void RS01Fix(Method *method)
|
||||
|
||||
/* Read the parity bytes */
|
||||
|
||||
if(!LargeSeek(ei->file, (gint64)(sizeof(EccHeader) + ei->sectors*sizeof(guint32) + nroots*parity_block)))
|
||||
if(!LargeSeek(image->eccFile, (gint64)(sizeof(EccHeader) + image->expectedSectors*sizeof(guint32) + nroots*parity_block)))
|
||||
Stop(_("Failed seeking in ecc area: %s"), strerror(errno));
|
||||
|
||||
n = LargeRead(ei->file, parity, nroots);
|
||||
n = LargeRead(image->eccFile, parity, nroots);
|
||||
if(n != nroots)
|
||||
Stop(_("Can't read ecc file:\n%s"),strerror(errno));
|
||||
parity_block++;
|
||||
@@ -703,14 +715,14 @@ void RS01Fix(Method *method)
|
||||
|
||||
/* Write the recovered sector */
|
||||
|
||||
if(!LargeSeek(ii->file, (gint64)(2048*idx)))
|
||||
if(!LargeSeek(image->file, (gint64)(2048*idx)))
|
||||
Stop(_("Failed seeking to sector %lld in image [%s]: %s"),
|
||||
idx, "FW", strerror(errno));
|
||||
|
||||
if(idx < ei->sectors-1) length = 2048;
|
||||
if(idx < image->expectedSectors-1) length = 2048;
|
||||
else length = eh->inLast;
|
||||
|
||||
n = LargeWrite(ii->file, cache_offset+fc->imgBlock[erasure_list[i]], length);
|
||||
n = LargeWrite(image->file, cache_offset+fc->imgBlock[erasure_list[i]], length);
|
||||
if(n != length)
|
||||
Stop(_("could not write medium sector %lld:\n%s"),idx,strerror(errno));
|
||||
}
|
||||
@@ -735,7 +747,6 @@ skip:
|
||||
RS01AddFixValues(wl, percent, local_plot_max);
|
||||
local_plot_max = 0;
|
||||
|
||||
//if(last_corrected != corrected || last_uncorrected != uncorrected)
|
||||
RS01UpdateFixResults(wl, corrected, uncorrected);
|
||||
}
|
||||
else PrintProgress(_("Ecc progress: %3d.%1d%%"),percent/10,percent%10);
|
||||
|
||||
Reference in New Issue
Block a user