First attempt at a second-pass option, although it does not seem successful for the time being

This commit is contained in:
Vincent Fourmond 2013-01-02 23:43:47 +01:00
parent 3a53962ed2
commit f0bc221382
3 changed files with 145 additions and 12 deletions

View file

@ -32,6 +32,9 @@
#include <sys/time.h>
// use of regular expressions !
#include <regex.h>
#define BUF_BLOCK_SIZE 128
@ -134,11 +137,15 @@ void DVDCopy::copyFile(const DVDFileData * dat, int firstBlock,
outfile.seek(current_size);
size -= current_size;
printf("File already partially read: using %d sectors\n",
current_size);
const char * fmt =
(firstBlock > 0 ?
"Partial read starting at sector %d\n":
"File already partially read: using %d sectors\n");
printf(fmt, current_size);
}
if(blockNumber > 0)
size = current_size + blockNumber; // we read only the relevant portion
size = blockNumber; // we read only the relevant portion
switch(dat->domain) {
case DVD_READ_INFO_FILE:
case DVD_READ_INFO_BACKUP_FILE:
@ -263,7 +270,17 @@ void DVDCopy::copy(const char *device, const char * target)
void DVDCopy::secondPass(const char *device, const char * target)
{
setup(device, target);
readBadSectors();
for(int i = 0; i < badSectorsList.size(); i++) {
BadSectors & bs = badSectorsList[i];
printf("Trying to read %d bad sectors from file %s at %d:\n",
bs.number,
bs.file->fileName().c_str(),
bs.start);
copyFile(bs.file, bs.start, bs.number);
}
}
DVDCopy::~DVDCopy()
@ -278,15 +295,18 @@ DVDCopy::~DVDCopy()
delete *i; // Keep it clean;
}
void DVDCopy::openBadSectorsFile(const char * mode)
{
if(! badSectors) {
std::string bsf = targetDirectory + ".bad";
badSectors = fopen(bsf.c_str(), mode);
}
}
void DVDCopy::registerBadSectors(const DVDFileData * dat,
int beg, int size)
{
if(! badSectors) {
std::string bsf = targetDirectory + ".bad";
badSectors = fopen(bsf.c_str(), "a");
}
openBadSectorsFile("a");
fprintf(badSectors, "%s: %d,%d,%d %d (%d)\n",
dat->fileName().c_str(),
dat->title,
@ -294,4 +314,78 @@ void DVDCopy::registerBadSectors(const DVDFileData * dat,
dat->number,
beg, size);
fflush(badSectors);
badSectorsList.push_back(BadSectors(dat, beg, size));
}
int DVDCopy::findFile(int title, dvd_read_domain_t domain, int number)
{
for(int i = 0; i < files.size(); i++) {
const DVDFileData * dat = files[i];
if(
(dat->title == title) &&
(dat->domain == domain) &&
(dat->number == number)
)
return i;
}
return -1;
}
void DVDCopy::readBadSectors()
{
openBadSectorsFile("r");
if(! badSectors) {
fprintf(stderr, "%s", "No bad sectors file found, "
"which is probably good news !\n");
return;
}
char buffer[1024];
regex_t re;
regmatch_t matches[6];
{
int er = regcomp(&re, "[^:]+: *([0-9]+),([0-9]+),([0-9]+) *"
"([0-9]+) *\\(([0-9]+)\\)",
REG_EXTENDED);
if(er) {
regerror(er, &re, buffer, sizeof(buffer));
fprintf(stderr, "Error building the line regexp: %s", buffer);
return;
}
}
while(! feof(badSectors)) {
fgets(buffer, sizeof(buffer), badSectors);
int status = regexec(&re, buffer, sizeof(matches)/sizeof(regmatch_t),
matches, 0);
if(status) {
fprintf(stderr, "error parsing line: %s", buffer);
}
else {
// Make all substrings NULL-terminated:
for(int i = 1; i < sizeof(matches)/sizeof(regmatch_t); i++) {
if(matches[i].rm_so >= 0)
buffer[matches[i].rm_eo] = 0;
}
// No validation whatsoever, but all groups should be here anyway !
int title = atoi(buffer + matches[1].rm_so);
dvd_read_domain_t domain =
(dvd_read_domain_t) atoi(buffer + matches[2].rm_so);
int number = atoi(buffer + matches[3].rm_so);
int beg = atoi(buffer + matches[4].rm_so);
int size = atoi(buffer + matches[5].rm_so);
int idx = findFile(title, domain, number);
if(idx < 0) {
fprintf(stderr, "Found no match for file %d,%d,%d\n",
title, domain, number);
}
else
badSectorsList.push_back(BadSectors(files[idx], beg, size));
}
}
}

View file

@ -43,7 +43,8 @@ class DVDCopy {
/// In the hope to be read again...
FILE * badSectors;
/// Writes a bad sector list to the file
/// Writes a bad sector list to the file, and add them to the
/// badSectors list.
void registerBadSectors(const DVDFileData * dat,
int beg, int size);
@ -55,10 +56,40 @@ class DVDCopy {
/// The underlying files of the source
std::vector<DVDFileData *> files;
/// Subclass representing a single line in a bad sectors file.
class BadSectors {
public:
/// The underlying DVD file (ie something in the files list)
const DVDFileData * file;
/// The starting sector
int start;
/// The number of bad sectors;
int number;
BadSectors(const DVDFileData * f, int s, int n) :
file(f), start(s), number(n) {;}
};
/// The list of bad sectors, either read from the bad sectors file
/// or directly populated registerBadSectors
std::vector<BadSectors> badSectorsList;
/// reads the bad sectors from the bad sectors file
void readBadSectors();
/// Opens the bad sectors file with the given mode, if not open already.
///
/// @todo There should be a way to track the mode last used in order
/// not to try to read from a descriptor open for writing.
void openBadSectorsFile(const char * mode);
/// Finds the index of the file referred to by the title, domain,
/// number triplet. Returns -1 if not found.
int findFile(int title, dvd_read_domain_t domain, int number);
public:
DVDCopy();

View file

@ -43,6 +43,7 @@ static struct option long_options[] = {
{ "help", 0, NULL, 'h'},
{ "eject", 0, NULL, 'e' },
{ "list", 1, NULL, 'l' },
{ "second-pass", 0, NULL, 's' },
{ NULL, 0, NULL, 0}
};
@ -51,9 +52,10 @@ int main(int argc, char ** argv)
DVDCopy dvd;
int option;
int secondPass = 0;
do {
option = getopt_long(argc, argv, "hel:",
option = getopt_long(argc, argv, "hel:s",
long_options, NULL);
switch(option) {
@ -70,6 +72,9 @@ int main(int argc, char ** argv)
dvd.displayFiles();
}
return 0;
case 's':
secondPass = 1;
break;
}
} while(option != -1);
if(argc != optind + 2) {
@ -77,6 +82,9 @@ int main(int argc, char ** argv)
return 1;
}
dvd.copy(argv[optind], argv[optind+1]);
if(secondPass)
dvd.secondPass(argv[optind], argv[optind+1]);
else
dvd.copy(argv[optind], argv[optind+1]);
return 0;
}