From 83a8fc5483e375fac91bd3cb1326ccac43cc7527 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Tue, 25 Apr 2017 15:05:23 -0400 Subject: [PATCH] Adds --force-overread Force overreading into the lead-out portion of the disc. This option is only applicable when using the-O option with a positive sample offset value. Many drives are not capable of reading into this portion of the disc and attempting to do so on those drives will produce read errors and possibly hard lockups. See: https://gist.github.com/AnwarShah/560d77f7d7da52553f918f3ecb7401e3 --- doc/en/cd-paranoia.1.in | 88 ++++++++++++++------------- src/cd-paranoia.c | 129 ++++++++++++++++++++++++++-------------- 2 files changed, 133 insertions(+), 84 deletions(-) diff --git a/doc/en/cd-paranoia.1.in b/doc/en/cd-paranoia.1.in index 336aea0..a6813c5 100644 --- a/doc/en/cd-paranoia.1.in +++ b/doc/en/cd-paranoia.1.in @@ -4,7 +4,7 @@ .SH SYNOPSIS .B @CDPARANOIA_NAME@ .RB [ options ] -.B span +.B span .RB [ outfile ] .SH DESCRIPTION .B @CDPARANOIA_NAME@ @@ -15,7 +15,7 @@ makes are supported; .B @CDPARANOIA_NAME@ can determine if the target drive is CDDA capable. .P -In addition to simple reading, +In addition to simple reading, .B @CDPARANOIA_NAME@ adds extra-robust data verification, synchronization, error handling and scratch reconstruction capability. @@ -25,7 +25,7 @@ drive. The jitter and error correction however are the same as used in Xiph's cdparanoia. .SH OPTIONS -.TP +.TP .B \-A --analyze-drive Run and log a complete analysis of drive caching, timing and reading behavior; verifies that cdparanoia is correctly modelling a sprcific drive's cache and @@ -55,23 +55,23 @@ contents, then quit. .TP .B \-h --help -Print a brief synopsis of -.B @CDPARANOIA_NAME@ +Print a brief synopsis of +.B @CDPARANOIA_NAME@ usage and options. .TP -.BI "\-l --log-summary " file +.BI "\-l --log-summary " file Save result summary to file. .TP -.BI "\-L --log-debug " file +.BI "\-L --log-debug " file Save detailed device autosense and debugging output to a file. .TP .B \-p --output-raw -Output headerless data as raw 16 bit PCM data with interleaved samples in host byte order. To force little or big endian byte order, use -.B \-r -or +Output headerless data as raw 16 bit PCM data with interleaved samples in host byte order. To force little or big endian byte order, use +.B \-r +or .B \-R as described below. @@ -118,12 +118,12 @@ As above but force @CDPARANOIA_NAME@ to treat the drive as a big endian device. .TP .BI "\-n --force-default-sectors " n -Force the interface backend to do atomic reads of +Force the interface backend to do atomic reads of .B n sectors per read. This number can be misleading; the kernel will often split read requests into multiple atomic reads (the automated Paranoia code is aware of this) or allow reads only wihin a restricted size -range. +range. .B This option should generally not be used. .TP @@ -183,13 +183,19 @@ partial sectors before or past the known user data area, probably causing read errors on most drives and possibly even hard lockups on some buggy hardware. +.TP +.BI \-E --force-overread +Force overreading into the lead-out portion of the disc. This option is only applicable when using the ++.B -O ++option with a positive sample offset value. Many drives are not capable of reading into this portion of the disc and attempting to do so on those drives will produce read errors and possibly hard lockups. + .TP .B \-Z --disable-paranoia -Disable +Disable .B all data verification and correction features. When using -Z, @CDPARANOIA_NAME@ reads data exactly as would cdda2wav with an overlap setting of zero. -This option implies that +This option implies that .B \-Y is active. @@ -223,35 +229,35 @@ simulate the kind of specified failure. .SH OUTPUT SMILIES .TP .B - :-) + :-) Normal operation, low/no jitter .TP .B - :-| + :-| Normal operation, considerable jitter .TP .B - :-/ + :-/ Read drift .TP .B - :-P + :-P Unreported loss of streaming in atomic read operation .TP .B - 8-| + 8-| Finding read problems at same point during reread; hard to correct .TP .B - :-0 + :-0 SCSI/ATAPI transport error .TP .B - :-( + :-( Scratch detected .TP .B - ;-( + ;-( Gave up trying to perform a correction .TP .B @@ -259,41 +265,41 @@ Gave up trying to perform a correction Aborted read due to known, uncorrectable error .TP .B - :^D + :^D Finished extracting .SH PROGRESS BAR SYMBOLS .TP .B - + No corrections needed .TP .B - - + - Jitter correction required .TP .B - + + + Unreported loss of streaming/other error in read .TP .B - ! + ! Errors found after stage 1 correction; the drive is making the same error through multiple re-reads, and @CDPARANOIA_NAME@ is having trouble detecting them. .TP .B - e + e SCSI/ATAPI transport error (corrected) .TP .B - V + V Uncorrected error/skip .SH SPAN ARGUMENT The span argument specifies which track, tracks or subsections of -tracks to read. This argument is required. +tracks to read. This argument is required. .B NOTE: Unless the span is a simple number, it's generally a good idea to quote the span argument to protect it from the shell. @@ -301,7 +307,7 @@ quote the span argument to protect it from the shell. The span argument may be a simple track number or an offset/span specification. The syntax of an offset/span takes the rough form: .P -1[ww:xx:yy.zz]-2[aa:bb:cc.dd] +1[ww:xx:yy.zz]-2[aa:bb:cc.dd] .P Here, 1 and 2 are track numbers; the numbers in brackets provide a finer grained offset within a particular track. [aa:bb:cc.dd] is in @@ -316,20 +322,20 @@ offset is preceeded or followed by a hyphen, the implicit missing offset is taken to be the start or end of the disc, respectively. Thus: .TP -.B 1:[20.35] +.B 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to the end of track 1. .TP -.B 1:[20.35]- +.B 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc .TP -.B \-2 +.B \-2 Specifies ripping from the beginning of the disc up to (and including) track 2 .TP -.B \-2:[30.35] +.B \-2:[30.35] Specifies ripping from the beginning of the disc up to 2:[30.35] .TP -.B 2-4 +.B 2-4 Specifies ripping from the beginning of track 2 to the end of track 4. .P Again, don't forget to protect square brackets and preceeding hyphens from @@ -345,7 +351,7 @@ Query only with exhaustive search for a drive and full reporting of autosense: .TP Extract an entire disc, putting each track in a seperate file: .P - @CDPARANOIA_NAME@ -B + @CDPARANOIA_NAME@ -B .TP Extract from track 1, time 0:30.12 to 1:10.00: .P @@ -361,11 +367,11 @@ The "--" above is to distinguish "-3" from an option flag. The output file argument is optional; if it is not specified, @CDPARANOIA_NAME@ will output samples to one of .BR cdda.wav ", " cdda.aifc ", or " cdda.raw -depending on whether -.BR \-w ", " \-a ", " \-r " or " \-R " is used (" \-w -is the implicit default). The output file argument of +depending on whether +.BR \-w ", " \-a ", " \-r " or " \-R " is used (" \-w +is the implicit default). The output file argument of .B \- -specifies standard output; all data formats may be piped. +specifies standard output; all data formats may be piped. .SH ACKNOWLEDGEMENTS @CDPARANOIA_NAME@ sprang from and once drew heavily from the interface of diff --git a/src/cd-paranoia.c b/src/cd-paranoia.c index 3b2f9f5..9443b62 100644 --- a/src/cd-paranoia.c +++ b/src/cd-paranoia.c @@ -581,7 +581,7 @@ callback(long int inpos, paranoia_cb_mode_t function) } #endif /* !TRACE_PARANOIA */ -static const char optstring[] = "aBcCd:efg:k:hi:l:L:Am:n:o:O:pqQrRsS:Tt:VvwWx:XYZz::"; +static const char optstring[] = "aBcCd:eEfFg:k:hi:l:L:Am:n:o:O:pqQrRsS:Tt:VvwWx:XYZz::"; static const struct option options [] = { {"abort-on-skip", no_argument, NULL, 'X'}, @@ -598,6 +598,7 @@ static const struct option options [] = { {"force-generic-device", required_argument, NULL, 'g'}, {"force-read-speed", required_argument, NULL, 'S'}, {"force-search-overlap", required_argument, NULL, 'o'}, + {"force-overread", no_argument, NULL, 'E'}, {"help", no_argument, NULL, 'h'}, {"log-summary", required_argument, NULL, 'l'}, {"log-debug", required_argument, NULL, 'L'}, @@ -711,6 +712,7 @@ main(int argc,char *argv[]) long int force_cdrom_overlap = -1; long int force_cdrom_sectors = -1; long int force_cdrom_speed = 0; + long int force_overread = 0; long int sample_offset = 0; long int test_flags = 0; long int toc_offset = 0; @@ -873,6 +875,9 @@ main(int argc,char *argv[]) paranoia_mode|=PARANOIA_MODE_NEVERSKIP; } break; + case 'E': + force_overread=1; + break; default: usage(stderr); exit(1); @@ -1210,11 +1215,18 @@ main(int argc,char *argv[]) } + if (toc_offset && !force_overread) { + d->disc_toc[d->tracks].dwStartSector -= toc_offset; + if (i_last_lsn > cdda_track_lastsector(d, d->tracks)) + i_last_lsn -= toc_offset; + } { long cursor; int16_t offset_buffer[1176]; int offset_buffer_used=0; int offset_skip=sample_offset*4; + off_t sectorlen; + #if defined(HAVE_GETUID) && (defined(HAVE_SETEUID) || defined(HAVE_SETEGID)) int dummy __attribute__((unused)); #endif @@ -1243,7 +1255,7 @@ main(int argc,char *argv[]) need to set the disc length forward here so that the libs are willing to read past, assuming that works on the hardware, of course */ - if(sample_offset) + if(sample_offset && force_overread) d->disc_toc[d->tracks].dwStartSector++; while(cursor<=i_last_lsn){ @@ -1367,17 +1379,22 @@ main(int argc,char *argv[]) } + sectorlen = batch_last - batch_first + 1; + if (cdda_sector_gettrack(d, cursor) == d->tracks && + toc_offset > 0 && !force_overread){ + sectorlen += toc_offset; + } switch(output_type) { case 0: /* raw */ break; case 1: /* wav */ - WriteWav(out, (batch_last-batch_first+1)*CDIO_CD_FRAMESIZE_RAW); + WriteWav(out, sectorlen * CD_FRAMESIZE_RAW); break; case 2: /* aifc */ - WriteAifc(out, (batch_last-batch_first+1)*CDIO_CD_FRAMESIZE_RAW); + WriteAifc(out, sectorlen * CD_FRAMESIZE_RAW); break; case 3: /* aiff */ - WriteAiff(out, (batch_last-batch_first+1)*CDIO_CD_FRAMESIZE_RAW); + WriteAiff(out, sectorlen * CD_FRAMESIZE_RAW); break; } @@ -1448,45 +1465,71 @@ main(int argc,char *argv[]) /* One last bit of silliness to deal with sample offsets */ if(sample_offset && cursor>batch_last){ - int i; - /* read a sector and output the partial offset. Save the - rest for the next batch iteration */ - readbuf=paranoia_read_limited(p, callback, max_retries); - err=cdda_errors(d);mes=cdda_messages(d); - - if(mes || err) - fprintf(stderr,"\r " - " \r%s%s\n", - mes?mes:"",err?err:""); - - if(err)free(err);if(mes)free(mes); - if(readbuf==NULL){ - skipped_flag=1; - report("\nparanoia_read: Unrecoverable error reading through " - "sample_offset shift\n\tat end of track, bailing.\n"); - break; - } - if (skipped_flag && abort_on_skip) break; - skipped_flag=0; - /* do not move the cursor */ - - if(output_endian!=bigendianp()) - for(i=0;itracks || force_overread) { + int i; + + /* Need to flush the buffer when overreading into the leadout */ + if (cdda_sector_gettrack(d, batch_last) == d->tracks) + paranoia_seek(p, cursor, SEEK_SET); + + /* read a sector and output the partial offset. Save the + rest for the next batch iteration */ + readbuf=paranoia_read_limited(p,callback,max_retries); + err=cdda_errors(d);mes=cdda_messages(d); + + if(mes || err) + fprintf(stderr,"\r " + " \r%s%s\n", + mes?mes:"",err?err:""); + + if(err)free(err);if(mes)free(mes); + if(readbuf==NULL){ + skipped_flag=1; + report("\nparanoia_read: Unrecoverable error reading through " + "sample_offset shift\n\tat end of track, bailing.\n"); + break; + } + if (skipped_flag && abort_on_skip) break; + skipped_flag=0; + /* do not move the cursor */ + + if(output_endian!=bigendianp()) + for(i=0;itracks && + toc_offset > 0 && !force_overread) + { + char *silence; + size_t missing_sector_bytes = CD_FRAMESIZE_RAW * toc_offset; + + silence = calloc(toc_offset, CD_FRAMESIZE_RAW); + if (!silence || buffering_write(out, silence, missing_sector_bytes)) { + report("Error writing output: %s", strerror(errno)); + exit(1); + } + free(silence); + } + + callback(cursor* (CDIO_CD_FRAMESIZE_RAW/2)-1, PARANOIA_CB_FINISHED); buffering_close(out); if(skipped_flag){