From ca144db1a6963242078baf3a801861023224fc4d Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 9 Jul 2012 22:56:11 +0200 Subject: [PATCH 01/22] Fix comment typo --- src/dvdbackup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 9f1a9dc..8a8d719 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -987,7 +987,7 @@ static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_inf - /* Now figure out the offset we will start at also check that the previus files are of valid DVD size */ + /* Now figure out the offset we will start at also check that the previous files are of valid DVD size */ for ( i = 0; i < vob - 1; i++ ) { tsize = title_set_info->title_set[title_set].size_vob[i]; if (tsize%DVD_VIDEO_LB_LEN != 0) { -- 1.8.1.3 From d3810737312f8aa6ecf7b43ab4fae7be8461267e Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 10 Jul 2012 19:39:35 +0200 Subject: [PATCH 02/22] Remove a pointless free() in DVDCopyIfoBup() --- src/dvdbackup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 8a8d719..c9a78f5 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -1216,7 +1216,6 @@ static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, in if ((buffer = (unsigned char *)malloc(size * sizeof(unsigned char))) == NULL) { perror(PACKAGE); ifoClose(ifo_file); - free(buffer); close(streamout_ifo); close(streamout_bup); return 1; -- 1.8.1.3 From 54ac1414b07b87f37f42ec14a49b0a743580b24a Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 10 Jul 2012 17:58:57 +0200 Subject: [PATCH 03/22] Suppress a useless newline in DVDCopyBlocks() that caused an empty line after padding --- src/dvdbackup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index c9a78f5..1ac96a5 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -912,7 +912,7 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int } - if(progress) { + if(progress && (act_read == to_read)) { fprintf(stdout, "\n"); } -- 1.8.1.3 From f41500e810892d05c60bcf94e2bdcfb9d8d24721 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 10 Jul 2012 19:12:13 +0200 Subject: [PATCH 04/22] Keep the _dvd opened if DVDGetFileSet() fails in DVDMirrorTitleSet() or DVDMirror() The _dvd is always closed in main() and doing it twice results in double frees and, depending on the malloc options used, segmentation faults. --- src/dvdbackup.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 1ac96a5..ad411ea 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -1547,7 +1547,6 @@ int DVDMirror(dvd_reader_t * _dvd, char * targetdir,char * title_name, read_erro title_set_info = DVDGetFileSet(_dvd); if (!title_set_info) { - DVDClose(_dvd); return(1); } @@ -1574,7 +1573,6 @@ int DVDMirrorTitleSet(dvd_reader_t * _dvd, char * targetdir,char * title_name, i title_set_info = DVDGetFileSet(_dvd); if (!title_set_info) { - DVDClose(_dvd); return(1); } -- 1.8.1.3 From 1f1a544e1611d63e56ece04ca55c572a633a80db Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 10 Jul 2012 19:35:19 +0200 Subject: [PATCH 05/22] Add a missing free() in DVDWriteCells() --- src/dvdbackup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index ad411ea..bc7b37c 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -260,6 +260,7 @@ static int DVDWriteCells(dvd_reader_t * dvd, int cell_start_sector[], if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) { fprintf(stderr, _("Error creating %s\n"), targetname); + free(buffer); perror(PACKAGE); return(1); } -- 1.8.1.3 From 993aeef08f6deca5a931039f5e37fee946dcdb97 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Wed, 11 Jul 2012 15:01:17 +0200 Subject: [PATCH 06/22] Stop emitting blank lines when hitting read errors in DVDCopyBlocks() --- src/dvdbackup.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index bc7b37c..dba7806 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -866,10 +866,6 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int if(act_read != to_read) { int numBlanks = 0; - if(progress) { - fprintf(stdout, "\n"); - } - if (act_read < 0) { act_read = 0; } -- 1.8.1.3 From 27e5e6696b4f71ad8af207ad5f6e9fa7620f0780 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Fri, 6 Jul 2012 23:37:00 +0200 Subject: [PATCH 07/22] In DVDCopyBlocks, pad with previously read data if available --- src/dvdbackup.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index dba7806..fe6a8a9 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -812,7 +812,6 @@ static titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) { static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int size, char* filename, read_error_strategy_t errorstrat) { - int i; /* all sizes are in DVD logical blocks */ int remaining = size; @@ -821,13 +820,8 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int int to_read = BUFFER_SIZE; int act_read; /* number of buffers actually read */ - /* Write buffer */ - unsigned char buffer[BUFFER_SIZE * DVD_VIDEO_LB_LEN]; - unsigned char buffer_zero[BUFFER_SIZE * DVD_VIDEO_LB_LEN]; - - for(i = 0; i < BUFFER_SIZE * DVD_VIDEO_LB_LEN; i++) { - buffer_zero[i] = '\0'; - } + /* Write buffer, also used as padding source. */ + static unsigned char buffer[BUFFER_SIZE * DVD_VIDEO_LB_LEN]; while( remaining > 0 ) { @@ -886,7 +880,7 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int break; } - if (write(destination, buffer_zero, numBlanks * DVD_VIDEO_LB_LEN) != numBlanks * DVD_VIDEO_LB_LEN) { + if (write(destination, buffer, numBlanks * DVD_VIDEO_LB_LEN) != numBlanks * DVD_VIDEO_LB_LEN) { fprintf(stderr, _("Error writing %s (padding)\n"), filename); return 1; } -- 1.8.1.3 From 3b2cb4b7dd63ad1dc6cb9e408dde861ebf5d658b Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sun, 15 Jul 2012 17:14:23 +0200 Subject: [PATCH 08/22] Fix a README typo --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index b9fe239..e10a345 100644 --- a/README +++ b/README @@ -93,7 +93,7 @@ To backup a specific chapter or chapters from a title: You can skip the -t switch and let the program guess the title although it is not recommended. - If you specify a chapter that his higher than the last chapter of the + If you specify a chapter that is higher than the last chapter of the title dvdbackup will truncate to the highest chapter of the title. Return values: -- 1.8.1.3 From 120d244c7b6d6fe09e21ea8e336a91e777e9bc42 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 9 Jul 2012 21:36:52 +0200 Subject: [PATCH 09/22] Pad percentages and doneMiM in progress lines --- src/dvdbackup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index fe6a8a9..367b97c 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -895,7 +895,7 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int if(remaining < BUFFER_SIZE || (done % BUFFER_SIZE) == 0) { // don't print too often float doneMiB = (float)(done) / 512.0f; // [MiB] done fprintf(stdout, "\r"); - fprintf(stdout, _("Copying %s: %.0f%% done (%.0f/%.0f MiB)"), + fprintf(stdout, _("Copying %s: %3.0f%% done (%4.0f/%.0f MiB)"), progressText, doneMiB / totalMiB * 100.0f, doneMiB, totalMiB); fflush(stdout); } -- 1.8.1.3 From ad87c1c5f97de52d433fdbc0d6b4b8bacb434a59 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sun, 29 Jul 2012 20:55:18 +0200 Subject: [PATCH 10/22] Let DVDCopyBlocks() print the number of readable blocks if there are any --- src/dvdbackup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 367b97c..1d000a1 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -837,7 +837,7 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int fprintf(stdout, "\n"); } if(act_read >= 0) { - fprintf(stderr, _("Error reading %s at block %d\n"), filename, offset+act_read); + fprintf(stderr, _("Error reading %s at block %d, only got %d blocks\n"), filename, offset+act_read, act_read); } else { fprintf(stderr, _("Error reading %s at block %d, read error returned\n"), filename, offset); } -- 1.8.1.3 From 95267359655576c0a850a32d22fa4c7158d0fa57 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 10 Jul 2012 00:06:13 +0200 Subject: [PATCH 11/22] Read the Ifo file with DVDCopyBlocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Ifos are several hundred megs large, others contain invalid sectors. Link the IFO file to the Bup file afterwards. XXX: We should probably actually read the Bup file in case they differ or in case there is no matching Bup file. With this commit ripping "Das Parfüm" actually completes, it turns out that the completely unreadable IFO file is optional, though, so a better approach might be to skip it. --- src/dvdbackup.c | 108 ++++++++++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 1d000a1..1dd87df 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -36,6 +36,7 @@ #include #include #include +#include /* libdvdread */ #include @@ -811,7 +812,7 @@ static titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) { } -static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int size, char* filename, read_error_strategy_t errorstrat) { +static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int size, char *filename, read_error_strategy_t errorstrat, dvd_read_domain_t dvd_file_type) { /* all sizes are in DVD logical blocks */ int remaining = size; @@ -823,15 +824,39 @@ static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int /* Write buffer, also used as padding source. */ static unsigned char buffer[BUFFER_SIZE * DVD_VIDEO_LB_LEN]; + /* We pad whole blocks and thus want to read IFOs and BUPs in block-sized chunks as well. */ + int simulate_block_reads = (dvd_file_type == DVD_READ_INFO_FILE) || (dvd_file_type == DVD_READ_INFO_BACKUP_FILE); + while( remaining > 0 ) { if (to_read > remaining) { to_read = remaining; } - /* Reading blocks */ - act_read = DVDReadBlocks(dvd_file, offset, to_read, buffer); - + if (simulate_block_reads) + { + int byte_offset = offset / DVD_VIDEO_LB_LEN; + int bytes_to_read = to_read * DVD_VIDEO_LB_LEN; + + fprintf(stderr, _("Trying to read %d ifo bytes from %s at offset %d\n"), + bytes_to_read, filename, byte_offset); + /* Explicit seeking is required in case of padding. */ + DVDFileSeek(dvd_file, byte_offset); + act_read = DVDReadBytes(dvd_file, buffer, bytes_to_read); + if (act_read > 0) + { + act_read /= DVD_VIDEO_LB_LEN; + } + else + { + fprintf(stderr, _("Failure when trying to read ifo bytes. Fuck Fuck Fuck\n")); + } + } + else + { + /* Reading blocks */ + act_read = DVDReadBlocks(dvd_file, offset, to_read, buffer); + } if(act_read != to_read) { if(progress) { fprintf(stdout, "\n"); @@ -1021,7 +1046,7 @@ static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_inf return(1); } - result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat); + result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat, DVD_READ_TITLE_VOBS); DVDCloseFile(dvd_file); close(streamout); @@ -1102,7 +1127,7 @@ static int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, in strncpy(progressText, _("menu"), MAXNAME); } - result = DVDCopyBlocks(dvd_file, streamout, 0, size, filename, errorstrat); + result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat, DVD_READ_MENU_VOBS); DVDCloseFile(dvd_file); close(streamout); @@ -1111,7 +1136,7 @@ static int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, in } -static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, int title_set, char* targetdir, char* title_name) { +static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, int title_set, char* targetdir, char* title_name, read_error_strategy_t errorstrat) { /* Temp filename, dirname */ char targetname_ifo[PATH_MAX], targetname_bup[PATH_MAX]; struct stat fileinfo; @@ -1120,14 +1145,16 @@ static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, in unsigned char* buffer = NULL; /* File Handler */ - int streamout_ifo = -1, streamout_bup = -1; + int streamout_ifo = -1; + + /* return value */ + int result; int size; - /* DVD handler */ + /* DVD handlers */ ifo_handle_t* ifo_file = NULL; - if (title_set_info->number_of_title_sets + 1 < title_set) { return(1); } @@ -1174,73 +1201,38 @@ static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, in if ((streamout_ifo = open(targetname_ifo, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { fprintf(stderr, _("Error creating %s\n"), targetname_ifo); perror(PACKAGE); - ifoClose(ifo_file); - free(buffer); - close(streamout_ifo); - close(streamout_bup); - return 1; - } - - if ((streamout_bup = open(targetname_bup, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { - fprintf(stderr, _("Error creating %s\n"), targetname_bup); - perror(PACKAGE); - ifoClose(ifo_file); free(buffer); - close(streamout_ifo); - close(streamout_bup); return 1; } - /* Copy VIDEO_TS.IFO, since it's a small file try to copy it in one shot */ - if ((ifo_file = ifoOpen(dvd, title_set))== 0) { fprintf(stderr, _("Failed opening IFO for title set %d\n"), title_set); - ifoClose(ifo_file); free(buffer); close(streamout_ifo); - close(streamout_bup); return 1; } size = DVDFileSize(ifo_file->file) * DVD_VIDEO_LB_LEN; - if ((buffer = (unsigned char *)malloc(size * sizeof(unsigned char))) == NULL) { - perror(PACKAGE); - ifoClose(ifo_file); - close(streamout_ifo); - close(streamout_bup); - return 1; - } + char *filename = basename(targetname_ifo); - DVDFileSeek(ifo_file->file, 0); + fprintf(stderr, _("Trying to read %d ifo bytes, equaling %d blocks\n"), size, size / DVD_VIDEO_LB_LEN); - if (DVDReadBytes(ifo_file->file,buffer,size) != size) { - fprintf(stderr, _("Error reading IFO for title set %d\n"), title_set); - ifoClose(ifo_file); - free(buffer); - close(streamout_ifo); - close(streamout_bup); - return 1; + result = DVDCopyBlocks(ifo_file->file, streamout_ifo, 0, size / DVD_VIDEO_LB_LEN, filename, errorstrat, DVD_READ_INFO_FILE); + if (result) { + fprintf(stderr, _("Failed to copy %s\n"), filename); } + ifoClose(ifo_file); + close(streamout_ifo); + fprintf(stderr, _("Linking %s file to %s. Ain't I clever?\n"), targetname_ifo, targetname_bup); - if (write(streamout_ifo,buffer,size) != size) { - fprintf(stderr, _("Error writing %s\n"),targetname_ifo); - ifoClose(ifo_file); - free(buffer); - close(streamout_ifo); - close(streamout_bup); - return 1; + result = link(targetname_ifo, targetname_bup); + if (result) { + fprintf(stderr, _("Linking %s to %s failed. You don't need it, right?\n"), + targetname_ifo , targetname_bup); } - if (write(streamout_bup,buffer,size) != size) { - fprintf(stderr, _("Error writing %s\n"),targetname_bup); - ifoClose(ifo_file); - free(buffer); - close(streamout_ifo); - close(streamout_bup); - return 1; - } return 0; } @@ -1254,7 +1246,7 @@ static int DVDMirrorTitleX(dvd_reader_t* dvd, title_set_info_t* title_set_info, int i; int n; - if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) { + if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name, errorstrat) != 0 ) { return(1); } -- 1.8.1.3 From a32cd786c6c026b88654fe0a75b6fbd2b60ea46e Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 24 Sep 2012 15:55:24 +0200 Subject: [PATCH 12/22] Ignore ifoOpen() failures in DVDCopyIfoBup() to let the mirroring continue --- src/dvdbackup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 1dd87df..3778586 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -1206,10 +1206,10 @@ static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, in } if ((ifo_file = ifoOpen(dvd, title_set))== 0) { - fprintf(stderr, _("Failed opening IFO for title set %d\n"), title_set); + fprintf(stderr, _("Failed opening IFO for title set %d. Skipping the file.\n"), title_set); free(buffer); close(streamout_ifo); - return 1; + return 0; } size = DVDFileSize(ifo_file->file) * DVD_VIDEO_LB_LEN; -- 1.8.1.3 From 52e67894918e7ddca805abd05c155f0a3c946ad5 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 31 Jul 2012 19:35:03 +0200 Subject: [PATCH 13/22] Add OpenOutputFile() which opens already existing files for appending if possible and necessary --- src/dvdbackup.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 3778586..9b7c012 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -936,6 +936,67 @@ static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int } +static int OpenOutputFile(const char *targetname, const char *type, int final_size, int *block_offset) { + struct stat fileinfo; + int streamout; + int resume_offset = 0; + int write_flags = O_WRONLY; + + if (stat(targetname, &fileinfo) == 0) { + if (! S_ISREG(fileinfo.st_mode)) { + /* TRANSLATORS: The sentence starts with "The 'file type' file %s exists[...]" */ + fprintf(stderr,_("The %s %s exists but is invalid, it may be a directory.\n"), type, targetname); + return(-1); + } + /* + * We may lose a couple of bytes due to the integer devision. + * This is intentional as we can only resume at multiples of + * DVD_VIDEO_LB_LEN anyway. + */ + *block_offset = fileinfo.st_size / DVD_VIDEO_LB_LEN; + if (final_size == *block_offset) { + /* TRANSLATORS: The sentence starts with "The 'file type' %s exists[...]" */ + fprintf(stderr, _("The %s %s exists with a size that fits. Skipping it.\n"), type, targetname); + return(0); + } + if (final_size < *block_offset) { + /* TRANSLATORS: The sentence starts with "The 'file type' %s exists[...]" */ + fprintf(stderr, _("The %s %s exists but is too large. Trying to overwrite.\n"), type, targetname); + *block_offset = 0; + write_flags |= O_TRUNC; + } + else + { + int bytes_overwritten; + resume_offset = *block_offset * DVD_VIDEO_LB_LEN; + bytes_overwritten = fileinfo.st_size - resume_offset; + /* TRANSLATORS: The sentence starts with "The 'file type' %s exists[...]" */ + fprintf(stderr, _("The %s %s exists; will try to resume after skipping %d" + " blocks, overwriting %d stray bytes.\n"), type, targetname, *block_offset, bytes_overwritten); + write_flags |= O_APPEND; + } + } else { + *block_offset = 0; + write_flags |= O_CREAT; + } + + streamout = open(targetname, write_flags, 0666); + if (streamout == -1) { + fprintf(stderr, _("Error creating %s\n"), targetname); + perror(PACKAGE); + return(-1); + } + + if ((resume_offset != 0) && (resume_offset != lseek(streamout, resume_offset, SEEK_SET))) + { + fprintf(stderr, _("Failed to seek %d bytes to resume %s.\n"), resume_offset, targetname); + close(streamout); + return(-1); + } + + return streamout; +} + static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, int vob, char * targetdir,char * title_name, read_error_strategy_t errorstrat) { -- 1.8.1.3 From 071f11816ff31e61666c84834fd08370713b666d Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 9 Jul 2012 22:52:48 +0200 Subject: [PATCH 14/22] Allow resuming a previous mirror operation instead of overwriting already existing files --- src/dvdbackup.c | 76 +++++++++++++++++++++------------------------------------ 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 9b7c012..2a4b7ca 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -1006,10 +1006,10 @@ static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_inf /* Temp filename,dirname */ char filename[PATH_MAX] = "VIDEO_TS.VOB"; char targetname[PATH_MAX]; - struct stat fileinfo; /* File Handler */ int streamout; + int output_offset = 0; int size; @@ -1078,28 +1078,17 @@ static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_inf fprintf(stderr,"The offset for vob %d is %d\n", vob, offset); #endif - - if (stat(targetname, &fileinfo) == 0) { - /* TRANSLATORS: The sentence starts with "The title file %s exists[...]" */ - fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("title file"), targetname); - if (! S_ISREG(fileinfo.st_mode)) { - /* TRANSLATORS: The sentence starts with "The title file %s is not valid[...]" */ - fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("title file"), targetname); - return(1); - } else { - if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0666)) == -1) { - fprintf(stderr, _("Error opening %s\n"), targetname); - perror(PACKAGE); - return(1); - } - } - } else { - if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0666)) == -1) { - fprintf(stderr, _("Error creating %s\n"), targetname); - perror(PACKAGE); - return(1); - } + streamout = OpenOutputFile(targetname, _("title file"), size, &output_offset); + if (streamout == -1) + { + return(1); } + if (output_offset == size) + { + /* File already exists with the correct size. Skip it. */ + return(0); + } + offset += output_offset; if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) { fprintf(stderr, _("Failed opening TITLE VOB\n")); @@ -1107,7 +1096,7 @@ static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_inf return(1); } - result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat, DVD_READ_TITLE_VOBS); + result = DVDCopyBlocks(dvd_file, streamout, offset, size - output_offset, filename, errorstrat, DVD_READ_TITLE_VOBS); DVDCloseFile(dvd_file); close(streamout); @@ -1120,12 +1109,12 @@ static int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, in /* Temp filename,dirname */ char filename[PATH_MAX] = "VIDEO_TS.VOB"; char targetname[PATH_MAX]; - struct stat fileinfo; /* File Handler */ int streamout; int size; + int offset; /* return value */ int result; @@ -1159,36 +1148,22 @@ static int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, in /* Create VIDEO_TS.VOB or VTS_XX_0.VOB */ sprintf(targetname,"%s/%s/VIDEO_TS/%s",targetdir, title_name, filename); - if (stat(targetname, &fileinfo) == 0) { - /* TRANSLATORS: The sentence starts with "The menu file %s exists[...]" */ - fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("menu file"), targetname); - if (! S_ISREG(fileinfo.st_mode)) { - /* TRANSLATORS: The sentence starts with "The menu file %s is not valid[...]" */ - fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("menu file"), targetname); - DVDCloseFile(dvd_file); - return(1); - } else { - if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0666)) == -1) { - fprintf(stderr, _("Error opening %s\n"), targetname); - perror(PACKAGE); - DVDCloseFile(dvd_file); - return(1); - } - } - } else { - if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0666)) == -1) { - fprintf(stderr, _("Error creating %s\n"), targetname); - perror(PACKAGE); - DVDCloseFile(dvd_file); - return(1); - } + streamout = OpenOutputFile(targetname, _("menu file"), size, &offset); + if (streamout == -1) + { + return(1); + } + if (offset == size) + { + /* File already exists with the correct size. Skip it. */ + return(0); } if(progress) { strncpy(progressText, _("menu"), MAXNAME); } - result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat, DVD_READ_MENU_VOBS); + result = DVDCopyBlocks(dvd_file, streamout, offset, size - offset, filename, errorstrat, DVD_READ_MENU_VOBS); DVDCloseFile(dvd_file); close(streamout); @@ -1240,6 +1215,11 @@ static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, in } if (stat(targetname_ifo, &fileinfo) == 0) { + if (title_set_info->title_set[title_set].size_ifo == fileinfo.st_size) { + /* TRANSLATORS: The sentence starts with "The IFO file %s exists[...]" */ + fprintf(stderr, _("The %s %s exists with a size that fits. Skipping it.\n"), _("IFO file"), targetname_ifo); + return(0); + } /* TRANSLATORS: The sentence starts with "The IFO file %s exists[...]" */ fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("IFO file"), targetname_ifo); if (! S_ISREG(fileinfo.st_mode)) { -- 1.8.1.3 From 0fae12109e4a8ac361c66089f1268c2ddd1c5a21 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 10 Jul 2012 19:39:10 +0200 Subject: [PATCH 15/22] Factor LogDVDCopyProgress() out of DVDCopyBlocks() While at it, include the file name in the message and show values below 1 MiB as KiB --- src/dvdbackup.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 2a4b7ca..c6a72a9 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -811,13 +811,31 @@ static titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) { } +static void LogDVDCopyProgress(char *useless_text, char *filename, int total_blocks, int blocks_done) { + + float total = (float)total_blocks / 512.0f; + float done = (float)blocks_done / 512.0f; + float percentage_done = done / total * 100.0f; + char factor = 'M'; + + if (total < 1) + { + done *= 1024; + total *= 1024; + factor = 'K'; + } + + fprintf(stdout, "\r"); + fprintf(stdout, _("Copying %s %s: %3.0f%% done (%4.0f/%.0f %ciB)"), + useless_text, filename, percentage_done, done, total, factor); + fflush(stdout); +} static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int size, char *filename, read_error_strategy_t errorstrat, dvd_read_domain_t dvd_file_type) { /* all sizes are in DVD logical blocks */ int remaining = size; int total = size; // total size in blocks - float totalMiB = (float)(total) / 512.0f; // total size in [MiB] int to_read = BUFFER_SIZE; int act_read; /* number of buffers actually read */ @@ -916,13 +934,10 @@ static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int } if(progress) { - int done = total - remaining; // blocks done - if(remaining < BUFFER_SIZE || (done % BUFFER_SIZE) == 0) { // don't print too often - float doneMiB = (float)(done) / 512.0f; // [MiB] done - fprintf(stdout, "\r"); - fprintf(stdout, _("Copying %s: %3.0f%% done (%4.0f/%.0f MiB)"), - progressText, doneMiB / totalMiB * 100.0f, doneMiB, totalMiB); - fflush(stdout); + int blocks_done = total - remaining; + // don't print too often + if(remaining < BUFFER_SIZE || (blocks_done % BUFFER_SIZE) == 0) { + LogDVDCopyProgress(progressText, filename, total, blocks_done); } } -- 1.8.1.3 From 42e2b462a4a8c06f1145df1d8c71c3ba432660c8 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 16 Jul 2012 17:04:39 +0200 Subject: [PATCH 16/22] Drop in get_number_of_blocks_to_skip() which I previously wrote for vobcopy It's currently reached by using the shiny new STRATEGY_SKIP_MULTIBLOCK_FANCY and some of the parameters aren't configurable but probably should be. --- src/dvdbackup.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/dvdbackup.h | 3 +- src/main.c | 2 + 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index c6a72a9..c53549f 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -831,6 +831,132 @@ static void LogDVDCopyProgress(char *useless_text, char *filename, int total_blo fflush(stdout); } +/* XXX: These should be configurable, the current values may not be ideal */ +static unsigned int INITIAL_SKIP_COUNT = 16; +static unsigned int MAX_BLOCKS_TO_SKIP_AT_ONCE = 512; +static unsigned int UPPER_INITIAL_SKIP_LIMIT = 1024; + +/* + * Given an offset to a dvd_file_t, figure out how many + * unreadable blocks have to be skipped to reach the next + * readable block. + * + */ +static int get_number_of_blocks_to_skip(dvd_file_t *dvd_file, + unsigned int original_offset, unsigned int last_valid_offset, + unsigned int initial_skip_count, + unsigned char *bufferin) +{ + int blocks; + unsigned int offset = original_offset; + int known_readable_sectors; + /* + * This was previously used to report the number of readable + * sectors that are known to exist, so the caller can adjust + * it's buffer size accordingly to make sure the next read + * operation can be successful. As it turns out this isn't + * necessary as libdvdread will return the readable sectors + * up to the first unreadable block. The number of known good + * blocks may is can still be useful for debugging purposes, + * so it's kept for now. + */ + unsigned int known_good_blocks; + /* + * Static so we use the last working value when called more than once. + * The initial value seems to be a reasonable guess but maybe it should be + * configurable. + */ + static unsigned int blocks_to_skip; + + if (blocks_to_skip < initial_skip_count) + { + /* + * The last value is too low and would slow us down, + * so pretend it doesn't exist. + */ + fprintf( stderr, _("Increasing skip count from %d to %d\n"), blocks_to_skip, initial_skip_count); + blocks_to_skip = initial_skip_count; + } + else if (UPPER_INITIAL_SKIP_LIMIT < blocks_to_skip) + { + fprintf( stderr, _("Decreasing skip count from %d to %d\n"), blocks_to_skip, initial_skip_count); + blocks_to_skip = initial_skip_count; + } + + if (blocks_to_skip >= initial_skip_count) + { + /* Will be doubled again in the next loop. */ + blocks_to_skip /= 2; + } + + do + { + if (offset == last_valid_offset) + { + known_good_blocks = 0; + blocks_to_skip = last_valid_offset - original_offset; + fprintf( stderr, + _("The last readable sector %d is located beyond the end of the file. The last %d sectors of the file are unreadable.\n"), + offset, blocks_to_skip); + return blocks_to_skip; + } + if (blocks_to_skip < MAX_BLOCKS_TO_SKIP_AT_ONCE) + { + blocks_to_skip *= 2; + } + else + { + blocks_to_skip += MAX_BLOCKS_TO_SKIP_AT_ONCE; + } + fprintf( stderr, _("Reading blocks starting at %d failed, trying to read a single block at %d, skipping %d\n"), + offset, original_offset + blocks_to_skip, blocks_to_skip); + offset = original_offset + blocks_to_skip; + + if (offset > last_valid_offset) + { + fprintf( stderr, _("Reducing offset from %d to the last valid offset %d\n"), + offset, last_valid_offset); + offset = last_valid_offset; + } + } while ((blocks = DVDReadBlocks(dvd_file, offset, 1, bufferin)) <= 0); + + fprintf( stderr, _("Got a valid block at offset %d, after skipping %d. Trying to reduce the number of blocks to skip.\n"), + offset, blocks_to_skip); + + known_readable_sectors = blocks_to_skip; + + do + { + /* + * XXX: This could be done smarter, for example by using a binary search. + */ + blocks_to_skip--; + offset = original_offset + blocks_to_skip; + } + while (blocks_to_skip > 0 && (blocks = DVDReadBlocks(dvd_file, offset, 1, bufferin)) > 0); + + blocks_to_skip++; + + known_good_blocks = known_readable_sectors - blocks_to_skip; + + if (blocks_to_skip == 0) + { + /* + * This can happen if the caller tried to read more blocks at + * once then we did. XXX: This is probably incorrect. + */ + fprintf( stderr, _("All of the %d blocks starting at offset %d appear to be readable\n"), + known_good_blocks, original_offset); + } + else + { + fprintf( stderr, _("Got an invalid block at offset %d, after skipping %d. Known good blocks: %u. Returning %d\n"), + offset, blocks_to_skip-1, known_good_blocks, blocks_to_skip); + } + + return blocks_to_skip; +} + static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int size, char *filename, read_error_strategy_t errorstrat, dvd_read_domain_t dvd_file_type) { /* all sizes are in DVD logical blocks */ @@ -902,7 +1028,6 @@ static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int if(act_read != to_read) { int numBlanks = 0; - if (act_read < 0) { act_read = 0; } @@ -921,6 +1046,21 @@ static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int numBlanks = to_read - act_read; fprintf(stderr, _("padding %d blocks\n"), numBlanks); break; + + case STRATEGY_SKIP_MULTIBLOCK_FANCY: + numBlanks = get_number_of_blocks_to_skip(dvd_file, + offset + act_read, + offset + remaining, + INITIAL_SKIP_COUNT, + buffer); + if (numBlanks < 1) + { + fprintf(stderr, _("Unhandled get_number_of_blocks_to_skip() return code %d\n"), + numBlanks); + numBlanks = to_read - act_read; + } + fprintf(stderr, _("padding %d blocks\n"), numBlanks); + break; } if (write(destination, buffer, numBlanks * DVD_VIDEO_LB_LEN) != numBlanks * DVD_VIDEO_LB_LEN) { diff --git a/src/dvdbackup.h b/src/dvdbackup.h index d981403..5a2ad96 100644 --- a/src/dvdbackup.h +++ b/src/dvdbackup.h @@ -32,7 +32,8 @@ extern int progress; typedef enum { STRATEGY_ABORT, STRATEGY_SKIP_BLOCK, - STRATEGY_SKIP_MULTIBLOCK + STRATEGY_SKIP_MULTIBLOCK, + STRATEGY_SKIP_MULTIBLOCK_FANCY } read_error_strategy_t; int DVDDisplayInfo(dvd_reader_t*, char*); diff --git a/src/main.c b/src/main.c index c53cf5f..689b684 100644 --- a/src/main.c +++ b/src/main.c @@ -284,6 +284,8 @@ int main(int argc, char* argv[]) { errorstrat=STRATEGY_SKIP_BLOCK; } else if(errorstrat_temp[0]=='m') { errorstrat=STRATEGY_SKIP_MULTIBLOCK; + } else if(errorstrat_temp[0]=='f') { + errorstrat=STRATEGY_SKIP_MULTIBLOCK_FANCY; } else { print_help(); exit(1); -- 1.8.1.3 From e677c3dbf742b243d11d350d1070d3a4bb4df320 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 16 Jul 2012 17:46:48 +0200 Subject: [PATCH 17/22] Factor out the padding into PadUnreadableBlocks() It allows to pad with an arbitrary number of blocks and uses only the first block of the last successfully read blocks as padding source. It's not clear what impact this has, but is easier to implement and was the approach I took with the vobcopy hack as well. --- src/dvdbackup.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index c53549f..ecb7b19 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -957,6 +957,19 @@ static int get_number_of_blocks_to_skip(dvd_file_t *dvd_file, return blocks_to_skip; } +static int PadUnreadableBlocks(int destination, unsigned char *buffer, int numBlanks) { + int i; + for (i = 0; i < numBlanks; i++) + { + if (write(destination, buffer, DVD_VIDEO_LB_LEN) != DVD_VIDEO_LB_LEN) + { + fprintf(stderr, _("Padding failure after %d blocks.\n"), i); + return 1; + } + } + return 0; +} + static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int size, char *filename, read_error_strategy_t errorstrat, dvd_read_domain_t dvd_file_type) { /* all sizes are in DVD logical blocks */ @@ -1063,9 +1076,10 @@ static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int break; } - if (write(destination, buffer, numBlanks * DVD_VIDEO_LB_LEN) != numBlanks * DVD_VIDEO_LB_LEN) { - fprintf(stderr, _("Error writing %s (padding)\n"), filename); - return 1; + if (PadUnreadableBlocks(destination, buffer, numBlanks)) + { + fprintf(stderr, _("Error writing %d blocks of padding to %s (padding)\n"), numBlanks, filename); + return 1; } /* pretend we read what we padded */ -- 1.8.1.3 From 4e2e5eff20321cdb7337bb2083244a3a3c981e91 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 16 Jul 2012 17:57:54 +0200 Subject: [PATCH 18/22] Always show the progress until I figure out a fix --- src/dvdbackup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index ecb7b19..406d4f2 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -1090,7 +1090,7 @@ static int DVDCopyBlocks(dvd_file_t *dvd_file, int destination, int offset, int if(progress) { int blocks_done = total - remaining; // don't print too often - if(remaining < BUFFER_SIZE || (blocks_done % BUFFER_SIZE) == 0) { + if(remaining < BUFFER_SIZE || (blocks_done % BUFFER_SIZE) == 0 || 1) { LogDVDCopyProgress(progressText, filename, total, blocks_done); } } -- 1.8.1.3 From 0a8a8658997af313f69201dbf24071491fcd44d0 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 28 Jul 2012 20:28:17 +0200 Subject: [PATCH 19/22] Add a define to enable zero padding --- src/dvdbackup.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dvdbackup.c b/src/dvdbackup.c index 406d4f2..b129515 100644 --- a/src/dvdbackup.c +++ b/src/dvdbackup.c @@ -59,6 +59,8 @@ #define DVD_SEC_SIZ 2048 +#define PAD_WITH_ZEROES 0 + /* Flag for verbose mode */ int verbose = 0; int aspect; @@ -959,6 +961,10 @@ static int get_number_of_blocks_to_skip(dvd_file_t *dvd_file, static int PadUnreadableBlocks(int destination, unsigned char *buffer, int numBlanks) { int i; +#if PAD_WITH_ZEROES + fprintf(stderr, _("Zeroing %d bytes before padding.\n"), DVD_VIDEO_LB_LEN); + memset(buffer, 0, DVD_VIDEO_LB_LEN); +#endif for (i = 0; i < numBlanks; i++) { if (write(destination, buffer, DVD_VIDEO_LB_LEN) != DVD_VIDEO_LB_LEN) -- 1.8.1.3 From 6d734225525858b6dcb7021213a6a87b86bbf59e Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 15 Oct 2012 21:40:01 +0200 Subject: [PATCH 20/22] Allow title name lengths up to PATH_MAX. Overflows could happen either way so who cares --- src/main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main.c b/src/main.c index 689b684..4e18178 100644 --- a/src/main.c +++ b/src/main.c @@ -165,7 +165,7 @@ int main(int argc, char* argv[]) { /* Title of the DVD */ - char title_name[33] = ""; + char title_name[PATH_MAX] = ""; char* provided_title_name = NULL; /* Targer dir */ @@ -396,13 +396,12 @@ int main(int argc, char* argv[]) { } } else { - if (strlen(provided_title_name) > 32) { - fprintf(stderr,_("The title name specified is longer than 32 characters; truncating the title name\n")); - strncpy(title_name,provided_title_name, 32); - title_name[32]='\0'; - } else { - strcpy(title_name,provided_title_name); + const size_t max_title_length = sizeof(title_name) - 1; + if (strlen(provided_title_name) > max_title_length) { + fprintf(stderr,_("The title name specified is longer than %u characters; truncating the title name\n"), (unsigned)max_title_length); + provided_title_name[max_title_length] = '\0'; } + strcpy(title_name,provided_title_name); } -- 1.8.1.3