From f0bc221382943d3db3a6fb4bcb26fd4321144134 Mon Sep 17 00:00:00 2001 From: Vincent Fourmond Date: Wed, 2 Jan 2013 23:43:47 +0100 Subject: [PATCH] First attempt at a second-pass option, although it does not seem successful for the time being --- src/dvdcopy.cc | 112 +++++++++++++++++++++++++++++++++++++++++++++---- src/dvdcopy.hh | 33 ++++++++++++++- src/main.cc | 12 +++++- 3 files changed, 145 insertions(+), 12 deletions(-) diff --git a/src/dvdcopy.cc b/src/dvdcopy.cc index 35d3fb1..bb17c68 100644 --- a/src/dvdcopy.cc +++ b/src/dvdcopy.cc @@ -32,6 +32,9 @@ #include +// use of regular expressions ! +#include + #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)); + } + } + } diff --git a/src/dvdcopy.hh b/src/dvdcopy.hh index 5ad7830..7e628b5 100644 --- a/src/dvdcopy.hh +++ b/src/dvdcopy.hh @@ -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 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 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(); diff --git a/src/main.cc b/src/main.cc index 0a89023..7fb64d8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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; }