Codebase list gddrescue / 818f1fc
Adding upstream version 1.18.1 Michael Prokop 9 years ago
35 changed file(s) with 4190 addition(s) and 2987 deletion(s). Raw diff Collapse all Expand all
0 2014-06-07 Antonio Diaz Diaz <antonio@gnu.org>
1
2 * Version 1.18.1 released.
3 * ddrescuelog.cc (do_logic_ops): Fixed 'or' and 'xor'.
4 * Added new option '-H, --test-mode' to simulate read errors.
5 * Added new option '-L, --loose-domain' to ddrescue and ddrescuelog.
6 * Added new option '-N, --no-trim' to disable trimming of
7 damaged areas.
8 * Added new option '-O, --reopen-on-error'.
9 * Added new options '-1, --log-rates', and '-2, --log-reads'.
10 * Extended '-K, --skip-size' with maximum and disable values.
11 * Changed long name of option '-r' to '--retry-passes'.
12 * Changed short name of option '--generate-mode' to '-G'.
13 * Default value of option '-l, --logfile-size' increased to 10000.
14 * If interrupted, ddrescue terminates by raising the signal received.
15 * rescuebook.cc (copy_non_tried): Do not mark skipped blocks as
16 non-trimmed. Try them in additional passes (before trimming).
17 * rescuebook.cc: Limit the copying phase to 3 passes.
18 * rescuebook.cc: Alternate direction of passes during copying phase.
19 * rescuebook.cc: Smallest blocks are trimmed first.
20 * rescuebook.cc (split_errors): Read largest first if logfile full.
21 * Improved speed when using option '-m, --domain-logfile'.
22 * io.cc (show_status): Show the current total run time.
23 * rescuebook.cc: Show pass number and direction during copying.
24 * rescuebook.cc (show_status): Show block pos instead of current_pos.
25 * main.cc: Show "an unknown number of bytes" for unknown isize.
26 * Added option '-B, --binary-prefixes' to ddrescuelog.
27 * Added new option '-C, --complete-logfile' to ddrescuelog.
28 * Added new option '-P, --compare-as-domain' to ddrescuelog.
29 * Improved speed of logic operations in ddrescuelog.
30 * rescuebook.cc (Rescuebook::do_rescue): Show warning when domain
31 is smaller than logfile.
32 * ddrescuelog.cc (do_show_status): Show logfile and domain extents
33 when domain is smaller than logfile.
34 * block.h: Class Block now forces the invariant by itself.
35 * Code reorganization. New class 'Logfile'.
36 * Added status message to rescue logfile.
37 * Many improvements to documentation.
38 * ddrescue.texinfo: Renamed to ddrescue.texi.
39
040 2013-07-09 Antonio Diaz Diaz <antonio@gnu.org>
141
242 * Version 1.17 released.
1656 * rescuebook.cc: Mark failed blocks with 1 sector as bad-sector.
1757 * logbook.cc (extend_sblock_vector): Remove last block of
1858 logfile if it starts at isize and is not marked as finished.
19 * io.cc (show_status,update_rates): Detect a jump back in time
59 * io.cc (show_status, update_rates): Detect a jump back in time
2060 and adjust status.
2161 * ddrescue.h (slow_read): Return false for the first 10 seconds.
2262 * io.cc (show_status) Leave cursor after message so that ^C does
153193 * Version 1.6 released.
154194 * Code reorganization. New classes 'Fillbook' and 'Rescuebook'.
155195 * logbook.cc (copy_non_tried): Added new variable 'skip_counter'.
156 * Added new pass that trims error areas backward before splitting.
196 * Added new pass that trims error areas backwards before splitting.
157197 * Added support for sparse output files.
158198 * Blocks longer than hardbs are now split at sector boundaries.
159199 * Added new option '-F, --fill'.
271311 * Version 0.1 released.
272312
273313
274 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
275 Antonio Diaz Diaz.
314 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
315 2014 Antonio Diaz Diaz.
276316
277317 This file is a collection of facts, and thus it is not copyrightable,
278318 but just in case, you have unlimited permission to copy, distribute and
99 ---------
1010 1. Unpack the archive if you have not done so already:
1111
12 tar -xf ddrescue[version].tar.lz
13 or
1214 lzip -cd ddrescue[version].tar.lz | tar -xf -
13 or
14 gzip -cd ddrescue[version].tar.gz | tar -xf -
1515
1616 This creates the directory ./ddrescue[version] containing the source from
1717 the main archive.
3838
3939 Another way
4040 -----------
41 You can also compile ddrescue into a separate directory. To do this, you
42 must use a version of 'make' that supports the 'VPATH' variable, such
43 as GNU 'make'. 'cd' to the directory where you want the object files
44 and executables to go and run the 'configure' script. 'configure'
45 automatically checks for the source code in '.', in '..' and in the
46 directory that 'configure' is in.
41 You can also compile ddrescue into a separate directory.
42 To do this, you must use a version of 'make' that supports the 'VPATH'
43 variable, such as GNU 'make'. 'cd' to the directory where you want the
44 object files and executables to go and run the 'configure' script.
45 'configure' automatically checks for the source code in '.', in '..' and
46 in the directory that 'configure' is in.
4747
4848 'configure' recognizes the option '--srcdir=DIR' to control where to
4949 look for the sources. Usually 'configure' can determine that directory
5353 explained above.
5454
5555
56 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
57 Antonio Diaz Diaz.
56 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
57 2014 Antonio Diaz Diaz.
5858
5959 This file is free documentation: you have unlimited permission to copy,
6060 distribute and modify it.
00
11 DISTNAME = $(pkgname)-$(pkgversion)
22 INSTALL = install
3 INSTALL_PROGRAM = $(INSTALL) -p -m 755
4 INSTALL_DATA = $(INSTALL) -p -m 644
3 INSTALL_PROGRAM = $(INSTALL) -m 755
4 INSTALL_DATA = $(INSTALL) -m 644
55 INSTALL_DIR = $(INSTALL) -d -m 755
66 SHELL = /bin/sh
77
8 ddobjs = block.o fillbook.o genbook.o io.o logbook.o rescuebook.o main.o
9 objs = arg_parser.o rational.o $(ddobjs)
10 logobjs = arg_parser.o block.o logbook.o ddrescuelog.o
8 ddobjs = fillbook.o genbook.o io.o logbook.o rescuebook.o main.o
9 objs = arg_parser.o block.o logfile.o loggers.o rational.o $(ddobjs)
10 logobjs = arg_parser.o block.o logbook.o logfile.o ddrescuelog.o
1111
1212
1313 .PHONY : all install install-bin install-info install-man install-strip \
1717 all : $(progname) ddrescuelog
1818
1919 $(progname) : $(objs)
20 $(CXX) $(LDFLAGS) -o $@ $(objs)
20 $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(objs)
2121
2222 $(progname)_profiled : $(objs)
23 $(CXX) $(LDFLAGS) -pg -o $@ $(objs)
23 $(CXX) $(CXXFLAGS) $(LDFLAGS) -pg -o $@ $(objs)
2424
2525 ddrescuelog : $(logobjs)
26 $(CXX) $(LDFLAGS) -o $@ $(logobjs)
26 $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(logobjs)
2727
2828 static_$(progname) : $(objs)
29 $(CXX) $(LDFLAGS) -static -o $@ $(objs)
29 $(CXX) $(CXXFLAGS) $(LDFLAGS) -static -o $@ $(objs)
3030
3131 main.o : main.cc
32 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
32 $(CXX) $(CXXFLAGS) $(CPPFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
3333
3434 ddrescuelog.o : ddrescuelog.cc
35 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
35 $(CXX) $(CXXFLAGS) $(CPPFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
3636
3737 %.o : %.cc
38 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
38 $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
3939
4040 $(objs) : Makefile
4141 $(ddobjs) : block.h ddrescue.h
4242 arg_parser.o : arg_parser.h
43 block.o : block.h
44 io.o : loggers.h
45 logfile.o : block.h
46 loggers.o : block.h loggers.h
4347 rational.o : rational.h
44 main.o : arg_parser.h rational.h main_common.cc
48 rescuebook.o : loggers.h
49 main.o : arg_parser.h rational.h loggers.h main_common.cc
4550 ddrescuelog.o : Makefile arg_parser.h block.h ddrescue.h main_common.cc
4651
4752
4954
5055 info : $(VPATH)/doc/$(pkgname).info
5156
52 $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
53 cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
57 $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texi
58 cd $(VPATH)/doc && makeinfo $(pkgname).texi
5459
5560 man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/ddrescuelog.1
5661
5762 $(VPATH)/doc/$(progname).1 : $(progname)
58 help2man -n 'data recovery tool' \
59 -o $@ ./$(progname)
63 help2man -n 'data recovery tool' -o $@ ./$(progname)
6064
6165 $(VPATH)/doc/ddrescuelog.1 : ddrescuelog
62 help2man -n 'tool for ddrescue logfiles' \
63 -o $@ --no-info ./ddrescuelog
66 help2man -n 'tool for ddrescue logfiles' -o $@ --no-info ./ddrescuelog
6467
6568 Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
6669 ./config.status
104107
105108 dist : doc
106109 ln -sf $(VPATH) $(DISTNAME)
107 tar -cvf $(DISTNAME).tar \
110 tar -Hustar --owner=root --group=root -cvf $(DISTNAME).tar \
108111 $(DISTNAME)/AUTHORS \
109112 $(DISTNAME)/COPYING \
110113 $(DISTNAME)/ChangeLog \
116119 $(DISTNAME)/doc/$(progname).1 \
117120 $(DISTNAME)/doc/ddrescuelog.1 \
118121 $(DISTNAME)/doc/$(pkgname).info \
119 $(DISTNAME)/doc/$(pkgname).texinfo \
122 $(DISTNAME)/doc/$(pkgname).texi \
120123 $(DISTNAME)/testsuite/check.sh \
121 $(DISTNAME)/testsuite/logfile1 \
122 $(DISTNAME)/testsuite/logfile2 \
124 $(DISTNAME)/testsuite/logfile[1-5] \
125 $(DISTNAME)/testsuite/logfile2i \
126 $(DISTNAME)/testsuite/logfile_blank \
123127 $(DISTNAME)/testsuite/test.txt \
124128 $(DISTNAME)/testsuite/test1.txt \
125129 $(DISTNAME)/testsuite/test2.txt \
+36
-36
NEWS less more
0 Changes in version 1.17:
0 Changes in version 1.18:
11
2 The new option "-l, --logfile-size" has been added.
2 A bug has been fixed in the "or" and "xor" operations of ddrescuelog.
33
4 The new option "-w, --ignore-write-errors", which makes fill mode ignore
5 write errors, has been added.
4 The new option "-H, --test-mode" has been added.
65
7 The option "--fill" has been renamed to "--fill-mode".
6 The new option "-L, --loose-domain" has been added to ddrescue and
7 ddrescuelog.
88
9 The option '--generate-logfile' has been renamed to '--generate-mode'.
9 The new option "-N, --no-trim" has been added.
1010
11 The option "--sector-size" has been added as a synonym of "--block-size".
11 The new option "-O, --reopen-on-error" has been added.
1212
13 The option "--retries" has been added as a synonym of "--max-retries".
13 The new options "-1, --log-rates" and "-2, --log-reads" have been added.
14 They produce data files usable by plotting utilities like gnuplot.
1415
15 The option "--size" has been added as a synonym of "--max-size".
16 The option "-K, --skip-size" has been extended to accept a maximum skip
17 size and to disable skipping.
1618
17 Trimming is now done from both edges of each non-trimmed block. Largest
18 blocks are trimmed first.
19 The long name of option "-r" has been changed to "--retry-passes" to
20 make it clear that ddrescue tries each sector only once per retry pass.
1921
20 Largest blocks are now split first until logfile reaches
21 "--logfile-size" entries.
22 The short name of option "--generate-mode" has been changed to "-G".
2223
23 Ddrescue now terminates with an error if an unexpected EOF would discard
24 any successfully read data, just as it does when the input file
25 disappears from /dev.
24 The default value of option "-l, --logfile-size" has been increased to
25 10000 (from 1000).
2626
27 During the copying phase, failed blocks containing one sector are marked
28 as bad-sector instead of as non-trimmed. This avoids reading a sector
29 twice when a cluster size of 1 is used.
27 If ddrescue is interrupted by a signal, it now terminates by raising the
28 signal received.
3029
31 Ddrescue now removes the last block from the logfile if it starts at the
32 end of the input file and is not marked as finished. This automatically
33 adjusts the logfile to shrinking input devices, like CD-ROMs written in
34 Track-At-Once mode.
30 The algorithm of the copying phase has been changed. It now marks as
31 non-trimmed just the failed blocks, skips beyond them, and tries the
32 skipped areas later in two additional passes (before trimming),
33 reversing the direction after each pass. The third pass is a sweeping
34 pass, with skipping disabled. The new method is faster around large
35 errors, keeps the logfile smaller, and produces better starting points
36 for trimming, which now tries the smallest blocks first.
3537
36 A bug has been fixed that prevented status to update after the system
37 clock had been put back.
38 Speed has been improved when using complex domains with option '-m,
39 --domain-logfile'.
3840
39 Slow reads are now ignored during the first 10 seconds.
41 Current total run time is now shown on the screen.
4042
41 Control-C no more overwrites status message.
43 The pass number and direction are now shown during the copying phase.
4244
43 Generate mode no more requires the "--force" option when outfile is not
44 a regular file.
45 The message "About to copy an unknown number of bytes" is now shown when
46 the size of the input file can't be determined.
4547
46 Ddrescuelog no more says that the logfile does not exist when it exists
47 but is empty.
48 The option "-B, --binary-prefixes" has been added to ddrescuelog.
4849
49 The new chapter "Using ddrescue safely" has been added to the manual.
50 The new option "-C, --complete-logfile" has been added to ddrescuelog.
5051
51 The manual now explains that only whole sectors can be read when "direct
52 disc access" is used.
52 The new option "-P, --compare-as-domain" has been added to ddrescuelog.
5353
54 "configure" now accepts options with a separate argument.
54 Many improvements have been made to the documentation.
5555
56 The target "install-bin" has been added to the Makefile.
56 "ddrescue.texinfo" has been renamed to "ddrescue.texi".
00 Description
11
22 GNU ddrescue is a data recovery tool. It copies data from one file or
3 block device (hard disc, cdrom, etc) to another, trying hard to rescue
4 data in case of read errors.
3 block device (hard disc, cdrom, etc) to another, trying to rescue the
4 good parts first in case of read errors.
55
66 Ddrescuelog is a tool that manipulates ddrescue logfiles, shows logfile
77 contents, converts logfiles to/from other formats, compares logfiles,
2323 gaps without wiping out the data already rescued.
2424
2525 Automatic merging of backups: If you have two or more damaged copies of
26 a file, cdrom, etc, and run ddrescue on all of them, one at a time,
27 with the same output file, you will probably obtain a complete and
28 error-free file. This is so because the probability of having damaged
29 areas at the same places on different input files is very low. Using
30 the logfile, only the needed blocks are read from the second and
31 successive copies.
26 a file, cdrom, etc, and run ddrescue on all of them, one at a time, with
27 the same output file, you will probably obtain a complete and error-free
28 file. This is so because the probability of having the same area damaged
29 in all copies is low. Using the logfile, only the needed blocks are read
30 from the second and successive copies.
3231
33 Ddrescue recommends lzip for compression of backups because of its
34 reliability and data recovery capabilities, including error-checked
35 merging of backup copies. Lziprecover makes lzip files resistant to
36 bit-flip, one of the most common forms of data corruption, and its
37 recovery capabilities contribute to make of the lzip format one of the
38 best formats for long-term data archiving. The combination ddrescue +
39 lziprecover is the best option for recovering data from multiple damaged
40 copies.
32 Ddrescue recommends lzip for compression of backups because the lzip
33 format is designed for long-term data archiving and provides data
34 recovery capabilities which nicely complement those of ddrescue.
35 (Ddrescue fills unreadable sectors with data from other copies, while
36 lziprecover corrects corrupt sectors with data from other copies). If
37 the cause of file corruption is damaged media, the combination ddrescue
38 + lziprecover is the best option for recovering data from multiple
39 damaged copies.
4140
4241 Recordable CD and DVD media keep their data only for a finite time
4342 (typically for many years). After that time, data loss develops slowly
6968 data, marking bad areas or even, in some cases, "repair" damaged
7069 sectors.
7170
71 One of the great strengths of ddrescue is that it is interface-agnostic,
72 and so can be used for any kind of device supported by your kernel (ATA,
73 SATA, SCSI, old MFM drives, floppy discs, or even flash media cards like
74 SD).
7275
73 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
74 Antonio Diaz Diaz.
76
77 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
78 2014 Antonio Diaz Diaz.
7579
7680 This file is free documentation: you have unlimited permission to copy,
7781 distribute and modify it.
00 /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
1 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
1 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
22 Antonio Diaz Diaz.
33
44 This library is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
6 the Free Software Foundation, either version 2 of the License, or
77 (at your option) any later version.
88
99 This library is distributed in the hope that it will be useful,
119119
120120 if( index < 0 )
121121 {
122 error_ = "invalid option -- "; error_ += c;
122 error_ = "invalid option -- '"; error_ += c; error_ += '\'';
123123 return false;
124124 }
125125
134134 {
135135 if( !arg || !arg[0] )
136136 {
137 error_ = "option requires an argument -- "; error_ += c;
137 error_ = "option requires an argument -- '"; error_ += c;
138 error_ += '\'';
138139 return false;
139140 }
140141 data.back().argument = arg; ++argind; cind = 0;
155156 while( argind < argc )
156157 {
157158 const unsigned char ch1 = argv[argind][0];
158 const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 );
159 const unsigned char ch2 = ch1 ? argv[argind][1] : 0;
159160
160161 if( ch1 == '-' && ch2 ) // we found an option
161162 {
162163 const char * const opt = argv[argind];
163 const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0;
164 const char * const arg = ( argind + 1 < argc ) ? argv[argind+1] : 0;
164165 if( ch2 == '-' )
165166 {
166167 if( !argv[argind][2] ) { ++argind; break; } // we found "--"
00 /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
1 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
1 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
22 Antonio Diaz Diaz.
33
44 This library is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
6 the Free Software Foundation, either version 2 of the License, or
77 (at your option) any later version.
88
99 This library is distributed in the hope that it will be useful,
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
2020 #include <algorithm>
2121 #include <climits>
2222 #include <cstdio>
23 #include <cstdlib>
2324 #include <string>
2425 #include <vector>
2526 #include <stdint.h>
2627
2728 #include "block.h"
28 #include "ddrescue.h"
2929
3030
3131 // Align pos to next boundary if size is big enough
6565 {
6666 if( this->follows( b ) ) pos_ = b.pos_;
6767 else if( !b.follows( *this ) ) return false;
68 if( b.size_ > LLONG_MAX - end() )
69 internal_error( "size overflow joining two Blocks." );
6870 size_ += b.size_;
69 if( size_ < 0 || size_ > LLONG_MAX - pos_ )
70 internal_error( "size overflow joining two Blocks" );
7171 return true;
72 }
73
74
75 // shift the border of two consecutive Blocks
76 void Block::shift( Block & b, const long long pos )
77 {
78 if( end() != b.pos_ || pos <= pos_ || pos >= b.end() )
79 internal_error( "bad argument shifting the border of two Blocks." );
80 b.size_ = b.end() - pos; b.pos_ = pos; size_ = pos - pos_;
7281 }
7382
7483
8594 }
8695
8796
88 void Domain::crop( const Block & b )
97 Domain::Domain( const long long p, const long long s,
98 const char * const logname, const bool loose )
8999 {
90 for( unsigned i = block_vector.size(); i > 0; )
100 const Block b( p, s );
101 if( !logname || !logname[0] ) { block_vector.push_back( b ); return; }
102 Logfile logfile( logname );
103 if( !logfile.read_logfile( loose ? '?' : 0 ) )
91104 {
92 block_vector[--i].crop( b );
93 if( block_vector[i].size() <= 0 )
94 block_vector.erase( block_vector.begin() + i );
105 char buf[80];
106 snprintf( buf, sizeof buf,
107 "Logfile '%s' does not exist or is not readable.", logname );
108 show_error( buf );
109 std::exit( 1 );
95110 }
96 if( block_vector.size() == 0 ) block_vector.push_back( Block( 0, 0 ) );
111 logfile.compact_sblock_vector();
112 for( int i = 0; i < logfile.sblocks(); ++i )
113 {
114 const Sblock & sb = logfile.sblock( i );
115 if( sb.status() == Sblock::finished ) block_vector.push_back( sb );
116 }
117 if( block_vector.empty() ) block_vector.push_back( Block( 0, 0 ) );
118 else this->crop( b );
97119 }
98120
99121
100 void Domain::crop_by_file_size( const long long end )
122 void Domain::crop( const Block & b )
101123 {
102 unsigned i = block_vector.size();
103 while( i > 0 && block_vector[i-1].pos() >= end ) --i;
104 if( i == 0 )
105 block_vector[0].assign( 0, 0 );
106 else
107 {
108 Block & b = block_vector[--i];
109 if( b.includes( end ) ) b.size( end - b.pos() );
110 }
111 block_vector.erase( block_vector.begin() + i + 1, block_vector.end() );
124 unsigned r = block_vector.size();
125 while( r > 0 && b < block_vector[r-1] ) --r;
126 if( r > 0 ) block_vector[r-1].crop( b );
127 if( r <= 0 || block_vector[r-1].size() <= 0 ) // no block overlaps b
128 { block_vector.clear(); block_vector.push_back( Block( 0, 0 ) ); return; }
129 if( r < block_vector.size() ) // remove blocks beyond b
130 block_vector.erase( block_vector.begin() + r, block_vector.end() );
131 if( b.pos() <= 0 ) return;
132 --r; // block_vector[r] is now the last non-cropped-out block
133 unsigned l = 0;
134 while( l < r && block_vector[l] < b ) ++l;
135 if( l < r ) block_vector[l].crop( b ); // crop block overlapping b
136 if( l > 0 ) // remove blocks before b
137 block_vector.erase( block_vector.begin(), block_vector.begin() + l );
112138 }
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
2828
2929 class Block
3030 {
31 long long pos_, size_; // pos + size <= LLONG_MAX
32
33 public:
34 Block( const long long p, const long long s )
35 : pos_( p ), size_( s ) {}
31 long long pos_, size_; // pos >= 0 && size >= 0 && pos + size <= LLONG_MAX
32
33 void fix_size() // limit size_ to largest possible value
34 { if( size_ < 0 || size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; }
35
36 public:
37 Block( const long long p, const long long s ) : pos_( p ), size_( s )
38 { if( p < 0 ) { pos_ = 0; if( s > 0 ) size_ -= std::min( s, -p ); }
39 fix_size(); }
3640
3741 long long pos() const { return pos_; }
3842 long long size() const { return size_; }
3943 long long end() const { return pos_ + size_; }
4044
41 void pos( const long long p ) { pos_ = p; }
42 void size( const long long s ) { size_ = s; }
43 void end( const long long e )
44 { pos_ = e - size_; if( pos_ < 0 ) { size_ += pos_; pos_ = 0; } }
45 void pos( const long long p )
46 { pos_ = std::max( p, 0LL );
47 if( size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; }
48 void size( const long long s ) { size_ = s; fix_size(); }
49 void end( long long e )
50 { if( e < 0 ) e = LLONG_MAX;
51 if( size_ <= e ) pos_ = e - size_; else { pos_ = 0; size_ = e; } }
4552 Block & assign( const long long p, const long long s )
46 { pos_ = p; size_ = s; return *this; }
47
48 void fix_size() // limit size_ to largest possible value
49 { if( size_ < 0 || size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; }
53 {
54 pos_ = p; size_ = s;
55 if( p < 0 ) { pos_ = 0; if( s > 0 ) size_ -= std::min( s, -p ); }
56 fix_size(); return *this;
57 }
58
5059 void align_pos( const int alignment );
5160 void align_end( const int alignment );
52 void inc_size( const long long delta ) { size_ += delta; }
5361
5462 bool operator==( const Block & b ) const
5563 { return pos_ == b.pos_ && size_ == b.size_; }
5664 bool operator!=( const Block & b ) const
5765 { return pos_ != b.pos_ || size_ != b.size_; }
66
67 bool operator<( const Block & b ) const { return ( end() <= b.pos() ); }
5868
5969 bool follows( const Block & b ) const
6070 { return ( pos_ == b.end() ); }
6272 { return ( pos_ <= b.pos_ && end() >= b.end() ); }
6373 bool includes( const long long pos ) const
6474 { return ( pos_ <= pos && end() > pos ); }
75 bool strictly_includes( const long long pos ) const
76 { return ( pos_ < pos && end() > pos ); }
6577
6678 void crop( const Block & b );
6779 bool join( const Block & b );
80 void shift( Block & b, const long long pos );
6881 Block split( long long pos, const int hardbs = 1 );
6982 };
7083
107120 std::vector< Block > block_vector; // blocks are ordered and don't overlap
108121
109122 public:
110 Domain( const long long p, const long long s, const char * const logname = 0 );
111
112 long long pos() const { return block_vector[0].pos(); }
113 long long size() const
114 { return block_vector.back().end() - block_vector[0].pos(); }
123 Domain( const long long p, const long long s,
124 const char * const logname = 0, const bool loose = false );
125
126 long long pos() const { return block_vector.front().pos(); }
115127 long long end() const { return block_vector.back().end(); }
128 long long size() const { return end() - pos(); }
129 const Block & block( const int i ) const { return block_vector[i]; }
116130 int blocks() const { return (int)block_vector.size(); }
131 bool empty() const { return ( end() <= pos() ); }
132 bool full() const { return ( !empty() && end() >= LLONG_MAX ); }
117133
118134 long long in_size() const
119135 {
131147 return false;
132148 }
133149
134 bool operator<( const Block & b ) const
135 { return ( block_vector.back().end() <= b.pos() ); }
136
137 long long breaks_block_by( const Block & b ) const
138 {
139 for( unsigned i = 0; i < block_vector.size(); ++i )
150 bool operator<( const Block & b ) const { return ( end() <= b.pos() ); }
151
152 bool includes( const Block & b ) const
153 {
154 unsigned l = 0, r = block_vector.size();
155 while( l < r )
140156 {
141 const Block & db = block_vector[i];
142 if( b.includes( db.pos() ) && b.pos() < db.pos() ) return db.pos();
143 const long long end = db.end();
144 if( b.includes( end ) && b.pos() < end ) return end;
157 const int m = ( l + r ) / 2;
158 const Block & db = block_vector[m];
159 if( db.includes( b ) ) return true;
160 if( db < b ) l = m + 1; else if( b < db ) r = m; else break;
145161 }
146 return 0;
147 }
148
149 bool includes( const Block & b ) const
150 {
151 for( unsigned i = 0; i < block_vector.size(); ++i )
152 if( block_vector[i].includes( b ) ) return true;
153162 return false;
154163 }
155164
163172 void clear()
164173 { block_vector.clear(); block_vector.push_back( Block( 0, 0 ) ); }
165174 void crop( const Block & b );
166 void crop_by_file_size( const long long end );
167 };
175 void crop_by_file_size( const long long size ) { crop( Block( 0, size ) ); }
176 };
177
178
179 class Logfile
180 {
181 public:
182 enum Status
183 { copying = '?', trimming = '*', splitting = '/', retrying = '-',
184 filling = 'F', generating = 'G', finished = '+' };
185
186 private:
187 long long current_pos_;
188 const char * const filename_;
189 std::string current_msg;
190 Status current_status_;
191 mutable int index_; // cached index of last find or change
192 bool read_only_;
193 std::vector< Sblock > sblock_vector; // note: blocks are consecutive
194
195 void erase_sblock( const int i )
196 { sblock_vector.erase( sblock_vector.begin() + i ); }
197 void insert_sblock( const int i, const Sblock & sb )
198 { sblock_vector.insert( sblock_vector.begin() + i, sb ); }
199
200 public:
201 explicit Logfile( const char * const logname )
202 : current_pos_( 0 ), filename_( logname ), current_status_( copying ),
203 index_( 0 ), read_only_( false ) {}
204
205 void compact_sblock_vector();
206 void extend_sblock_vector( const long long isize );
207 bool truncate_vector( const long long end, const bool force = false );
208 void make_blank()
209 { sblock_vector.clear();
210 sblock_vector.push_back( Sblock( 0, -1, Sblock::non_tried ) ); }
211 bool read_logfile( const int default_sblock_status = 0 );
212 int write_logfile( FILE * f = 0, const bool timestamp = false ) const;
213
214 bool blank() const;
215 long long current_pos() const { return current_pos_; }
216 Status current_status() const { return current_status_; }
217 const char * filename() const { return filename_; }
218 bool read_only() const { return read_only_; }
219
220 void current_pos( const long long pos ) { current_pos_ = pos; }
221 void current_status( const Status st, const char * const msg = "" )
222 { current_status_ = st;
223 current_msg = ( st == finished ) ? "Finished" : msg; }
224
225 Block extent() const
226 { if( sblock_vector.empty() ) return Block( 0, 0 );
227 return Block( sblock_vector.front().pos(),
228 sblock_vector.back().end() - sblock_vector.front().pos() ); }
229 const Sblock & sblock( const int i ) const { return sblock_vector[i]; }
230 int sblocks() const { return (int)sblock_vector.size(); }
231 void change_sblock_status( const int i, const Sblock::Status st )
232 { sblock_vector[i].status( st ); }
233
234 void split_by_domain_borders( const Domain & domain );
235 void split_by_logfile_borders( const Logfile & logfile );
236 bool try_split_sblock_by( const long long pos, const int i )
237 {
238 if( sblock_vector[i].strictly_includes( pos ) )
239 { insert_sblock( i, sblock_vector[i].split( pos ) ); return true; }
240 return false;
241 }
242
243 int find_index( const long long pos ) const;
244 int find_largest_sblock( const Sblock::Status st,
245 const Domain & domain ) const;
246 int find_smallest_sblock( const Sblock::Status st,
247 const Domain & domain, const int min_size ) const;
248 void find_chunk( Block & b, const Sblock::Status st,
249 const Domain & domain, const int alignment = 1 ) const;
250 void rfind_chunk( Block & b, const Sblock::Status st,
251 const Domain & domain, const int alignment = 1 ) const;
252 int change_chunk_status( const Block & b, const Sblock::Status st,
253 const Domain & domain );
254
255 static bool isstatus( const int st )
256 { return ( st == copying || st == trimming || st == splitting ||
257 st == retrying || st == filling || st == generating ||
258 st == finished ); }
259 static const char * status_name( const Status st );
260 };
261
262
263 // Defined in main_common.cc
264 //
265 extern int verbosity;
266 void show_error( const char * const msg,
267 const int errcode = 0, const bool help = false );
268 void internal_error( const char * const msg );
269 int empty_domain();
270 int not_readable( const char * const logname );
271 int not_writable( const char * const logname );
272 long initial_time();
273 bool write_logfile_header( FILE * const f, const char * const logtype );
274 bool write_timestamp( FILE * const f );
275 bool write_final_timestamp( FILE * const f );
276 const char * format_num( long long num, long long limit = 999999,
277 const int set_prefix = 0 );
00 #! /bin/sh
11 # configure script for GNU ddrescue - Data recovery tool
22 # Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
3 # 2013 Antonio Diaz Diaz.
3 # 2013, 2014 Antonio Diaz Diaz.
44 #
55 # This configure script is free software: you have unlimited permission
66 # to copy, distribute and modify it.
77
88 pkgname=ddrescue
9 pkgversion=1.17
9 pkgversion=1.18.1
1010 progname=ddrescue
11 srctrigger=ddrescue.h
11 srctrigger=doc/${pkgname}.texi
1212
1313 # clear some things potentially inherited from environment.
1414 LC_ALL=C
6464 echo " --datarootdir=DIR base directory for doc and data [${datarootdir}]"
6565 echo " --infodir=DIR info files directory [${infodir}]"
6666 echo " --mandir=DIR man pages directory [${mandir}]"
67 echo " CXX=COMPILER C++ compiler to use [g++]"
67 echo " CXX=COMPILER C++ compiler to use [${CXX}]"
6868 echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
6969 echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
7070 echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
166166 cat > Makefile << EOF
167167 # Makefile for GNU ddrescue - Data recovery tool
168168 # Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
169 # 2013 Antonio Diaz Diaz.
169 # 2013, 2014 Antonio Diaz Diaz.
170170 # This file was generated automatically by configure. Do not edit.
171171 #
172172 # This Makefile is free software: you have unlimited permission
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1515 along with this program. If not, see <http://www.gnu.org/licenses/>.
1616 */
1717
18 class Logbook
19 {
20 public:
21 enum Status
22 { copying = '?', trimming = '*', splitting = '/', retrying = '-',
23 filling = 'F', generating = 'G', finished = '+' };
24
25 private:
18 class Logbook : public Logfile
19 {
2620 const long long offset_; // outfile offset (opos - ipos);
27 long long current_pos_;
2821 long long logfile_isize_;
29 Status current_status_;
3022 Domain & domain_; // rescue domain
3123 uint8_t *iobuf_base, *iobuf_; // iobuf is aligned to page and hardbs
32 const char * const filename_;
3324 const int hardbs_, softbs_;
3425 const char * final_msg_;
3526 int final_errno_;
36 mutable int index_; // cached index of last find or change
37 std::vector< Sblock > sblock_vector; // note: blocks are consecutive
3827 long ul_t1; // variable for update_logfile
3928 bool logfile_exists_;
4029
4130 Logbook( const Logbook & ); // declared as private
4231 void operator=( const Logbook & ); // declared as private
4332
44 void erase_sblock( const int i )
45 { sblock_vector.erase( sblock_vector.begin() + i ); }
46 void insert_sblock( const int i, const Sblock & sb )
47 { sblock_vector.insert( sblock_vector.begin() + i, sb ); }
48 void split_domain_border_sblocks();
49
50 public:
51 Logbook( const long long offset, const long long isize,
52 Domain & dom, const char * const logname,
53 const int cluster, const int hardbs,
54 const bool complete_only, const bool do_not_read = false );
33 public:
34 Logbook( const long long offset, const long long isize, Domain & dom,
35 const char * const logname, const int cluster,
36 const int hardbs, const bool complete_only );
5537 ~Logbook() { delete[] iobuf_base; }
5638
57 bool blank() const;
58 void compact_sblock_vector();
59 bool update_logfile( const int odes = -1, const bool force = false,
60 const bool retry = true );
61 void write_logfile( FILE * const f ) const;
62
63 long long current_pos() const { return current_pos_; }
64 Status current_status() const { return current_status_; }
39 bool update_logfile( const int odes = -1, const bool force = false );
40
6541 const Domain & domain() const { return domain_; }
66 const char * filename() const { return filename_; }
6742 uint8_t * iobuf() const { return iobuf_; }
6843 int hardbs() const { return hardbs_; }
6944 int softbs() const { return softbs_; }
7348 bool logfile_exists() const { return logfile_exists_; }
7449 long long logfile_isize() const { return logfile_isize_; }
7550
76 void current_pos( const long long pos ) { current_pos_ = pos; }
77 void current_status( const Status st ) { current_status_ = st; }
78 void final_msg( const char * const msg ) { final_msg_ = msg; }
79 void final_errno( const int e ) { final_errno_ = e; }
80
81 const Sblock & sblock( const int i ) const
82 { return sblock_vector[i]; }
83 int sblocks() const { return (int)sblock_vector.size(); }
84 void change_sblock_status( const int i, const Sblock::Status st )
85 { sblock_vector[i].status( st ); }
86 void split_sblock_by( const long long pos, const int i )
87 {
88 if( sblock_vector[i].includes( pos ) )
89 insert_sblock( i, sblock_vector[i].split( pos ) );
90 }
91 bool truncate_vector( const long long end, const bool force = false );
51 void final_msg( const char * const msg, const int e = 0 )
52 { final_msg_ = msg; final_errno_ = e; }
53
9254 void truncate_domain( const long long end )
9355 { domain_.crop_by_file_size( end ); }
94
95 int find_index( const long long pos ) const;
96 int find_largest_sblock( const Sblock::Status st ) const;
97 int find_smallest_sblock( const Sblock::Status st ) const;
98 void find_chunk( Block & b, const Sblock::Status st,
99 const int alignment = 0 ) const;
100 void rfind_chunk( Block & b, const Sblock::Status st,
101 const int alignment = 0 ) const;
102 int change_chunk_status( const Block & b, const Sblock::Status st );
103
104 static bool isstatus( const int st )
105 { return ( st == copying || st == trimming || st == splitting ||
106 st == retrying || st == filling || st == generating ||
107 st == finished ); }
108 static const char * status_name( const Status st );
10956 };
11057
11158
12168 // variables for show_status
12269 long long a_rate, c_rate, first_size, last_size;
12370 long long last_ipos;
124 long t0, t1;
71 long t0, t1; // start, current times
72 int oldlen;
12573
12674 int fill_areas( const std::string & filltypes );
12775 int fill_block( const Block & b );
128 void show_status( const long long ipos, bool force = false );
76 void show_status( const long long ipos, const char * const msg = 0,
77 bool force = false );
12978
13079 public:
13180 Fillbook( const long long offset, Domain & dom,
13584 ignore_write_errors_( ignore_write_errors ),
13685 synchronous_( synchronous ),
13786 a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ),
138 last_ipos( 0 ), t0( 0 ), t1( 0 )
87 last_ipos( 0 ), t0( 0 ), t1( 0 ), oldlen( 0 )
13988 {}
14089
14190 int do_fill( const int odes, const std::string & filltypes );
15099 // variables for show_status
151100 long long a_rate, c_rate, first_size, last_size;
152101 long long last_ipos;
153 long t0, t1;
102 long t0, t1; // start, current times
154103 int oldlen;
155104
156105 void check_block( const Block & b, int & copied_size, int & error_size );
172121
173122 struct Rb_options
174123 {
175 enum { default_skipbs = 65536, max_skipbs = 1 << 30 };
124 enum { default_skipbs = 65536, max_max_skipbs = 1 << 30 };
176125
177126 long long max_error_rate;
178127 long long min_outfile_size;
181130 int max_errors;
182131 int max_logfile_size;
183132 int max_retries;
133 int o_direct; // O_DIRECT or 0
184134 int skipbs; // initial size to skip on read error
135 int max_skipbs; // maximum size to skip on read error
185136 bool complete_only;
186137 bool new_errors_only;
187138 bool nosplit;
139 bool notrim;
140 bool reopen_on_error;
188141 bool retrim;
142 bool reverse;
189143 bool sparse;
190144 bool try_again;
191145
192146 Rb_options()
193147 : max_error_rate( -1 ), min_outfile_size( -1 ), min_read_rate( -1 ),
194 timeout( -1 ), max_errors( -1 ), max_logfile_size( 1000 ),
195 max_retries( 0 ), skipbs( default_skipbs ), complete_only( false ),
196 new_errors_only( false ), nosplit( false ), retrim( false ),
148 timeout( -1 ), max_errors( -1 ), max_logfile_size( 10000 ),
149 max_retries( 0 ), o_direct( 0 ), skipbs( default_skipbs ),
150 max_skipbs( max_max_skipbs ), complete_only( false ),
151 new_errors_only( false ), nosplit( false ), notrim( false ),
152 reopen_on_error( false ), retrim( false ), reverse( false ),
197153 sparse( false ), try_again( false )
198154 {}
199155
203159 min_read_rate == o.min_read_rate && timeout == o.timeout &&
204160 max_errors == o.max_errors &&
205161 max_logfile_size == o.max_logfile_size &&
206 max_retries == o.max_retries && skipbs == o.skipbs &&
162 max_retries == o.max_retries && o_direct == o.o_direct &&
163 skipbs == o.skipbs && max_skipbs == o.max_skipbs &&
207164 complete_only == o.complete_only &&
208165 new_errors_only == o.new_errors_only &&
209 nosplit == o.nosplit && retrim == o.retrim &&
166 nosplit == o.nosplit && notrim == o.notrim &&
167 reopen_on_error == o.reopen_on_error &&
168 retrim == o.retrim && reverse == o.reverse &&
210169 sparse == o.sparse && try_again == o.try_again ); }
211170 bool operator!=( const Rb_options & o ) const
212171 { return !( *this == o ); }
218177 long long error_rate;
219178 long long sparse_size; // end position of pending writes
220179 long long recsize, errsize; // total recovered and error sizes
180 const Domain * const test_domain; // good/bad map for test mode
221181 const char * const iname_;
222 const int max_skip_size; // maximum size to skip on read error
223182 int e_code; // error code for errors_or_timeout
224183 // 1 rate, 2 errors, 4 timeout
225184 int errors; // error areas found so far
226185 int ides_, odes_; // input and output file descriptors
227 const bool synchronous_;
186 const bool access_works, synchronous_;
228187 // variables for update_rates
229188 long long a_rate, c_rate, first_size, last_size;
230189 long long last_ipos;
231190 long t0, t1, ts; // start, current, last successful
232191 int oldlen;
233192 bool rates_updated;
193 bool first_post; // variable for show_status
234194
235195 bool extend_outfile_size();
236196 int copy_block( const Block & b, int & copied_size, int & error_size );
241201 void reduce_min_read_rate()
242202 { if( min_read_rate > 0 ) min_read_rate /= 10; }
243203 bool slow_read() const
244 { return ( t1 - t0 >= 10 && // no slow reads for first 10s
204 { return ( t1 - t0 >= 30 && // no slow reads for first 30s
245205 ( ( min_read_rate > 0 && c_rate < min_read_rate &&
246206 c_rate < a_rate / 2 ) ||
247207 ( min_read_rate == 0 && c_rate < a_rate / 10 ) ) ); }
248 int copy_and_update( const Block & b, const Sblock::Status st,
249 int & copied_size, int & error_size,
250 const char * const msg, bool & first_post,
251 const bool forward );
208 int update( const Block & b, const Sblock::Status st,
209 const int copied_size, const int error_size );
210 int copy_and_update( const Block & b, int & error_size,
211 const char * const msg, const bool forward );
212 int copy_and_update2( const Block & b, int & copied_size,
213 int & error_size, const char * const msg,
214 const bool forward, const bool small_try );
215 bool reopen_infile();
252216 int copy_non_tried();
253 int rcopy_non_tried();
217 int fcopy_non_tried( const char * const msg, const int pass );
218 int rcopy_non_tried( const char * const msg, const int pass );
254219 int trim_errors();
255 int split_errors( const bool reverse );
220 int split_errors();
256221 int copy_errors();
257222 int rcopy_errors();
258223 void update_rates( const bool force = false );
260225 const bool force = false );
261226 public:
262227 Rescuebook( const long long offset, const long long isize,
263 Domain & dom, const Rb_options & rb_opts,
264 const char * const iname, const char * const logname,
265 const int cluster, const int hardbs,
266 const bool synchronous );
267
268 int do_rescue( const int ides, const int odes, const bool reverse );
228 Domain & dom, const Domain * const test_dom,
229 const Rb_options & rb_opts, const char * const iname,
230 const char * const logname, const int cluster,
231 const int hardbs, const bool synchronous );
232
233 int do_rescue( const int ides, const int odes );
269234 };
270235
271236
287252 const char * format_time( long t );
288253 bool interrupted();
289254 void set_signals();
290
291
292 // Defined in main_common.cc
293 //
294 extern int verbosity;
295 void internal_error( const char * const msg );
296 void show_error( const char * const msg,
297 const int errcode = 0, const bool help = false );
298 void write_logfile_header( FILE * const f );
299 const char * format_num( long long num, long long limit = 999999,
300 const int set_prefix = 0 );
255 int signaled_exit();
00 /* GNU ddrescuelog - Tool for ddrescue logfiles
1 Copyright (C) 2011, 2012, 2013 Antonio Diaz Diaz.
1 Copyright (C) 2011, 2012, 2013, 2014 Antonio Diaz Diaz.
22
33 This program is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
2020 (eg, bug) which caused ddrescuelog to panic.
2121 */
2222
23 #include <algorithm>
2324 #include <cerrno>
2425 #include <climits>
2526 #include <cstdio>
2627 #include <cstdlib>
2728 #include <cstring>
29 #include <ctime>
2830 #include <string>
2931 #include <vector>
3032 #include <stdint.h>
4042 const char * const program_name = "ddrescuelog";
4143 const char * invocation_name = 0;
4244
43 enum Mode { m_none, m_and, m_change, m_compare, m_create, m_delete,
44 m_done_st, m_invert, m_list, m_or, m_status, m_xor };
45 enum Mode { m_none, m_and, m_change, m_compare, m_complete, m_create,
46 m_delete, m_done_st, m_invert, m_list, m_or, m_status, m_xor };
4547
4648
4749 void show_help( const int hardbs )
5153 "other formats, compares them, and tests rescue status.\n"
5254 "\nUsage: %s [options] logfile\n", invocation_name );
5355 std::printf( "\nOptions:\n"
54 " -h, --help display this help and exit\n"
55 " -V, --version output version information and exit\n"
56 " -a, --change-types=<ot>,<nt> change the block types of a logfile\n"
57 " -b, --block-size=<bytes> block size in bytes [default %d]\n", hardbs );
58 std::printf( " -c, --create-logfile[=<tt>] create logfile from list of blocks [+-]\n"
59 " -d, --delete-if-done delete the logfile if rescue is finished\n"
60 " -D, --done-status return 0 if rescue is finished\n"
61 " -f, --force overwrite existing output files\n"
62 " -i, --input-position=<bytes> starting position of rescue domain [0]\n"
63 " -l, --list-blocks=<types> print block numbers of given types (?*/-+)\n"
64 " -m, --domain-logfile=<file> restrict domain to finished blocks in file\n"
65 " -n, --invert-logfile invert block types (finished <-> others)\n"
66 " -o, --output-position=<bytes> starting position in output file [ipos]\n"
67 " -p, --compare-logfile=<file> compare block types in domain of both files\n"
68 " -q, --quiet suppress all messages\n"
69 " -s, --size=<bytes> maximum size of rescue domain to be processed\n"
70 " -t, --show-status show a summary of logfile contents\n"
71 " -v, --verbose be verbose (a 2nd -v gives more)\n"
72 " -x, --xor-logfile=<file> XOR the finished blocks in file with logfile\n"
73 " -y, --and-logfile=<file> AND the finished blocks in file with logfile\n"
74 " -z, --or-logfile=<file> OR the finished blocks in file with logfile\n"
75 "Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,\n"
76 "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
56 " -h, --help display this help and exit\n"
57 " -V, --version output version information and exit\n"
58 " -a, --change-types=<ot>,<nt> change the block types of logfile\n"
59 " -b, --block-size=<bytes> block size in bytes [default %d]\n", hardbs );
60 std::printf( " -B, --binary-prefixes show binary multipliers in numbers [SI]\n"
61 " -c, --create-logfile[=<tt>] create logfile from list of blocks [+-]\n"
62 " -C, --complete-logfile[=<t>] complete logfile adding blocks of type t [?]\n"
63 " -d, --delete-if-done delete the logfile if rescue is finished\n"
64 " -D, --done-status return 0 if rescue is finished\n"
65 " -f, --force overwrite existing output files\n"
66 " -i, --input-position=<bytes> starting position of rescue domain [0]\n"
67 " -l, --list-blocks=<types> print block numbers of given types (?*/-+)\n"
68 " -L, --loose-domain accept an incomplete domain logfile\n"
69 " -m, --domain-logfile=<file> restrict domain to finished blocks in file\n"
70 " -n, --invert-logfile invert block types (finished <--> others)\n"
71 " -o, --output-position=<bytes> starting position in output file [ipos]\n"
72 " -p, --compare-logfile=<file> compare block types in domain of both files\n"
73 " -P, --compare-as-domain=<file> like -p but compare finished blocks only\n"
74 " -q, --quiet suppress all messages\n"
75 " -s, --size=<bytes> maximum size of rescue domain to be processed\n"
76 " -t, --show-status show a summary of logfile contents\n"
77 " -v, --verbose be verbose (a 2nd -v gives more)\n"
78 " -x, --xor-logfile=<file> XOR the finished blocks in file with logfile\n"
79 " -y, --and-logfile=<file> AND the finished blocks in file with logfile\n"
80 " -z, --or-logfile=<file> OR the finished blocks in file with logfile\n"
81 "Numbers may be in decimal, hexadecimal or octal, and may be followed by a\n"
82 "multiplier: s = sectors, k = 1000, Ki = 1024, M = 10^6, Mi = 2^20, etc...\n"
7783 "\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
7884 "not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
7985 "invalid input file, 3 for an internal consistency error (eg, bug) which\n"
8490 }
8591
8692
87 void set_types( const std::string & arg,
88 std::string & types1, std::string & types2 )
93 void parse_types( const std::string & arg,
94 std::string & types1, std::string & types2 )
8995 {
9096 std::string * p = &types1;
9197 bool error = false, comma_found = false;
103109 if( !Sblock::isstatus( ch ) ) { error = true; break; }
104110 *p += ch;
105111 }
106 if( types1.size() == 0 || types2.size() == 0 ) error = true;
112 if( types1.empty() || types2.empty() ) error = true;
107113 if( error )
108114 {
109115 show_error( "Invalid type for 'change-types' option.", 0, true );
114120 }
115121
116122
117 void set_types( const std::string & arg,
118 Sblock::Status & type1, Sblock::Status & type2 )
119 {
120 if( arg.size() == 0 ) return;
123 void parse_2types( const std::string & arg,
124 Sblock::Status & type1, Sblock::Status & type2 )
125 {
126 if( arg.empty() ) return;
121127 if( arg.size() != 2 || arg[0] == arg[1] ||
122128 !Sblock::isstatus( arg[0] ) || !Sblock::isstatus( arg[1] ) )
123129 {
129135 }
130136
131137
132 void verify_logname_and_domain( const Logbook & logbook )
133 {
134 if( !logbook.logfile_exists() )
135 {
136 char buf[80];
137 snprintf( buf, sizeof buf, "Logfile '%s' does not exist.",
138 logbook.filename() );
139 show_error( buf );
138 void parse_type( const std::string & arg, Sblock::Status & complete_type )
139 {
140 if( arg.empty() ) return;
141 if( arg.size() != 1 || !Sblock::isstatus( arg[0] ) )
142 {
143 show_error( "Invalid type for 'complete-logfile' option.", 0, true );
140144 std::exit( 1 );
141145 }
142 if( logbook.domain().size() == 0 )
143 { show_error( "Empty domain." ); std::exit( 0 ); }
146 complete_type = Sblock::Status( arg[0] );
144147 }
145148
146149
147150 int do_logic_ops( Domain & domain, const char * const logname,
148151 const char * const second_logname, const Mode program_mode )
149152 {
150 Domain domain2( domain );
151 Logbook logbook( 0, 0, domain, logname, 1, 1, true );
152 verify_logname_and_domain( logbook );
153 const Logbook logbook2( 0, 0, domain2, second_logname, 1, 1, true );
154 verify_logname_and_domain( logbook2 );
155
156 for( int i = 0; i < logbook.sblocks(); ++i )
157 {
158 const Sblock & sb = logbook.sblock( i );
159 if( !logbook.domain().includes( sb ) )
160 { if( logbook.domain() < sb ) break; else continue; }
153 Logfile logfile( logname );
154 if( !logfile.read_logfile() ) return not_readable( logname );
155 logfile.compact_sblock_vector();
156
157 Logfile logfile2( second_logname );
158 if( !logfile2.read_logfile() ) return not_readable( second_logname );
159 logfile2.compact_sblock_vector();
160
161 domain.crop( logfile.extent() );
162 domain.crop( logfile2.extent() );
163 if( domain.empty() ) return empty_domain();
164 logfile.split_by_domain_borders( domain );
165 logfile2.split_by_domain_borders( domain );
166 logfile.split_by_logfile_borders( logfile2 );
167 logfile2.split_by_logfile_borders( logfile );
168
169 for( int i = 0, j = 0; ; ++i, ++j )
170 {
171 while( i < logfile.sblocks() && !domain.includes( logfile.sblock( i ) ) )
172 ++i;
173 while( j < logfile2.sblocks() && !domain.includes( logfile2.sblock( j ) ) )
174 ++j;
175 if( i >= logfile.sblocks() || j >= logfile2.sblocks() ) break;
176 const Sblock & sb1 = logfile.sblock( i );
177 const Sblock & sb2 = logfile2.sblock( j );
178 if( sb1.pos() != sb2.pos() || sb1.size() != sb2.size() )
179 internal_error( "blocks got out of sync." );
180 const bool f1 = ( sb1.status() == Sblock::finished );
181 const bool f2 = ( sb2.status() == Sblock::finished );
161182 switch( program_mode )
162183 {
163184 case m_and:
164 {
165 if( sb.status() != Sblock::finished ) continue;
166 Block b( sb );
167 logbook2.find_chunk( b, Sblock::finished );
168 if( b.size() <= 0 || b.pos() >= sb.end() )
169 logbook.change_sblock_status( i, Sblock::bad_sector );
170 else if( b == sb ) continue;
171 else if( b.pos() == sb.pos() ) logbook.split_sblock_by( b.end(), i );
172 else
173 { logbook.change_chunk_status( Block( sb.pos(), b.pos() - sb.pos() ),
174 Sblock::bad_sector ); --i; }
175 } break;
185 if( f1 && !f2 ) logfile.change_sblock_status( i, Sblock::bad_sector );
186 break;
176187 case m_or:
177 {
178 if( sb.status() == Sblock::finished ) continue;
179 Block b( sb );
180 logbook2.find_chunk( b, Sblock::finished );
181 if( b.size() <= 0 || b.pos() >= sb.end() ) continue;
182 else if( b == sb )
183 logbook.change_sblock_status( i, Sblock::finished );
184 else if( b.pos() == sb.pos() )
185 { logbook.change_chunk_status( b, Sblock::finished ); --i; }
186 else logbook.split_sblock_by( b.end(), i );
187 } break;
188 if( !f1 && f2 ) logfile.change_sblock_status( i, Sblock::finished );
189 break;
188190 case m_xor:
189 {
190 const Sblock::Status st = ( ( sb.status() == Sblock::finished ) ?
191 Sblock::bad_sector : Sblock::finished );
192 Block b( sb );
193 logbook2.find_chunk( b, Sblock::finished );
194 if( b.size() <= 0 || b.pos() >= sb.end() ) continue;
195 else if( b == sb ) logbook.change_sblock_status( i, st );
196 else if( b.pos() == sb.pos() )
197 { logbook.change_chunk_status( b, st ); --i; }
198 else logbook.split_sblock_by( b.end(), i );
199 } break;
200 default: internal_error( "invalid program_mode" );
201 }
202 }
203 logbook.compact_sblock_vector();
204 logbook.write_logfile( stdout );
191 if( f1 != ( ( f1 || f2 ) && !( f1 && f2 ) ) )
192 logfile.change_sblock_status( i, f1 ? Sblock::bad_sector : Sblock::finished );
193 break;
194 default: internal_error( "invalid program_mode." );
195 }
196 }
197 logfile.compact_sblock_vector();
198 logfile.write_logfile( stdout );
205199 if( std::fclose( stdout ) != 0 )
206200 { show_error( "Can't close stdout", errno ); return 1; }
207201 return 0;
211205 int change_types( Domain & domain, const char * const logname,
212206 const std::string & types1, const std::string & types2 )
213207 {
214 Logbook logbook( 0, 0, domain, logname, 1, 1, true );
215 verify_logname_and_domain( logbook );
216
217 for( int i = 0; i < logbook.sblocks(); ++i )
218 {
219 const Sblock & sb = logbook.sblock( i );
220 if( !logbook.domain().includes( sb ) )
221 { if( logbook.domain() < sb ) break; else continue; }
208 Logfile logfile( logname );
209 if( !logfile.read_logfile() ) return not_readable( logname );
210 domain.crop( logfile.extent() );
211 if( domain.empty() ) return empty_domain();
212 logfile.split_by_domain_borders( domain );
213
214 for( int i = 0; i < logfile.sblocks(); ++i )
215 {
216 const Sblock & sb = logfile.sblock( i );
217 if( !domain.includes( sb ) )
218 { if( domain < sb ) break; else continue; }
222219 const unsigned j = types1.find( sb.status() );
223220 if( j < types1.size() )
224 logbook.change_sblock_status( i, Sblock::Status( types2[j] ) );
225 }
226 logbook.compact_sblock_vector();
227 logbook.write_logfile( stdout );
221 logfile.change_sblock_status( i, Sblock::Status( types2[j] ) );
222 }
223 logfile.compact_sblock_vector();
224 logfile.write_logfile( stdout );
228225 if( std::fclose( stdout ) != 0 )
229226 { show_error( "Can't close stdout", errno ); return 1; }
230227 return 0;
231228 }
232229
233230
231 int set_for_compare( Domain & domain, Logfile & logfile,
232 const bool as_domain, const bool loose )
233 {
234 if( !logfile.read_logfile( ( as_domain && loose ) ? '?' : 0 ) )
235 return not_readable( logfile.filename() );
236 logfile.compact_sblock_vector();
237 domain.crop( logfile.extent() );
238 if( domain.empty() ) return empty_domain();
239 logfile.split_by_domain_borders( domain );
240 return -1;
241 }
242
234243 int compare_logfiles( Domain & domain, const char * const logname,
235 const char * const second_logname )
244 const char * const second_logname,
245 const bool as_domain, const bool loose )
236246 {
237247 Domain domain2( domain );
238 const Logbook logbook( 0, 0, domain, logname, 1, 1, true );
239 verify_logname_and_domain( logbook );
240 const Logbook logbook2( 0, 0, domain2, second_logname, 1, 1, true );
241 verify_logname_and_domain( logbook2 );
242
243 int retval = 0;
244 if( logbook.domain() != logbook2.domain() ) retval = 1;
245 else for( int i = 0; i < logbook.sblocks(); ++i )
246 {
247 const Sblock & sb = logbook.sblock( i );
248 if( !logbook.domain().includes( sb ) )
249 { if( logbook.domain() < sb ) break; else continue; }
250 const int j = logbook2.find_index( sb.pos() );
251 if( j < 0 || logbook2.sblock( j ) != sb ) { retval = 1; break; }
248 Logfile logfile( logname );
249 int retval = set_for_compare( domain, logfile, as_domain, loose );
250 if( retval >= 0 ) return retval;
251
252 Logfile logfile2( second_logname );
253 retval = set_for_compare( domain2, logfile2, as_domain, loose );
254 if( retval >= 0 ) return retval;
255
256 retval = 0;
257 if( !as_domain && domain != domain2 ) retval = 1;
258 else
259 {
260 int i = 0, j = 0;
261 while( true )
262 {
263 while( i < logfile.sblocks() &&
264 ( !domain.includes( logfile.sblock( i ) ) ||
265 ( as_domain && logfile.sblock( i ).status() != Sblock::finished ) ) )
266 ++i;
267 while( j < logfile2.sblocks() &&
268 ( !domain2.includes( logfile2.sblock( j ) ) ||
269 ( as_domain && logfile2.sblock( j ).status() != Sblock::finished ) ) )
270 ++j;
271 if( ( i < logfile.sblocks() ) != ( j < logfile2.sblocks() ) )
272 { retval = 1; break; } // one file has more blocks
273 if( i >= logfile.sblocks() ) break; // successful compare
274 if( logfile.sblock( i++ ) != logfile2.sblock( j++ ) )
275 { retval = 1; break; }
276 }
252277 }
253278 if( retval )
254279 {
255280 char buf[80];
256281 snprintf( buf, sizeof buf, "Logfiles '%s' and '%s' differ.",
257 logbook.filename(), logbook2.filename() );
282 logfile.filename(), logfile2.filename() );
258283 show_error( buf );
259284 }
260285 return retval;
286 }
287
288
289 int complete_logfile( const char * const logname,
290 const Sblock::Status complete_type )
291 {
292 Logfile logfile( logname );
293 if( !logfile.read_logfile( complete_type ) ) return not_readable( logname );
294 logfile.compact_sblock_vector();
295 logfile.write_logfile( stdout );
296 if( std::fclose( stdout ) != 0 )
297 { show_error( "Can't close stdout", errno ); return 1; }
298 return 0;
261299 }
262300
263301
266304 const Sblock::Status type2, const bool force )
267305 {
268306 char buf[80];
269 Logbook logbook( 0, 0, domain, logname, 1, hardbs, false, force );
270 if( logbook.logfile_exists() )
307 Logfile logfile( logname );
308 if( !force && logfile.read_logfile() )
271309 {
272310 snprintf( buf, sizeof buf,
273311 "Logfile '%s' exists. Use '--force' to overwrite it.", logname );
274312 show_error( buf );
275313 return 1;
276314 }
277 if( logbook.domain().size() == 0 )
278 { show_error( "Empty domain." ); return 0; }
279
280 for( int i = 0; i < logbook.sblocks(); ++i ) // mark all logfile as type2
281 logbook.change_sblock_status( i, type2 );
315 if( domain.empty() ) return empty_domain();
316 logfile.make_blank();
317 logfile.split_by_domain_borders( domain );
318
319 for( int i = 0; i < logfile.sblocks(); ++i ) // mark all logfile as type2
320 logfile.change_sblock_status( i, type2 );
282321
283322 // mark every block read from stdin and in domain as type1
284323 for( int linenum = 1; ; ++linenum )
286325 long long block;
287326 const int n = std::scanf( "%lli\n", &block );
288327 if( n < 0 ) break; // EOF
289 if( n != 1 || block > LLONG_MAX / hardbs )
290 {
291 char buf[80];
328 if( n != 1 || block < 0 || block > LLONG_MAX / hardbs )
329 {
292330 snprintf( buf, sizeof buf,
293331 "error reading block number from stdin, line %d", linenum );
294332 show_error( buf );
295333 return 2;
296334 }
297335 const Block b( block * hardbs, hardbs );
298 if( logbook.domain().includes( b ) )
299 logbook.change_chunk_status( b, type1 );
300 }
301 logbook.truncate_vector( logbook.domain().end(), true );
302 if( !logbook.update_logfile( -1, true, false ) ) return 1;
336 if( domain.includes( b ) )
337 logfile.change_chunk_status( b, type1, domain );
338 }
339 logfile.truncate_vector( domain.end(), true );
340 if( !logfile.write_logfile() ) return 1;
303341 return 0;
304342 }
305343
307345 int test_if_done( Domain & domain, const char * const logname, const bool del )
308346 {
309347 char buf[80];
310 const Logbook logbook( 0, 0, domain, logname, 1, 1, true );
311 verify_logname_and_domain( logbook );
312
313 for( int i = 0; i < logbook.sblocks(); ++i )
314 {
315 const Sblock & sb = logbook.sblock( i );
316 if( !logbook.domain().includes( sb ) )
317 { if( logbook.domain() < sb ) break; else continue; }
348 Logfile logfile( logname );
349 if( !logfile.read_logfile() ) return not_readable( logname );
350 domain.crop( logfile.extent() );
351 if( domain.empty() ) return empty_domain();
352 logfile.split_by_domain_borders( domain );
353
354 for( int i = 0; i < logfile.sblocks(); ++i )
355 {
356 const Sblock & sb = logfile.sblock( i );
357 if( !domain.includes( sb ) )
358 { if( domain < sb ) break; else continue; }
318359 if( sb.status() != Sblock::finished )
319360 {
320361 if( verbosity >= 1 )
346387 const std::string & blocktypes )
347388 {
348389 long long last_block = -1;
349 const Logbook logbook( offset, 0, domain, logname, 1, hardbs, true );
350 verify_logname_and_domain( logbook );
351
352 for( int i = 0; i < logbook.sblocks(); ++i )
353 {
354 const Sblock & sb = logbook.sblock( i );
355 if( !logbook.domain().includes( sb ) )
356 { if( logbook.domain() < sb ) break; else continue; }
390 Logfile logfile( logname );
391 if( !logfile.read_logfile() ) return not_readable( logname );
392 domain.crop( logfile.extent() );
393 if( domain.empty() ) return empty_domain();
394 logfile.split_by_domain_borders( domain );
395
396 for( int i = 0; i < logfile.sblocks(); ++i )
397 {
398 const Sblock & sb = logfile.sblock( i );
399 if( !domain.includes( sb ) )
400 { if( domain < sb ) break; else continue; }
357401 if( blocktypes.find( sb.status() ) >= blocktypes.size() ) continue;
358 for( long long block = ( sb.pos() + logbook.offset() ) / hardbs;
359 block * hardbs < sb.end() + logbook.offset(); ++block )
402 for( long long block = ( sb.pos() + offset ) / hardbs;
403 block * hardbs < sb.end() + offset; ++block )
360404 {
361405 if( block > last_block )
362406 {
363407 last_block = block;
364408 std::printf( "%lld\n", block );
365409 }
366 else if( block < last_block ) internal_error( "block out of order" );
410 else if( block < last_block ) internal_error( "block out of order." );
367411 }
368412 }
369413 return 0;
422466 int errors = 0;
423467 Sblock::Status old_status = Sblock::non_tried;
424468 bool first_block = true, good = true;
425 const Logbook logbook( 0, 0, domain, logname, 1, 1, true );
426 verify_logname_and_domain( logbook );
427
428 for( int i = 0; i < logbook.sblocks(); ++i )
429 {
430 const Sblock & sb = logbook.sblock( i );
431 if( !logbook.domain().includes( sb ) )
432 {
433 if( logbook.domain() < sb ) break;
469 Logfile logfile( logname );
470 if( !logfile.read_logfile() ) return not_readable( logname );
471 const Block extent = logfile.extent();
472 domain.crop( extent );
473 if( domain.empty() ) return empty_domain();
474 const int true_sblocks = logfile.sblocks();
475 logfile.split_by_domain_borders( domain );
476
477 for( int i = 0; i < logfile.sblocks(); ++i )
478 {
479 const Sblock & sb = logfile.sblock( i );
480 if( !domain.includes( sb ) )
481 {
482 if( domain < sb ) break;
434483 else { first_block = true; good = true; continue; }
435484 }
436485 const bool sc = ( first_block || sb.status() != old_status );
454503 old_status = sb.status();
455504 }
456505
457 const long long domain_size = logbook.domain().in_size();
506 const long long domain_size = domain.in_size();
458507 const long long errsize = size_non_trimmed + size_non_split + size_bad_sector;
459 std::printf( "\ncurrent pos: %10sB, current status: %s\n",
460 format_num( logbook.current_pos() ),
461 logbook.status_name( logbook.current_status() ) );
462 std::printf( "domain size: %10sB, in %4d area(s)\n",
463 format_num( domain_size ),
464 logbook.domain().blocks() );
465 std::printf( " rescued: %10sB, in %4d area(s) (%s)\n",
508 std::printf( "\n current pos: %10sB, current status: %s\n",
509 format_num( logfile.current_pos() ),
510 logfile.status_name( logfile.current_status() ) );
511 std::printf( "logfile extent: %10sB, in %5d area(s)\n",
512 format_num( extent.size() ), true_sblocks );
513 if( domain.pos() > 0 || domain.end() < extent.end() )
514 {
515 std::printf( " domain begin: %10sB, domain end: %10sB\n",
516 format_num( domain.pos() ), format_num( domain.end() ) );
517 std::printf( " domain size: %10sB, in %5d area(s)\n",
518 format_num( domain_size ), domain.blocks() );
519 }
520 std::printf( " rescued: %10sB, in %5d area(s) (%s)\n",
466521 format_num( size_finished ), areas_finished,
467522 format_percentage( size_finished, domain_size ) );
468 std::printf( " non-tried: %10sB, in %4d area(s) (%s)\n",
523 std::printf( " non-tried: %10sB, in %5d area(s) (%s)\n",
469524 format_num( size_non_tried ), areas_non_tried,
470525 format_percentage( size_non_tried, domain_size ) );
471 std::printf( "\n errsize: %10sB, errors: %7u (%s)\n",
526 std::printf( "\n errsize: %10sB, errors: %8u (%s)\n",
472527 format_num( errsize ), errors,
473528 format_percentage( errsize, domain_size ) );
474 std::printf( "non-trimmed: %10sB, in %4d area(s) (%s)\n",
529 std::printf( " non-trimmed: %10sB, in %5d area(s) (%s)\n",
475530 format_num( size_non_trimmed ), areas_non_trimmed,
476531 format_percentage( size_non_trimmed, domain_size ) );
477 std::printf( " non-split: %10sB, in %4d area(s) (%s)\n",
532 std::printf( " non-split: %10sB, in %5d area(s) (%s)\n",
478533 format_num( size_non_split ), areas_non_split,
479534 format_percentage( size_non_split, domain_size ) );
480 std::printf( " bad-sector: %10sB, in %4d area(s) (%s)\n",
535 std::printf( " bad-sector: %10sB, in %5d area(s) (%s)\n",
481536 format_num( size_bad_sector ), areas_bad_sector,
482537 format_percentage( size_bad_sector, domain_size ) );
483538 return 0;
499554 const int default_hardbs = 512;
500555 int hardbs = default_hardbs;
501556 Mode program_mode = m_none;
557 bool as_domain = false;
502558 bool force = false;
559 bool loose = false;
503560 std::string types1, types2;
504561 Sblock::Status type1 = Sblock::finished, type2 = Sblock::bad_sector;
562 Sblock::Status complete_type = Sblock::non_tried;
505563 invocation_name = argv[0];
506564 command_line = argv[0];
507565 for( int i = 1; i < argc; ++i )
508566 { command_line += ' '; command_line += argv[i]; }
567 initial_time_ = std::time( 0 );
509568
510569 const Arg_parser::Option options[] =
511570 {
512 { 'a', "change-types", Arg_parser::yes },
513 { 'b', "block-size", Arg_parser::yes },
514 { 'b', "sector-size", Arg_parser::yes },
515 { 'c', "create-logfile", Arg_parser::maybe },
516 { 'd', "delete-if-done", Arg_parser::no },
517 { 'D', "done-status", Arg_parser::no },
518 { 'f', "force", Arg_parser::no },
519 { 'h', "help", Arg_parser::no },
520 { 'i', "input-position", Arg_parser::yes },
521 { 'l', "list-blocks", Arg_parser::yes },
522 { 'm', "domain-logfile", Arg_parser::yes },
523 { 'n', "invert-logfile", Arg_parser::no },
524 { 'o', "output-position", Arg_parser::yes },
525 { 'p', "compare-logfile", Arg_parser::yes },
526 { 'q', "quiet", Arg_parser::no },
527 { 's', "size", Arg_parser::yes },
528 { 's', "max-size", Arg_parser::yes },
529 { 't', "show-status", Arg_parser::no },
530 { 'v', "verbose", Arg_parser::no },
531 { 'V', "version", Arg_parser::no },
532 { 'x', "xor-logfile", Arg_parser::yes },
533 { 'y', "and-logfile", Arg_parser::yes },
534 { 'z', "or-logfile", Arg_parser::yes },
535 { 0 , 0, Arg_parser::no } };
571 { 'a', "change-types", Arg_parser::yes },
572 { 'b', "block-size", Arg_parser::yes },
573 { 'b', "sector-size", Arg_parser::yes },
574 { 'B', "binary-prefixes", Arg_parser::no },
575 { 'c', "create-logfile", Arg_parser::maybe },
576 { 'C', "complete-logfile", Arg_parser::maybe },
577 { 'd', "delete-if-done", Arg_parser::no },
578 { 'D', "done-status", Arg_parser::no },
579 { 'f', "force", Arg_parser::no },
580 { 'h', "help", Arg_parser::no },
581 { 'i', "input-position", Arg_parser::yes },
582 { 'l', "list-blocks", Arg_parser::yes },
583 { 'L', "loose-domain", Arg_parser::no },
584 { 'm', "domain-logfile", Arg_parser::yes },
585 { 'n', "invert-logfile", Arg_parser::no },
586 { 'o', "output-position", Arg_parser::yes },
587 { 'p', "compare-logfile", Arg_parser::yes },
588 { 'P', "compare-as-domain", Arg_parser::yes },
589 { 'q', "quiet", Arg_parser::no },
590 { 's', "size", Arg_parser::yes },
591 { 's', "max-size", Arg_parser::yes },
592 { 't', "show-status", Arg_parser::no },
593 { 'v', "verbose", Arg_parser::no },
594 { 'V', "version", Arg_parser::no },
595 { 'x', "xor-logfile", Arg_parser::yes },
596 { 'y', "and-logfile", Arg_parser::yes },
597 { 'z', "or-logfile", Arg_parser::yes },
598 { 0 , 0, Arg_parser::no } };
536599
537600 const Arg_parser parser( argc, argv, options );
538601 if( parser.error().size() ) // bad option
547610 switch( code )
548611 {
549612 case 'a': set_mode( program_mode, m_change );
550 set_types( arg, types1, types2 ); break;
613 parse_types( arg, types1, types2 ); break;
551614 case 'b': hardbs = getnum( arg, 0, 1, INT_MAX ); break;
615 case 'B': format_num( 0, 0, -1 ); break; // set binary prefixes
552616 case 'c': set_mode( program_mode, m_create );
553 set_types( arg, type1, type2 ); break;
617 parse_2types( arg, type1, type2 ); break;
618 case 'C': set_mode( program_mode, m_complete );
619 parse_type( arg, complete_type ); break;
554620 case 'd': set_mode( program_mode, m_delete ); break;
555621 case 'D': set_mode( program_mode, m_done_st ); break;
556622 case 'f': force = true; break;
558624 case 'i': ipos = getnum( arg, hardbs, 0 ); break;
559625 case 'l': set_mode( program_mode, m_list ); types1 = arg;
560626 check_types( types1, "list-blocks" ); break;
561 case 'm': set_name( &domain_logfile_name, arg ); break;
627 case 'L': loose = true; break;
628 case 'm': set_name( &domain_logfile_name, arg, code ); break;
562629 case 'n': set_mode( program_mode, m_invert ); break;
563630 case 'o': opos = getnum( arg, hardbs, 0 ); break;
564 case 'p': set_mode( program_mode, m_compare );
565 second_logname = arg; break;
631 case 'p':
632 case 'P': set_mode( program_mode, m_compare );
633 second_logname = arg; as_domain = ( code == 'P' ); break;
566634 case 'q': verbosity = -1; break;
567635 case 's': max_size = getnum( arg, hardbs, -1 ); break;
568636 case 't': set_mode( program_mode, m_status ); break;
574642 second_logname = arg; break;
575643 case 'z': set_mode( program_mode, m_or );
576644 second_logname = arg; break;
577 default : internal_error( "uncaught option" );
645 default : internal_error( "uncaught option." );
578646 }
579647 } // end process options
580648
599667
600668 // end scan arguments
601669
602 Domain domain( ipos, max_size, domain_logfile_name );
670 Domain domain( ipos, max_size, domain_logfile_name, loose );
603671
604672 switch( program_mode )
605673 {
606 case m_none: internal_error( "invalid operation" ); break;
674 case m_none: internal_error( "invalid operation." ); break;
607675 case m_and:
608676 case m_or:
609677 case m_xor:
610678 return do_logic_ops( domain, logname, second_logname, program_mode );
611679 case m_change: return change_types( domain, logname, types1, types2 );
612 case m_compare: return compare_logfiles( domain, logname, second_logname );
680 case m_compare:
681 return compare_logfiles( domain, logname, second_logname, as_domain, loose );
682 case m_complete: return complete_logfile( logname, complete_type );
613683 case m_create: return create_logfile( domain, logname, hardbs,
614684 type1, type2, force );
615685 case m_delete: return test_if_done( domain, logname, true );
00 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
1 .TH DDRESCUE "1" "July 2013" "ddrescue 1.17" "User Commands"
1 .TH DDRESCUE "1" "June 2014" "ddrescue 1.18.1" "User Commands"
22 .SH NAME
33 ddrescue \- data recovery tool
44 .SH SYNOPSIS
77 .SH DESCRIPTION
88 GNU ddrescue \- Data recovery tool.
99 Copies data from one file or block device to another,
10 trying hard to rescue data in case of read errors.
10 trying to rescue the good parts first in case of read errors.
1111 .PP
1212 You should use a logfile unless you know what you are doing.
1313 If you reboot, check the device names before restarting ddrescue.
14 Do not use options '\-F' or '\-g' without reading the manual first.
14 Do not use options '\-F' or '\-G' without reading the manual first.
1515 .SH OPTIONS
1616 .TP
1717 \fB\-h\fR, \fB\-\-help\fR
5656 \fB\-F\fR, \fB\-\-fill\-mode=\fR<types>
5757 fill given type blocks with infile data (?*/\-+)
5858 .TP
59 \fB\-g\fR, \fB\-\-generate\-mode\fR
59 \fB\-G\fR, \fB\-\-generate\-mode\fR
6060 generate approximate logfile from partial copy
61 .TP
62 \fB\-H\fR, \fB\-\-test\-mode=\fR<file>
63 set map of good/bad blocks from given logile
6164 .TP
6265 \fB\-i\fR, \fB\-\-input\-position=\fR<bytes>
6366 starting position in input file [0]
6568 \fB\-I\fR, \fB\-\-verify\-input\-size\fR
6669 verify input file size with size in logfile
6770 .TP
68 \fB\-K\fR, \fB\-\-skip\-size=\fR<bytes>
71 \fB\-K\fR, \fB\-\-skip\-size=\fR<min>[,<max>]
6972 initial size to skip on read error [64 KiB]
7073 .TP
7174 \fB\-l\fR, \fB\-\-logfile\-size=\fR<entries>
72 do not grow logfile beyond this size [1000]
75 do not grow logfile beyond this size [10000]
76 .TP
77 \fB\-L\fR, \fB\-\-loose\-domain\fR
78 accept an incomplete domain logfile
7379 .TP
7480 \fB\-m\fR, \fB\-\-domain\-logfile=\fR<file>
7581 restrict domain to finished blocks in file
7884 mark all failed blocks as non\-trimmed
7985 .TP
8086 \fB\-n\fR, \fB\-\-no\-split\fR
81 do not try to split or retry failed blocks
87 skip the splitting phase
88 .TP
89 \fB\-N\fR, \fB\-\-no\-trim\fR
90 skip the trimming phase
8291 .TP
8392 \fB\-o\fR, \fB\-\-output\-position=\fR<bytes>
8493 starting position in output file [ipos]
94 .TP
95 \fB\-O\fR, \fB\-\-reopen\-on\-error\fR
96 reopen input file after every read error
8597 .TP
8698 \fB\-p\fR, \fB\-\-preallocate\fR
8799 preallocate space on disc for output file
89101 \fB\-q\fR, \fB\-\-quiet\fR
90102 suppress all messages
91103 .TP
92 \fB\-r\fR, \fB\-\-retries=\fR<n>
93 exit after given retries (\fB\-1\fR=\fIinfinity\fR) [0]
104 \fB\-r\fR, \fB\-\-retry\-passes=\fR<n>
105 exit after <n> retry passes (\fB\-1\fR=\fIinfinity\fR) [0]
94106 .TP
95107 \fB\-R\fR, \fB\-\-reverse\fR
96 reverse direction of copy operations
108 reverse direction of some copy operations
97109 .TP
98110 \fB\-s\fR, \fB\-\-size=\fR<bytes>
99111 maximum size of input data to be copied
115127 .TP
116128 \fB\-x\fR, \fB\-\-extend\-outfile=\fR<bytes>
117129 extend outfile size to be at least this long
130 .TP
131 \fB\-1\fR, \fB\-\-log\-rates=\fR<file>
132 log rates and error sizes in file
133 .TP
134 \fB\-2\fR, \fB\-\-log\-reads=\fR<file>
135 log all read operations in file
118136 .PP
119 Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,
120 Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
137 Numbers may be in decimal, hexadecimal or octal, and may be followed by a
138 multiplier: s = sectors, k = 1000, Ki = 1024, M = 10^6, Mi = 2^20, etc...
121139 Time intervals have the format 1[.5][smhd] or 1/2[smhd].
122140 .PP
123141 Exit status: 0 for a normal exit, 1 for environmental problems (file
131149 .br
132150 General help using GNU software: http://www.gnu.org/gethelp
133151 .SH COPYRIGHT
134 Copyright \(co 2013 Antonio Diaz Diaz.
152 Copyright \(co 2014 Antonio Diaz Diaz.
135153 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
136154 .br
137155 This is free software: you are free to change and redistribute it.
Binary diff not shown
0 \input texinfo @c -*-texinfo-*-
1 @c %**start of header
2 @setfilename ddrescue.info
3 @documentencoding ISO-8859-15
4 @settitle GNU ddrescue Manual
5 @finalout
6 @c %**end of header
7
8 @set UPDATED 7 June 2014
9 @set VERSION 1.18
10
11 @dircategory GNU Packages
12 @direntry
13 * Ddrescue: (ddrescue). Data recovery tool
14 @end direntry
15
16
17 @ifnothtml
18 @titlepage
19 @title GNU ddrescue
20 @subtitle Data recovery tool
21 @subtitle for Ddrescue version @value{VERSION}, @value{UPDATED}
22 @author by Antonio Diaz Diaz
23
24 @page
25 @vskip 0pt plus 1filll
26 @end titlepage
27
28 @contents
29 @end ifnothtml
30
31 @node Top
32 @top
33
34 This manual is for GNU ddrescue (version @value{VERSION}, @value{UPDATED}).
35
36 @menu
37 * Introduction:: Purpose and features of GNU ddrescue
38 * Basic concepts:: Blocks, clusters, devices, files, sectors, etc
39 * Important advice:: Read this or risk losing your data
40 * Algorithm:: How ddrescue recovers the data
41 * Invoking ddrescue:: Command line interface
42 * Logfile structure:: Detailed format of the logfile
43 * Examples:: A small tutorial with examples
44 * Direct disc access:: Bypassing the kernel cache
45 * Fill mode:: Selectively overwriting the output file
46 * Generate mode:: Generating an approximate logfile
47 * Ddrescuelog:: Tool for ddrescue logfiles
48 * Invoking ddrescuelog:: Command line interface
49 * Problems:: Reporting bugs
50 * Concept index:: Index of concepts
51 @end menu
52
53 @sp 1
54 Copyright @copyright{} 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
55 2012, 2013, 2014 Antonio Diaz Diaz.
56
57 This manual is free documentation: you have unlimited permission
58 to copy, distribute and modify it.
59
60
61 @node Introduction
62 @chapter Introduction
63 @cindex introduction
64
65 GNU ddrescue is a data recovery tool. It copies data from one file or
66 block device (hard disc, cdrom, etc) to another, trying to rescue the
67 good parts first in case of read errors.
68
69 The basic operation of ddrescue is fully automatic. That is, you don't
70 have to wait for an error, stop the program, read the log, restart it
71 from a new position, etc.
72
73 If you use the logfile feature of ddrescue, the data is rescued very
74 efficiently, (only the needed blocks are read). Also you can interrupt
75 the rescue at any time and resume it later at the same point.
76
77 Ddrescue does not write zeros to the output when it finds bad sectors in
78 the input, and does not truncate the output file if not asked to. So,
79 every time you run it on the same output file, it tries to fill in the
80 gaps without wiping out the data already rescued.
81
82 Automatic merging of backups: If you have two or more damaged copies of
83 a file, cdrom, etc, and run ddrescue on all of them, one at a time, with
84 the same output file, you will probably obtain a complete and error-free
85 file. This is so because the probability of having the same area damaged
86 in all copies is low. Using the logfile, only the needed blocks are read
87 from the second and successive copies.
88
89 Ddrescue recommends lzip for compression of backups because the lzip
90 format is designed for long-term data archiving and provides data
91 recovery capabilities which nicely complement those of ddrescue.
92 (Ddrescue fills unreadable sectors with data from other copies, while
93 lziprecover corrects corrupt sectors with data from other copies). If
94 the cause of file corruption is damaged media, the combination ddrescue
95 + lziprecover is the best option for recovering data from multiple
96 damaged copies. @xref{lziprecover-example}, for an example.
97
98 Recordable CD and DVD media keep their data only for a finite time
99 (typically for many years). After that time, data loss develops slowly
100 with read errors growing from the outer media region towards the inside.
101 Just make two (or more) copies of every important CD/DVD you burn so
102 that you can later recover them with ddrescue.
103
104 Because ddrescue needs to read and write at random places, it only works
105 on seekable (random access) input and output files.
106
107 If your system supports it, ddrescue can use direct disc access to read
108 the input file, bypassing the kernel cache.
109
110 Ddrescue also features a "fill mode" able to selectively overwrite parts
111 of the output file, which has a number of interesting uses like wiping
112 data, marking bad areas or even, in some cases, "repair" damaged
113 sectors.
114
115 One of the great strengths of ddrescue is that it is interface-agnostic,
116 and so can be used for any kind of device supported by your kernel (ATA,
117 SATA, SCSI, old MFM drives, floppy discs, or even flash media cards like
118 SD).
119
120
121 @node Basic concepts
122 @chapter Basic concepts
123 @cindex basic concepts
124
125 @table @asis
126 @item Block
127 Any amount of data. A block is described by its starting position and
128 its size. The starting position (or beginning position) is the lowest
129 position in the block. The end of the block is its starting position
130 plus its size.
131
132 @item Cluster
133 Group of consecutive sectors read or written in one go.
134
135 @item Device
136 Piece of hardware containing data. Hard disc drives, cdrom drives, USB
137 pendrives, are devices. /dev/hda, /dev/sdb, are device names.
138
139 @item File
140 Files are named units of data which are stored by the operating system
141 for you to retrieve later by name. Devices and partitions are accessed
142 by means of their associated file names.
143
144 @item Partition
145 Every part in which a device is divided. A partition normally contains a
146 file system. /dev/hda1, /dev/sdb3, are partition names.
147
148 @item Recoverable formats
149 As ddrescue uses standard library functions to read data from the device
150 being rescued, only mountable device formats can be rescued with
151 ddrescue. DVDs can be mounted and they can be rescued, "compact disc
152 digital audio" CDs can't, "video CDs"[1] maybe.@*
153 [1] http://en.wikipedia.org/wiki/Video_CD
154
155 @item Rescue domain
156 Block or set of blocks to be acted upon (rescued, listed, etc). You can
157 define it with the options @samp{--input-position}, @samp{--size} and
158 @samp{--domain-logfile}. The rescue domain defaults to the whole input
159 file or logfile.
160
161 The amount of data rescued, number of errors, etc, shown by ddrescue may
162 vary or even become zero if you limit the rescue domain. Don't worry,
163 they have not disappeared; they are simply out of the specified rescue
164 domain.
165
166 @item Sector
167 Hardware block. Smallest accessible amount of data on a device.
168
169 @end table
170
171
172 @node Important advice
173 @chapter Using ddrescue safely
174 @cindex using ddrescue safely
175
176 Ddrescue is like any other power tool. You need to understand what it
177 does, and you need to understand some things about the machines it does
178 those things to, in order to use it safely.
179
180 Always use a logfile unless you know you won't need it. Without a
181 logfile, ddrescue can't resume a rescue, only reinitiate it.
182
183 Never try to rescue a r/w mounted partition. The resulting copy may be
184 useless.
185
186 Never try to repair a file system on a drive with I/O errors; you will
187 probably lose even more data.
188
189 If you use a device or a partition as destination, any data stored there
190 will be overwritten.
191
192 Some systems may change device names on reboot (eg. udev enabled
193 systems). If you reboot, check the device names before restarting
194 ddrescue.
195
196 If you interrupt the rescue and then reboot, any partially copied
197 partitions should be hidden before allowing them to be touched by any
198 operating system that tries to mount and "fix" the partitions it sees.
199
200
201 @node Algorithm
202 @chapter Algorithm
203 @cindex algorithm
204
205 GNU ddrescue is not a derivative of dd, nor is related to dd in any way
206 except in that both can be used for copying data from one device to
207 another. The key difference is that ddrescue uses a sophisticated
208 algorithm to copy data from failing drives causing them as little
209 additional damage as possible.
210
211 Ddrescue manages efficiently the status of the rescue in progress and
212 tries to rescue the good parts first, scheduling reads inside bad (or
213 slow) areas for later. This maximizes the amount of data that can be
214 finally recovered from a failing drive.
215
216 The standard dd utility can be used to save data from a failing drive,
217 but it reads the data sequentially, which may wear out the drive without
218 rescuing anything if the errors are at the beginning of the drive.
219
220 Other programs read the data sequentially but switch to small size reads
221 when they find errors. This is a bad idea because it means spending more
222 time at error areas, damaging the surface, the heads and the drive
223 mechanics, instead of getting out of them as fast as possible. This
224 behavior reduces the chances of rescuing the remaining good data.
225
226 The algorithm of ddrescue is as follows (the user may interrupt the
227 process at any point, but be aware that a bad drive can block ddrescue
228 for a long time until the kernel gives up):
229
230 1) Optionally read a logfile describing the status of a multi-part or
231 previously interrupted rescue. If no logfile is specified or is empty or
232 does not exist, mark all the rescue domain as non-tried.
233
234 2) (First phase; Copying) Read the non-tried parts of the input file,
235 marking the failed blocks as non-trimmed and skipping beyond them. Skip
236 also beyond slow areas. The skipped areas are tried later in two
237 additional passes (before trimming), reversing the direction after each
238 pass until all the rescue domain is tried. The third pass is a sweeping
239 pass, with skipping disabled. (The purpose is to delimit large errors
240 fast, keep the logfile small, and produce good starting points for
241 trimming). Only non-tried areas are read in large blocks. Trimming,
242 splitting and retrying are done sector by sector. Each sector is tried
243 at most two times; the first in this step (usually as part of a large
244 block read, but sometimes as a single sector read), the second in one of
245 the steps below as a single sector read.
246
247 3) (Second phase; Trimming) Read forwards one sector at a time from the
248 leading edge of the smallest non-trimmed block, until a bad sector is
249 found. Then read backwards one sector at a time from the trailing edge
250 of the same block, until a bad sector is found. For each non-trimmed
251 block, mark the bad sectors found as bad-sector and mark the rest of
252 that block as non-split without trying to read it. Repeat until there
253 are no more non-trimmed blocks. (Large non-trimmed blocks are produced
254 by concatenation of smaller ones, and its fraction of good data at the
255 edges is therefore smaller).
256
257 4) (Third phase; Splitting) Read forwards one sector at a time from the
258 center of the largest non-split block, until a bad sector is found.
259 Then, if the bad sector found is not the first one tried, read backwards
260 one sector at a time from the center of the same block, until a bad
261 sector is found. If the logfile is larger than @samp{--logfile-size},
262 read sequentially the largest non-split blocks until the number of
263 entries in the logfile drops below @samp{--logfile-size}. Repeat until
264 all remaining non-split blocks have less than 7 sectors. Then read the
265 remaining non-split blocks sequentially.
266
267 5) (Fourth phase; Retrying) Optionally try to read again the bad sectors
268 until the specified number of retry passes is reached. Every bad sector
269 is tried only once in each pass. Ddrescue can't know if a bad sector is
270 unrecoverable or if it will be eventually read after some retries.
271
272 6) Optionally write a logfile for later use.
273
274 @sp 1
275 The total error size (@samp{errsize}) is sum of the sizes of all the
276 non-trimmed, non-split and bad-sector blocks. It increases during the
277 copying phase and may decrease during trimming, splitting and retrying.
278 Note that as ddrescue splits the failed blocks, making them smaller, the
279 total error size may decrease while the number of errors increases.
280
281 The logfile is periodically saved to disc, as well as when ddrescue
282 finishes or is interrupted. So in case of a crash you can resume the
283 rescue with little recopying. The interval between saves varies from 30
284 seconds to 5 minutes depending on logfile size (larger logfiles are
285 saved at longer intervals).
286
287 Also, the same logfile can be used for multiple commands that copy
288 different areas of the input file, and for multiple recovery attempts
289 over different subsets. See this example:
290
291 @noindent
292 Rescue the most important part of the disc first.
293 @example
294 ddrescue -i0 -s50MiB /dev/hdc hdimage logfile
295 ddrescue -i0 -s1MiB -d -r3 /dev/hdc hdimage logfile
296 @end example
297
298 @noindent
299 Then rescue some key disc areas.
300 @example
301 ddrescue -i30GiB -s10GiB /dev/hdc hdimage logfile
302 ddrescue -i230GiB -s5GiB /dev/hdc hdimage logfile
303 @end example
304
305 @noindent
306 Now rescue the rest (does not recopy what is already done).
307 @example
308 ddrescue /dev/hdc hdimage logfile
309 ddrescue -d -r3 /dev/hdc hdimage logfile
310 @end example
311
312
313 @node Invoking ddrescue
314 @chapter Invoking ddrescue
315 @cindex invoking ddrescue
316 @cindex options
317 @cindex usage
318 @cindex version
319
320 The format for running ddrescue is:
321
322 @example
323 ddrescue [@var{options}] @var{infile} @var{outfile} [@var{logfile}]
324 @end example
325
326 ddrescue supports the following options:
327
328 @table @samp
329 @item -h
330 @itemx --help
331 Print an informative help message describing the options and exit.
332
333 @item -V
334 @itemx --version
335 Print the version number of ddrescue on the standard output and exit.
336
337 @item -a @var{bytes}
338 @itemx --min-read-rate=@var{bytes}
339 Minimum read rate of good non-tried areas, in bytes per second. If the
340 read rate falls below this value, ddrescue will skip ahead a variable
341 amount depending on rate and error histories. The skipped blocks are
342 tried in additional passes (before trimming) where the minimum read rate
343 is divided by ten before each pass, until there are no more non-tried
344 blocks left.
345
346 If @var{bytes} is 0 (auto), the minimum read rate is recalculated for
347 each block as @w{(average_rate / 10)}. Values above device capabilities
348 are ignored.
349
350 @item -A
351 @itemx --try-again
352 Mark all non-split and non-trimmed blocks inside the rescue domain as
353 non-tried before beginning the rescue. Try this if the drive stops
354 responding and ddrescue immediately starts splitting failed blocks when
355 restarted. If @samp{--retrim} is also specified, mark all failed blocks
356 inside the rescue domain as non-tried.
357
358 @item -b @var{bytes}
359 @itemx --sector-size=@var{bytes}
360 Sector (hardware block) size of input device in bytes (usually 512 for
361 hard discs and 3.5" floppies, 1024 for 5.25" floppies, and 2048 for
362 cdroms). Defaults to 512.
363
364 @item -B
365 @itemx --binary-prefixes
366 Show units with binary prefixes (powers of 1024).@*
367 SI prefixes (powers of 1000) are used by default. (See table below).
368
369 @item -c @var{sectors}
370 @itemx --cluster-size=@var{sectors}
371 Number of sectors to copy at a time. Defaults to @w{64 KiB / sector_size}.
372 Try smaller values for slow drives. The number of sectors per track (18
373 or 9) is a good value for floppies.
374
375 @item -C
376 @itemx --complete-only
377 Limit rescue domain to the blocks listed in the @var{logfile}. Do not
378 read new data beyond @var{logfile} limits. This is useful when reading
379 from devices of undefined size (like raw devices), when the drive
380 returns an incorrect size, or when reading from a partial copy. It can
381 only be used after a first rescue attempt, possibly limited with the
382 @samp{--size} option, has produced a complete @var{logfile}.
383
384 @item -d
385 @itemx --direct
386 Use direct disc access to read from @var{infile}, bypassing the kernel
387 cache. (Open the file with the O_DIRECT flag). Use it only on devices or
388 partitions, not on regular files. Sector size must be correctly set for
389 this to work. Not all systems support this.
390
391 If your system does not support direct disc access, ddrescue will warn
392 you. If the sector size is not correctly set, all reads will result in
393 errors, and no data will be rescued.
394
395 @item -D
396 @itemx --synchronous
397 Use synchronous writes for @var{outfile}. (Issue a fsync call after
398 every write). May be useful when forcing the drive to remap its bad
399 sectors.
400
401 @item -e [+]@var{n}
402 @itemx --max-errors=[+]@var{n}
403 Maximum number of error areas allowed before giving up. Defaults to
404 infinity. If @var{n} is preceded by @samp{+} the number refers to new
405 error areas found in this run, not counting those already annotated in
406 the @var{logfile}.
407
408 @item -E @var{bytes}
409 @itemx --max-error-rate=@var{bytes}
410 Maximum rate of errors allowed before giving up, in bytes per second.
411 Defaults to infinity. The rate being measured is that of actually failed
412 reads, so the rescue may finish because of this rate being exceeded even
413 if the total error size (errsize) does not change because the areas
414 being tried are already marked as errors.
415
416 @item -f
417 @itemx --force
418 Force overwrite of @var{outfile}. Needed when @var{outfile} is not a
419 regular file, but a device or partition.
420
421 @item -F @var{types}
422 @itemx --fill-mode=@var{types}
423 Fill the blocks in @var{outfile} specified as any of @var{types} in
424 @var{logfile}, with data read from @var{infile}. @var{types} contains
425 one or more of the status characters defined in the chapter Logfile
426 structure (@pxref{Logfile structure}). See the chapter Fill mode
427 (@pxref{Fill mode}) for a complete description of the fill mode.
428
429 @item -G
430 @itemx --generate-mode
431 Generate an approximate @var{logfile} from the @var{infile} and
432 @var{outfile} of the original rescue run. Note that you must keep the
433 original offset between @samp{--input-position} and
434 @samp{--output-position} of the original rescue run. See the chapter
435 Generate mode (@pxref{Generate mode}) for a complete description of the
436 generate mode.
437
438 @item -H @var{file}
439 @itemx --test-mode=@var{file}
440 Builds a map of good/bad blocks using the logfile @var{file} and uses it
441 to simulate read errors in @var{infile}. The blocks marked as finished
442 in @var{file} will be read normally. All other block types will be
443 considered read errors without even trying to read them from
444 @var{infile}. This mode is an aid in improving the algorithm of ddrescue
445 and is also useful to verify that ddrescue produces accurate results in
446 presence of read errors.
447
448 @item -i @var{bytes}
449 @itemx --input-position=@var{bytes}
450 Starting position of the rescue domain in @var{infile}, in bytes.
451 Defaults to 0. This is not the point from which ddrescue starts copying.
452 (For example, if you pass the @samp{--reverse} option to ddrescue, it
453 starts reading from the end of the rescue domain). In fill mode it
454 refers to a position in the @var{infile} of the original rescue run. See
455 the chapter Fill mode (@pxref{Fill mode}) for details.
456
457 @item -I
458 @itemx --verify-input-size
459 Compare the size of @var{infile} with the size calculated from the list
460 of blocks contained in the @var{logfile}, and exit with status 1 if they
461 differ. This is not enabled by default because the size of some devices
462 can't be known in advance and because the size derived from the
463 @var{logfile} may be incomplete, for example after doing a partial
464 rescue.
465
466 @item -K @var{initial}[,@var{max}]
467 @itemx -K ,@var{max}
468 @itemx --skip-size=@var{initial}[,@var{max}]
469 @itemx --skip-size=,@var{max}
470 Set limits to skip size during the copying phase. @var{initial} is the
471 size to skip on the first read error or slow read, in bytes. @var{max}
472 is the maximum size to skip. The values given will be rounded to the
473 next multiple of sector size. The skip size will be doubled for each
474 read error or slow read until it reaches @var{max} or, if @var{max} is
475 omitted, 1% of the size of @var{infile} or 1 GiB (whichever is smaller),
476 and will be reset to @var{initial} when good data is found. Valid values
477 range from 64 KiB to 1 GiB. @var{initial} defaults to 64 KiB. An
478 @var{initial} value of 0 disables skipping entirely.
479
480 If ddrescue is having difficulties skipping away from a large area with
481 scattered errors, or if the device has large error areas at regular
482 intervals, you can increase the initial skip size with this option.
483 Inversely, if ddrescue is skipping too much, leaving large non-tried
484 areas behind each error (which will be read later in the usually slower
485 backwards direction), you can reduce the maximum skip size, or disable
486 skipping.
487
488 @samp{--skip-size} is independent from @samp{--cluster-size}. The size
489 to skip is calculated from the end of the block that just failed.
490
491 @item -l @var{entries}
492 @itemx --logfile-size=@var{entries}
493 During the splitting phase, do not grow logfile beyond this number of
494 entries. Logfile may be larger if it was larger at startup or if it
495 became larger during the copying or trimming phases. Defaults to 10000.
496 (Each entry is about 26-30 bytes in size).
497
498 @item -L
499 @itemx --loose-domain
500 Accept an incomplete synthetic (user fabricated) domain logfile or
501 test-mode logfile and fill the gaps with non-tried blocks. The blocks in
502 the logfile must be strictly ascending and non-overlapping, but they do
503 not need to be contiguous. This option allows making quick edits to a
504 logfile without all the size calculations involved in making all data
505 blocks contiguous again.
506
507 @item -m @var{file}
508 @itemx --domain-logfile=@var{file}
509 Restrict the rescue domain to the blocks marked as finished in the
510 logfile @var{file}. This is useful for merging partially recovered
511 images of backups, or if the destination drive fails during the rescue.
512
513 @item -M
514 @itemx --retrim
515 Mark all failed blocks inside the rescue domain as non-trimmed before
516 beginning the rescue. The effect is similar to @samp{--retry-passes=1},
517 but the bad sectors are tried in a different order, making perhaps
518 possible to rescue some of them.
519
520 @item -n
521 @itemx --no-split
522 Skip the splitting phase. Avoids spending a lot of time trying to rescue
523 the most difficult parts of the file.
524
525 @item -N
526 @itemx --no-trim
527 Skip the trimming phase. Specially useful in the first parts of a
528 multi-part rescue.
529
530 @item -o @var{bytes}
531 @itemx --output-position=@var{bytes}
532 Starting position of the image of the rescue domain in @var{outfile}, in
533 bytes. Defaults to @samp{--input-position}. The bytes below @var{bytes}
534 aren't touched if they exist and truncation is not requested. Else they
535 are set to 0.
536
537 @item -O
538 @itemx --reopen-on-error
539 Close @var{infile} and then reopen it after every read error and, if
540 @samp{--min-read-rate} is set, after every slow read encountered both
541 during the copying phase. Use this option if you notice a permanent drop
542 in transfer rate after finding read errors or slow areas. But be warned
543 that most probably the slowing-down is intentionally caused by the
544 kernel in an attempt to increase the probability of reading data from
545 the device.
546
547 @item -p
548 @itemx --preallocate
549 Preallocate space on disc for @var{outfile}. Only space for regular
550 files can be preallocated. If preallocation succeeds, rescue will not
551 fail due to lack of free space on disc. If ddrescue can't determine the
552 size to preallocate, you may need to specify it with some combination of
553 the @samp{--input-position}, @samp{--output-position}, @samp{--size},
554 and @samp{--domain-logfile} options.
555
556 @item -q
557 @itemx --quiet
558 Quiet operation. Suppress all messages.
559
560 @item -r @var{n}
561 @itemx --retry-passes=@var{n}
562 Exit after given number of retry passes. Defaults to 0. -1 means
563 infinity. Every bad sector is tried only once in each pass. To retry bad
564 sectors detected on a previous run, you must specify a non-zero number
565 of retry passes.
566
567 @item -R
568 @itemx --reverse
569 Reverse the direction of the first pass of copying, all retrying passes,
570 and the sequential part of splitting, running them backwards from the
571 end of the rescue domain (or from the end of @var{infile} if no domain
572 options are specified). @samp{--reverse} does not modify the size of the
573 blocks copied during each phase, just the order in which they are tried.
574
575 @item -s @var{bytes}
576 @itemx --size=@var{bytes}
577 Maximum size of the rescue domain, in bytes. It limits the amount of
578 input data to be copied. If ddrescue can't determine the size of the
579 input device, you may need to specify it with this option. Note that
580 this option does not specify the size of the resulting @var{outfile}.
581 For example, the following command creates an @var{outfile} 300 bytes
582 long, but only writes data on the last 200 bytes:
583
584 @example
585 ddrescue -i 100 -s 200 infile outfile logfile
586 @end example
587
588 @item -S
589 @itemx --sparse
590 Use sparse writes for @var{outfile}. (The blocks of zeros are not
591 actually allocated on disc). May save a lot of disc space in some cases.
592 Not all systems support this. Only regular files can be sparse.
593
594 @item -t
595 @itemx --truncate
596 Truncate @var{outfile} to zero size before writing to it. Only works for
597 regular files, not for drives or partitions.
598
599 @item -T @var{interval}
600 @itemx --timeout=@var{interval}
601 Maximum time since last successful read allowed before giving up.
602 Defaults to infinity. @var{interval} is a rational number (like 1.5 or
603 1/2) optionally followed by one of @samp{s}, @samp{m}, @samp{h} or
604 @samp{d}, meaning seconds, minutes, hours and days respectively. If no
605 unit is specified, it defaults to seconds.
606
607 @item -v
608 @itemx --verbose
609 Verbose mode. Further -v's (up to 4) increase the verbosity level.
610
611 @item -w
612 @itemx --ignore-write-errors
613 Make fill mode ignore write errors. This is useful to avoid ddrescue
614 exiting because of new errors developing while wiping the good sectors
615 of a failing drive. Fill mode normally writes to @var{outfile} one
616 cluster at a time. With this option, after the first write error is
617 found in an area, the rest of that area is filled sector by sector.
618
619 @item -x @var{bytes}
620 @itemx --extend-outfile=@var{bytes}
621 Extend the size of @var{outfile} to make it at least @var{bytes} long.
622 If the size of @var{outfile} is already equal or longer than @var{bytes}
623 then this option does nothing. Use this option to guarantee a minimum
624 size for @var{outfile}. Only regular files can be extended.
625
626 @item -1 @var{file}
627 @itemx --log-rates=@var{file}
628 Log rates and error sizes every second in @var{file}. If @var{file}
629 already exists, it will be overwritten. Every time the screen is updated
630 with new details, some of those details (time, input position, current
631 and average rates, number of errors and error size) are written to
632 @var{file} in a format usable by plotting utilities like gnuplot. This
633 allows a posterior analysis of the drive to see if it has any weak zones
634 (areas where the transfer rate drops well below the sustained average).
635
636 @item -2 @var{file}
637 @itemx --log-reads=@var{file}
638 Log all read operations in @var{file}. If @var{file} already exists, it
639 will be overwritten. Every read attempt and its result (position, size,
640 copied size and error size) is written to @var{file}. (The position
641 written is always the beginning of the block tried, even if reading
642 backwards). A line is also written at the beginning of each phase
643 (copying, trimming, splitting and retrying). Finally, a line with a time
644 mark is written every second (unless the read takes more time). Use this
645 option with caution because @var{file} may become very large very
646 quickly. Use lzip to compress @var{file} if you need to store or
647 transmit it.
648
649 @end table
650
651 Numbers given as arguments to options (positions, sizes, rates, etc) may
652 be expressed as decimal, hexadecimal or octal values (using the same
653 syntax as integer constants in C++), and may be followed by a multiplier
654 and an optional @samp{B} for "byte".
655
656 Table of SI and binary prefixes (unit multipliers):
657
658 @multitable {Prefix} {kilobyte (10^3 = 1000)} {|} {Prefix} {kibibyte (2^10 = 1024)}
659 @item Prefix @tab Value @tab | @tab Prefix @tab Value
660 @item @tab @tab | @tab s @tab sectors
661 @item k @tab kilobyte (10^3 = 1000) @tab | @tab Ki @tab kibibyte (2^10 = 1024)
662 @item M @tab megabyte (10^6) @tab | @tab Mi @tab mebibyte (2^20)
663 @item G @tab gigabyte (10^9) @tab | @tab Gi @tab gibibyte (2^30)
664 @item T @tab terabyte (10^12) @tab | @tab Ti @tab tebibyte (2^40)
665 @item P @tab petabyte (10^15) @tab | @tab Pi @tab pebibyte (2^50)
666 @item E @tab exabyte (10^18) @tab | @tab Ei @tab exbibyte (2^60)
667 @item Z @tab zettabyte (10^21) @tab | @tab Zi @tab zebibyte (2^70)
668 @item Y @tab yottabyte (10^24) @tab | @tab Yi @tab yobibyte (2^80)
669 @end multitable
670
671 @sp 1
672 Exit status: 0 for a normal exit, 1 for environmental problems (file not
673 found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
674 invalid input file, 3 for an internal consistency error (eg, bug) which
675 caused ddrescue to panic.
676
677 If ddrescue is interrupted by a signal, it updates the logfile and then
678 terminates by raising the signal received.
679
680
681 @node Logfile structure
682 @chapter Logfile structure
683 @cindex logfile structure
684
685 The logfile is a text file easy to read and edit. It is formed by three
686 parts, the heading comments, the status line, and the list of data
687 blocks. Any line beginning with @samp{#} is a comment line.
688
689 The heading comments contain the version of ddrescue or ddrescuelog that
690 created the logfile, the command line used, and the time when the
691 program started. If the logfile was created by ddrescue it will also
692 contain the current time when the logfile was saved and a copy of the
693 status message from the screen describing the operation being performed
694 (copying, trimming, finished, etc). They are intended as information for
695 the user.
696
697 The first non-comment line is the status line. It contains a
698 non-negative integer and a status character. The integer is the position
699 being tried in the input file. (The beginning of the block being tried
700 in a forward pass or the end of the block in a backward pass). The
701 status character is one of these:
702
703 @multitable {Character} {generating approximate logfile}
704 @item Character @tab Meaning
705 @item '?' @tab copying non-tried blocks
706 @item '*' @tab trimming non-trimmed blocks
707 @item '/' @tab splitting non-split blocks
708 @item '-' @tab retrying bad sectors
709 @item 'F' @tab filling specified blocks
710 @item 'G' @tab generating approximate logfile
711 @item '+' @tab finished
712 @end multitable
713
714 The blocks in the list of data blocks must be contiguous and
715 non-overlapping.
716
717 Every line in the list of data blocks describes a block of data. It
718 contains 2 non-negative integers and a status character. The first
719 integer is the starting position of the block in the input file, the
720 second integer is the size (in bytes) of the block. The status character
721 is one of these:
722
723 @multitable {Character} {failed block bad-sector(s)}
724 @item Character @tab Meaning
725 @item '?' @tab non-tried block
726 @item '*' @tab failed block non-trimmed
727 @item '/' @tab failed block non-split
728 @item '-' @tab failed block bad-sector(s)
729 @item '+' @tab finished block
730 @end multitable
731
732 @noindent
733 And here is an example logfile:
734
735 @example
736 # Rescue Logfile. Created by GNU ddrescue version @value{VERSION}
737 # Command line: ddrescue -d -c18 /dev/fd0 fdimage logfile
738 # Start time: 2014-05-03 09:37:44
739 # Current time: 2014-05-03 09:38:19
740 # Copying non-tried blocks... Pass 1 (forwards)
741 # current_pos current_status
742 0x00120000 ?
743 # pos size status
744 0x00000000 0x00117000 +
745 0x00117000 0x00000200 -
746 0x00117200 0x00001000 /
747 0x00118200 0x00007E00 *
748 0x00120000 0x00048000 ?
749 @end example
750
751 If you edit the file, you may use decimal, hexadecimal or octal values,
752 using the same syntax as integer constants in C++.
753
754 NOTE: Logfiles generated by a version of ddrescue prior to 1.6 lack the
755 status line. If you want to use an old logfile with ddrescue 1.6 or
756 later, you will have to insert a line like @samp{0 +} at the beginning
757 of the logfile.
758
759
760 @node Examples
761 @chapter A small tutorial with examples
762 @cindex examples
763
764 This tutorial is for those already able to use the dd command. If you
765 don't know what dd is, better search the net for some introductory
766 material about dd and GNU ddrescue first.
767
768 A failing drive tends to develop more and more errors as time passes.
769 Because of this, you should rescue the data from a drive as soon as you
770 notice the first error. Be diligent because every time a physically
771 damaged drive powers up and is able to output some data, it may be the
772 very last time that it ever will.
773
774 You should make a copy of the failing drive with ddrescue, and then try
775 to repair the copy. If your data is really important, use the first copy
776 as a master for a second copy, and try to repair the second copy. If
777 something goes wrong, you have the master intact to try again.
778
779 If you are trying to rescue a whole partition, first repair the copy
780 with e2fsck or some other tool appropriate for the type of partition you
781 are trying to rescue, then mount the repaired copy somewhere and try to
782 recover the files in it.
783
784 If the drive is so damaged that the file system in the rescued partition
785 can't be repaired or mounted, you will have to browse the rescued data
786 with an hex editor and extract the desired parts by hand or use a file
787 recovery tool like photorec.
788
789 If the partition table is damaged, you may try to rescue the whole disc,
790 then try to repair the partition table and the partitions on the copy.
791
792 If the damaged drive is not listed in /dev, then you cannot rescue it.
793 At least not with ddrescue.
794
795 @sp 1
796 @noindent
797 Example 1: Rescue a whole disc with two ext2 partitions in /dev/hda to
798 /dev/hdb.@*
799 Note: you do not need to partition /dev/hdb beforehand, but if the
800 partition table on /dev/hda is damaged, you'll need to recreate it
801 somehow on /dev/hdb.
802
803 @example
804 ddrescue -f -n /dev/hda /dev/hdb logfile
805 ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
806 fdisk /dev/hdb
807 e2fsck -v -f /dev/hdb1
808 e2fsck -v -f /dev/hdb2
809 @end example
810
811 @sp 1
812 @noindent
813 Example 2: Rescue an ext2 partition in /dev/hda2 to /dev/hdb2.@*
814 Note: you need to create the hdb2 partition with fdisk first. hdb2
815 should be of appropriate type and size.
816
817 @example
818 ddrescue -f -n /dev/hda2 /dev/hdb2 logfile
819 ddrescue -d -f -r3 /dev/hda2 /dev/hdb2 logfile
820 e2fsck -v -f /dev/hdb2
821 mount -t ext2 -o ro /dev/hdb2 /mnt
822 (read rescued files from /mnt)
823 @end example
824
825 @sp 1
826 @noindent
827 Example 3: Rescue a CD-ROM in /dev/cdrom.
828
829 @example
830 ddrescue -n -b2048 /dev/cdrom cdimage logfile
831 ddrescue -d -b2048 /dev/cdrom cdimage logfile
832 (if errsize is zero, cdimage now contains a complete image of the
833 CD-ROM and you can write it to a blank CD-ROM)
834 @end example
835
836 @sp 1
837 @noindent
838 Example 4: Rescue a CD-ROM in /dev/cdrom from two copies.
839
840 @example
841 ddrescue -n -b2048 /dev/cdrom cdimage logfile
842 ddrescue -d -b2048 /dev/cdrom cdimage logfile
843 (insert second copy in the CD drive)
844 ddrescue -d -r1 -b2048 /dev/cdrom cdimage logfile
845 (if errsize is zero, cdimage now contains a complete image of the
846 CD-ROM and you can write it to a blank CD-ROM)
847 @end example
848
849 @sp 1
850 @noindent
851 Example 5: Merge the partially recovered images of 3 identical DVDs
852 using their logfiles as domain logfiles.
853
854 @example
855 ddrescue -m logfile1 dvdimage1 dvdimage logfile
856 ddrescue -m logfile2 dvdimage2 dvdimage logfile
857 ddrescue -m logfile3 dvdimage3 dvdimage logfile
858 (if errsize is zero, dvdimage now contains a complete image of the DVD
859 and you can write it to a blank DVD)
860 @end example
861
862 @sp 1
863 @anchor{lziprecover-example}
864 @noindent
865 Example 6: Rescue a lzip compressed backup from two copies on CD-ROM
866 with error-checked merging of copies
867 @ifnothtml
868 (@xref{Top,lziprecover manual,,lziprecover},
869 @end ifnothtml
870 @ifhtml
871 (See the
872 @uref{http://www.nongnu.org/lzip/manual/lziprecover_manual.html,,lziprecover manual}
873 @end ifhtml
874 for details about lziprecover).
875
876 @example
877 ddrescue -b2048 /dev/cdrom cdimage1 logfile1
878 mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage
879 cp /mnt/cdimage/backup.tar.lz rescued1.tar.lz
880 umount /mnt/cdimage
881 (insert second copy in the CD drive)
882 ddrescue -b2048 /dev/cdrom cdimage2 logfile2
883 mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage
884 cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz
885 umount /mnt/cdimage
886 lziprecover -m -v -o backup.tar.lz rescued1.tar.lz rescued2.tar.lz
887 @end example
888
889 @sp 1
890 @noindent
891 Example 7: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
892 freezes up at position 12345678.
893
894 @example
895 ddrescue -f /dev/hda /dev/hdb logfile <-- /dev/hda freezes here
896 (restart /dev/hda or reboot computer)
897 (restart copy at a safe distance from the troubled sector)
898 ddrescue -f -i 12350000 /dev/hda /dev/hdb logfile
899 (copy backwards down to the troubled sector)
900 ddrescue -f -R /dev/hda /dev/hdb logfile
901 @end example
902
903 @sp 1
904 @noindent
905 Example 8: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hdb
906 fails and you have to rescue data to a third drive, /dev/hdc.
907
908 @example
909 ddrescue -f -n /dev/hda /dev/hdb logfile1 <-- /dev/hdb fails here
910 ddrescue -f -m logfile1 /dev/hdb /dev/hdc logfile2
911 ddrescue -f -n /dev/hda /dev/hdc logfile2
912 ddrescue -d -f -r3 /dev/hda /dev/hdc logfile2
913 @end example
914
915 @sp 1
916 @noindent
917 Example 9: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
918 stops responding and disappears from /dev.
919
920 @example
921 ddrescue -f -n /dev/hda /dev/hdb logfile <-- /dev/hda fails here
922 (restart /dev/hda or reboot computer as many times as needed)
923 ddrescue -f -n -A /dev/hda /dev/hdb logfile
924 ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
925 @end example
926
927
928 @node Direct disc access
929 @chapter Direct disc access
930 @cindex direct disc access
931 @cindex raw devices
932
933 If you notice that the positions and sizes in the logfile are ALWAYS
934 multiples of the sector size, maybe your kernel is caching the disc
935 accesses and grouping them. In this case you may want to use direct disc
936 access or a raw device to bypass the kernel cache and rescue more of
937 your data.
938
939 NOTE! Sector size must be correctly set with the @samp{--sector-size}
940 option for this to work. Only whole sectors can be read; both
941 @samp{--input-position} and @samp{--size} must be a multiple of sector
942 size.
943
944 Try the @samp{--direct} option first. If direct disc access is not
945 available in your system, try raw devices. Read your system
946 documentation to find how to bind a raw device to a regular block
947 device. Some OSs provide raw access through special device names, like
948 /dev/rdisk.
949
950 Ddrescue aligns its I/O buffer to the sector size so that it can be used
951 for direct disc access or to read from raw devices. For efficiency
952 reasons, also aligns it to the memory page size if page size is a
953 multiple of sector size. On some systems, ddrescue can't determine the
954 size of a raw device, so an explicit @samp{--size} or
955 @samp{--complete-only} option may be needed.
956
957 Using direct disc access, or reading from a raw device, may be slower or
958 faster than normal cached reading depending on your OS and hardware. In
959 case it is slower you may want to make a first pass using normal cached
960 reads and use direct disc access, or a raw device, only to recover the
961 good sectors inside the failed blocks.
962
963 @sp 1
964 @noindent
965 Example 1: using direct disc access.
966
967 @example
968 ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
969 ddrescue -d -f -r3 /dev/hdb1 /dev/hdc1 logfile
970 e2fsck -v -f /dev/hdc1
971 mount -t ext2 -o ro /dev/hdc1 /mnt
972 @end example
973
974 @sp 1
975 @noindent
976 Example 2: using a raw device.
977
978 @example
979 raw /dev/raw/raw1 /dev/hdb1
980 ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
981 ddrescue -C -f -r3 /dev/raw/raw1 /dev/hdc1 logfile
982 raw /dev/raw/raw1 0 0
983 e2fsck -v -f /dev/hdc1
984 mount -t ext2 -o ro /dev/hdc1 /mnt
985 @end example
986
987
988 @node Fill mode
989 @chapter Fill mode
990 @cindex fill Mode
991
992 When ddrescue is invoked with the @samp{--fill-mode} option it operates
993 in "fill mode", which is different from the default "rescue mode". That
994 is, if you use the @samp{--fill-mode} option, ddrescue does not rescue
995 anything. It only fills with data read from the input file the blocks of
996 the output file whose status character from the logfile coincides with
997 one of the type characters specified as argument to the
998 @samp{--fill-mode} option.
999
1000 In fill mode the input file may have any size. If it is too small, the
1001 data will be duplicated as many times as necessary to fill the input
1002 buffer. If it is too big, only the data needed to fill the input buffer
1003 will be read. Then the same data will be written to every cluster or
1004 sector to be filled.
1005
1006 Note that in fill mode the input file is always read from position 0. If
1007 you specify a @samp{--input-position}, it refers to the original input
1008 file from which the logfile was built, and is only used to calculate the
1009 offset between input and output positions.
1010
1011 Note also that when filling the input file of the original rescue run
1012 you should set @samp{--input-position} and @samp{--output-position} to
1013 identical values, whereas when filling the output file of the original
1014 rescue run you should keep the original offset between
1015 @samp{--input-position} and @samp{--output-position}.
1016
1017 The @samp{--fill-mode} option implies the @samp{--complete-only} option.
1018
1019 In fill mode the logfile is updated to allow resumability when
1020 interrupted or in case of a crash, but as nothing is being rescued the
1021 logfile is not destroyed. The status line is the only part of the
1022 logfile that is modified.
1023
1024 @sp 1
1025 @noindent
1026 The fill mode has a number of uses. See the following examples:
1027
1028 @noindent
1029 Example 1: Mark parts of the rescued copy to allow finding them when
1030 examined in an hex editor. For example, the following command line fills
1031 all blocks marked as @samp{-} (bad-sector) with copies of the string
1032 @w{@samp{BAD SECTOR }}:
1033
1034 @example
1035 printf "BAD SECTOR " > tmpfile
1036 ddrescue --fill-mode=- tmpfile outfile logfile
1037 @end example
1038
1039 @noindent
1040 Example 2: Wipe only the good sectors, leaving the bad sectors alone.
1041 This way, the drive will still test bad (i.e., with unreadable sectors).
1042 This is the fastest way of wiping a failing drive, and is specially
1043 useful when sending the drive back to the manufacturer for warranty
1044 replacement.
1045
1046 @example
1047 ddrescue --fill-mode=+ --force /dev/zero bad_drive logfile
1048 @end example
1049
1050 @noindent
1051 Example 3: Force the drive to remap the bad sectors, making it usable
1052 again. If the drive has only a few bad sectors, and they are not caused
1053 by drive age, you can probably just rewrite those sectors, and the drive
1054 will reallocate them automatically to new "spare" sectors that it keeps
1055 for just this purpose. WARNING! This may not work on your drive.
1056
1057 @example
1058 ddrescue --fill-mode=- --force --synchronous /dev/zero bad_drive logfile
1059 @end example
1060
1061 @sp 1
1062 @noindent
1063 Fill mode can also help you to figure out, independently of the file
1064 system used, what files are partially or entirely in the bad areas of
1065 the disc. Just follow these steps:
1066
1067 1) Copy the damaged drive with ddrescue until finished. Do not use
1068 sparse writes. This yields a logfile with only finished (@samp{+}) and
1069 bad-sector (@samp{-}) blocks.
1070
1071 2) Fill the bad-sector blocks of the copied drive or image file with a
1072 string not present in any file, for example "DEADBEEF".
1073
1074 3) Mount the copied drive (or the image file, via loopback device).
1075
1076 4) Grep for the fill string in all the files. Those files containing the
1077 string reside (at least partially) in damaged disc areas. Note that if
1078 all the damaged areas are in unused space, grep will not find the string
1079 in any file, which means that no files are damaged.
1080
1081 5) Unmount the copied drive or image file.
1082
1083 6) Optionally fill the bad-sector blocks of the copied drive or image
1084 file with zeros to restore the disc image.
1085
1086 @noindent
1087 Example 4: Figure out what files are in the bad areas of the disc.
1088
1089 @example
1090 ddrescue -b2048 /dev/cdrom cdimage logfile
1091 printf "DEADBEEF" > tmpfile
1092 ddrescue --fill-mode=- tmpfile cdimage logfile
1093 rm tmpfile
1094 mount -t iso9660 -o loop,ro cdimage /mnt/cdimage
1095 find /mnt/cdimage -type f -exec grep -l "DEADBEEF" '@{@}' ';'
1096 umount /mnt/cdimage
1097 ddrescue --fill-mode=- /dev/zero cdimage logfile
1098 @end example
1099
1100
1101 @node Generate mode
1102 @chapter Generate mode
1103 @cindex generate Mode
1104
1105 NOTE: When ddrescue is invoked with the @samp{--generate-mode} option it
1106 operates in "generate mode", which is different from the default "rescue
1107 mode". That is, if you use the @samp{--generate-mode} option, ddrescue
1108 does not rescue anything. It only tries to generate a logfile for later
1109 use.
1110
1111 So you didn't read the tutorial and started ddrescue without a logfile.
1112 Now, two days later, your computer crashed and you can't know how much
1113 data ddrescue managed to save. And even worse, you can't resume the
1114 rescue; you have to restart it from the very beginning.
1115
1116 Or maybe you started copying a drive with @w{@code{dd
1117 conv=noerror,sync}} and are now in the same situation described above.
1118 In this case, note that you can't use a copy made by dd unless it was
1119 invoked with the @samp{sync} conversion argument.
1120
1121 Don't despair (yet). Ddrescue can in some cases generate an approximate
1122 logfile, from the input file and the (partial) copy, that is almost as
1123 good as an exact logfile. It makes this by simply assuming that sectors
1124 containing all zeros were not rescued.
1125
1126 However, if the destination of the copy was a drive or a partition, (or
1127 an existing regular file and truncation was not requested), most
1128 probably you will need to restart ddrescue from the very beginning.
1129 (This time with a logfile, of course). The reason is that old data may
1130 be present in the drive that have not been overwritten yet, and may be
1131 thus non-tried but non-zero.
1132
1133 For example, if you first tried one of these commands:
1134 @example
1135 ddrescue infile outfile
1136 or
1137 dd if=infile of=outfile conv=noerror,sync
1138 @end example
1139
1140 then you can generate an approximate logfile with this command:
1141 @example
1142 ddrescue --generate-mode infile outfile logfile
1143 @end example
1144
1145 @noindent
1146 Note that you must keep the original offset between
1147 @samp{--input-position} and @samp{--output-position} of the original
1148 rescue run.
1149
1150
1151 @node Ddrescuelog
1152 @chapter Ddrescuelog
1153 @cindex ddrescuelog
1154
1155 Ddrescuelog is a tool that manipulates ddrescue logfiles, shows logfile
1156 contents, converts logfiles to/from other formats, compares logfiles,
1157 tests rescue status, and can delete a logfile if the rescue is done.
1158 Ddrescuelog operations can be restricted to one or several parts of the
1159 logfile if the domain setting options are used.
1160
1161 When performing logic operations (AND, OR, XOR) on logfiles of different
1162 extension, only the blocks present in both files are processed.
1163
1164 Here are some examples of how to use ddrescuelog, alone or in
1165 combination with other tools.
1166
1167 @sp 1
1168 @noindent
1169 Example 1: Delete the logfile if the rescue is finished (all data is
1170 recovered without errors left).
1171
1172 @example
1173 ddrescue -f /dev/hda /dev/hdb logfile
1174 ddrescuelog -d logfile
1175 @end example
1176
1177 @sp 1
1178 @noindent
1179 Example 2: Rescue two ext2 partitions in /dev/hda to
1180 /dev/hdb and repair the file systems using badblock lists generated with
1181 ddrescuelog. File system block size is 4096.@*
1182 Note: you do need to partition /dev/hdb beforehand.
1183
1184 @example
1185 fdisk /dev/hdb <-- partition /deb/hdb
1186 ddrescue -f /dev/hda1 /dev/hdb1 logfile1
1187 ddrescue -f /dev/hda2 /dev/hdb2 logfile2
1188 ddrescuelog -l- -b4096 logfile1 > badblocks1
1189 ddrescuelog -l- -b4096 logfile2 > badblocks2
1190 e2fsck -v -f -L badblocks1 /dev/hdb1
1191 e2fsck -v -f -L badblocks2 /dev/hdb2
1192 @end example
1193
1194 @sp 1
1195 @noindent
1196 Example 3: Rescue a whole disc with two ext2 partitions in /dev/hda to
1197 /dev/hdb and repair the file systems using badblock lists generated with
1198 ddrescuelog. Disc sector size is 512, file system block size is 4096.
1199 Arguments to options @samp{-i} and @samp{-s} are the starting positions
1200 and sizes of the partitions being rescued.@*
1201 Note: you do not need to partition /dev/hdb beforehand, but if the
1202 partition table on /dev/hda is damaged, you'll need to recreate it
1203 somehow on /dev/hdb.
1204
1205 @example
1206 ddrescue -f /dev/hda /dev/hdb logfile
1207 fdisk /dev/hdb <-- get partition sizes
1208 ddrescuelog -l- -b512 -i63b -o0 -s9767457b -b4096 logfile > badblocks1
1209 ddrescuelog -l- -b512 -i9767520b -o0 -s128520b -b4096 logfile > badblocks2
1210 e2fsck -v -f -L badblocks1 /dev/hdb1
1211 e2fsck -v -f -L badblocks2 /dev/hdb2
1212 @end example
1213
1214
1215 @node Invoking ddrescuelog
1216 @chapter Invoking ddrescuelog
1217 @cindex invoking ddrescuelog
1218
1219 The format for running ddrescuelog is:
1220
1221 @example
1222 ddrescuelog [@var{options}] @var{logfile}
1223 @end example
1224
1225 Ddrescuelog supports the following options:
1226
1227 @table @samp
1228 @item -h
1229 @itemx --help
1230 Print an informative help message describing the options and exit.
1231
1232 @item -V
1233 @itemx --version
1234 Print the version number of ddrescuelog on the standard output and exit.
1235
1236 @item -a @var{old_types},@var{new_types}
1237 @itemx --change-types=@var{old_types},@var{new_types}
1238 Change the status of every block in the rescue domain from one type in
1239 @var{old_types} to the corresponding type in @var{new_types}, much like
1240 the @samp{tr} command does, and write the resulting logfile to standard
1241 output. @var{old_types} and @var{new_types} are strings of block status
1242 characters as defined in the chapter Logfile structure (@pxref{Logfile
1243 structure}). Blocks whose status is not in @var{old_types} are left
1244 unchanged. If @var{new_types} is shorter than @var{old_types} the last
1245 type of @var{new_types} is repeated as many times as necessary.
1246
1247 @item -b @var{bytes}
1248 @itemx --block-size=@var{bytes}
1249 Block size used by ddrescuelog. Depending on the requested operation it
1250 may be the sector size of the input device, the block size of the
1251 rescued file system, etc. Defaults to 512.
1252
1253 @item -B
1254 @itemx --binary-prefixes
1255 Show units with binary prefixes (powers of 1024).@*
1256 SI prefixes (powers of 1000) are used by default. (See table above,
1257 @ref{Invoking ddrescue}).
1258
1259 @item -c[@var{type1}@var{type2}]
1260 @itemx --create-logfile[=@var{type1}@var{type2}]
1261 Create a logfile from a list of block numbers read from standard input.
1262 Only blocks included in the rescue domain will be added to @var{logfile}.
1263
1264 @var{type1} and @var{type2} are block status characters as defined in
1265 the chapter Logfile structure (@pxref{Logfile structure}). @var{type1}
1266 sets the type for blocks included in the list, while @var{type2} sets
1267 the type for the rest of the logfile. If not specified, @var{type1}
1268 defaults to @samp{+} and @var{type2} defaults to @samp{-}.
1269
1270 @item -C[@var{type}]
1271 @itemx --complete-logfile[=@var{type}]
1272 Complete a synthetic (user fabricated) @var{logfile} by filling the gaps
1273 with blocks of type @var{type}, and write the completed logfile to
1274 standard output. @var{type} is one of the block status characters
1275 defined in the chapter Logfile structure (@pxref{Logfile structure}). If
1276 @var{type} is not specified, the gaps are filled with non-tried blocks.
1277 All gaps in the logfile are filled. Domain options are ignored.
1278
1279 @item -d
1280 @itemx --delete-if-done
1281 Delete the given @var{logfile} if all the blocks in the rescue domain
1282 have been successfuly recovered. The exit status is 0 if @var{logfile}
1283 could be deleted, 1 otherwise.
1284
1285 @item -D
1286 @itemx --done-status
1287 Test if all the blocks in the rescue domain have been successfuly
1288 recovered. The exit status is 0 if all tested blocks are finished, 1
1289 otherwise.
1290
1291 @item -f
1292 @itemx --force
1293 Force overwrite of @var{logfile}.
1294
1295 @item -i @var{bytes}
1296 @itemx --input-position=@var{bytes}
1297 Starting position of the rescue domain, in bytes. Defaults to 0. It
1298 refers to a position in the original input file.
1299
1300 @item -l @var{types}
1301 @itemx --list-blocks=@var{types}
1302 Print on standard output the block numbers of the blocks specified as
1303 any of @var{types} in @var{logfile} and included in the rescue domain.
1304 @var{types} contains one or more of the block status characters defined
1305 in the chapter Logfile structure (@pxref{Logfile structure}).
1306
1307 The list format is one block number per line in decimal, like the output
1308 of the badblocks program, so that it can be used as input for e2fsck or
1309 other similar filesystem repairing tool.
1310
1311 @item -L
1312 @itemx --loose-domain
1313 Accept an incomplete synthetic (user fabricated) domain logfile or
1314 compare-as-domain logfile and fill the gaps with non-tried blocks. The
1315 blocks in the logfile must be strictly ascending and non-overlapping,
1316 but they do not need to be contiguous. This option allows making quick
1317 edits to a logfile without all the size calculations involved in making
1318 all data blocks contiguous again.
1319
1320 @item -m @var{file}
1321 @itemx --domain-logfile=@var{file}
1322 Restrict the rescue domain to the blocks marked as finished in the
1323 logfile @var{file}.
1324
1325 @item -n
1326 @itemx --invert-logfile
1327 Invert the types of the blocks in @var{logfile} which are included in
1328 the rescue domain, and write the resulting logfile to standard output.
1329 Finished blocks (@samp{+}) are changed to bad-sector (@samp{-}), all
1330 other types are changed to finished. @samp{--invert-logfile} is
1331 equivalent to @samp{--change-types=?*/-+,++++-}
1332
1333 @item -o @var{bytes}
1334 @itemx --output-position=@var{bytes}
1335 Starting position of the image of the rescue domain in the output file,
1336 in bytes. Is used by the @samp{--list-blocks} option. Defaults to
1337 @samp{--input-position}.
1338
1339 @item -p @var{file}
1340 @itemx --compare-logfile=@var{file}
1341 Compare the types of the blocks included in the rescue domain. The exit
1342 status is 0 if all tested blocks are the same in both @var{file} and
1343 @var{logfile}, 1 otherwise.
1344
1345 @item -P @var{file}
1346 @itemx --compare-as-domain=@var{file}
1347 Compare only the blocks marked as finished in the rescue domain. The
1348 exit status is 0 if all tested blocks are the same in both @var{file}
1349 and @var{logfile}, 1 otherwise. Two files comparing equal with this
1350 option are equivalent when used as domain logfiles.
1351
1352 @item -q
1353 @itemx --quiet
1354 Quiet operation. Suppress all messages.
1355
1356 @item -s @var{bytes}
1357 @itemx --size=@var{bytes}
1358 Maximum size of the rescue domain, in bytes. It refers to a size in the
1359 original input file.
1360
1361 @item -t
1362 @itemx --show-status
1363 Print a summary of @var{logfile} contents on the standard output. The
1364 summary can be restricted to one or several parts of @var{logfile} if
1365 the domain setting options are used.
1366
1367 @item -v
1368 @itemx --verbose
1369 Verbose mode. Further -v's (up to 4) increase the verbosity level.
1370
1371 @item -x @var{file}
1372 @itemx --xor-logfile=@var{file}
1373 Perform a logical XOR (exclusive OR) operation between the finished
1374 blocks in @var{file} and those in @var{logfile}, and write the resulting
1375 logfile to standard output. In other words, in the resulting logfile a
1376 block is only shown as finished if it was finished in either of the two
1377 input logfiles but not in both.
1378
1379 @item -y @var{file}
1380 @itemx --and-logfile=@var{file}
1381 Perform a logical AND operation between the finished blocks in
1382 @var{file} and those in @var{logfile}, and write the resulting logfile
1383 to standard output. In other words, in the resulting logfile a block is
1384 only shown as finished if it was finished in both input logfiles.
1385
1386 @item -z @var{file}
1387 @itemx --or-logfile=@var{file}
1388 Perform a logical OR operation between the finished blocks in @var{file}
1389 and those in @var{logfile}, and write the resulting logfile to standard
1390 output. In other words, in the resulting logfile a block is shown as
1391 finished if it was finished in either of the two input logfiles.
1392
1393 @end table
1394
1395 Exit status: 0 for a normal exit, 1 for environmental problems (file not
1396 found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
1397 invalid input file, 3 for an internal consistency error (eg, bug) which
1398 caused ddrescuelog to panic.
1399
1400
1401 @node Problems
1402 @chapter Reporting bugs
1403 @cindex bugs
1404 @cindex getting help
1405
1406 There are probably bugs in ddrescue. There are certainly errors and
1407 omissions in this manual. If you report them, they will get fixed. If
1408 you don't, no one will ever know about them and they will remain unfixed
1409 for all eternity, if not longer.
1410
1411 If you find a bug in GNU ddrescue, please send electronic mail to
1412 @email{bug-ddrescue@@gnu.org}. Include the version number, which you can
1413 find by running @w{@samp{ddrescue --version}}.
1414
1415
1416 @node Concept index
1417 @unnumbered Concept index
1418
1419 @printindex cp
1420
1421 @bye
+0
-1243
doc/ddrescue.texinfo less more
0 \input texinfo @c -*-texinfo-*-
1 @c %**start of header
2 @setfilename ddrescue.info
3 @documentencoding ISO-8859-15
4 @settitle GNU ddrescue Manual
5 @finalout
6 @c %**end of header
7
8 @set UPDATED 9 July 2013
9 @set VERSION 1.17
10
11 @dircategory GNU Packages
12 @direntry
13 * Ddrescue: (ddrescue). Data recovery tool
14 @end direntry
15
16
17 @ifnothtml
18 @titlepage
19 @title GNU ddrescue
20 @subtitle Data recovery tool
21 @subtitle for Ddrescue version @value{VERSION}, @value{UPDATED}
22 @author by Antonio Diaz Diaz
23
24 @page
25 @vskip 0pt plus 1filll
26 @end titlepage
27
28 @contents
29 @end ifnothtml
30
31 @node Top
32 @top
33
34 This manual is for GNU ddrescue (version @value{VERSION}, @value{UPDATED}).
35
36 @menu
37 * Introduction:: Purpose and features of GNU ddrescue
38 * Basic concepts:: Blocks, clusters, devices, files, sectors, etc
39 * Important advice:: Read this or risk losing your data
40 * Algorithm:: How ddrescue recovers the data
41 * Invoking ddrescue:: Command line interface
42 * Logfile structure:: Detailed format of the logfile
43 * Examples:: A small tutorial with examples
44 * Direct disc access:: Bypassing the kernel cache
45 * Fill mode:: Selectively overwriting the output file
46 * Generate mode:: Generating an approximate logfile
47 * Ddrescuelog:: Tool for ddrescue logfiles
48 * Invoking ddrescuelog:: Command line interface
49 * Problems:: Reporting bugs
50 * Concept index:: Index of concepts
51 @end menu
52
53 @sp 1
54 Copyright @copyright{} 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
55 2012, 2013 Antonio Diaz Diaz.
56
57 This manual is free documentation: you have unlimited permission
58 to copy, distribute and modify it.
59
60
61 @node Introduction
62 @chapter Introduction
63 @cindex introduction
64
65 GNU ddrescue is a data recovery tool. It copies data from one file or
66 block device (hard disc, cdrom, etc) to another, trying hard to rescue
67 data in case of read errors.
68
69 The basic operation of ddrescue is fully automatic. That is, you don't
70 have to wait for an error, stop the program, read the log, restart it
71 from a new position, etc.
72
73 If you use the logfile feature of ddrescue, the data is rescued very
74 efficiently, (only the needed blocks are read). Also you can interrupt
75 the rescue at any time and resume it later at the same point.
76
77 Ddrescue does not write zeros to the output when it finds bad sectors in
78 the input, and does not truncate the output file if not asked to. So,
79 every time you run it on the same output file, it tries to fill in the
80 gaps without wiping out the data already rescued.
81
82 Automatic merging of backups: If you have two or more damaged copies of
83 a file, cdrom, etc, and run ddrescue on all of them, one at a time,
84 with the same output file, you will probably obtain a complete and
85 error-free file. This is so because the probability of having damaged
86 areas at the same places on different input files is very low. Using
87 the logfile, only the needed blocks are read from the second and
88 successive copies.
89
90 Ddrescue recommends lzip for compression of backups because of its
91 reliability and data recovery capabilities, including error-checked
92 merging of backup copies. Lziprecover makes lzip files resistant to
93 bit-flip, one of the most common forms of data corruption, and its
94 recovery capabilities contribute to make of the lzip format one of the
95 best formats for long-term data archiving. The combination ddrescue +
96 lziprecover is the best option for recovering data from multiple damaged
97 copies. @xref{lziprecover-example}, for an example.
98
99 Recordable CD and DVD media keep their data only for a finite time
100 (typically for many years). After that time, data loss develops slowly
101 with read errors growing from the outer media region towards the inside.
102 Just make two (or more) copies of every important CD/DVD you burn so
103 that you can later recover them with ddrescue.
104
105 Because ddrescue needs to read and write at random places, it only works
106 on seekable (random access) input and output files.
107
108 If your system supports it, ddrescue can use direct disc access to read
109 the input file, bypassing the kernel cache.
110
111 Ddrescue also features a "fill mode" able to selectively overwrite parts
112 of the output file, which has a number of interesting uses like wiping
113 data, marking bad areas or even, in some cases, "repair" damaged
114 sectors.
115
116
117 @node Basic concepts
118 @chapter Basic concepts
119 @cindex basic concepts
120
121 @table @asis
122 @item Block
123 Any amount of data. A block is described by its starting position and
124 its size.
125
126 @item Cluster
127 Group of consecutive sectors read or written in one go.
128
129 @item Device
130 Piece of hardware containing data. Hard disc drives, cdrom drives, USB
131 pendrives, are devices. /dev/hda, /dev/sdb, are device names.
132
133 @item File
134 Files are named units of data which are stored by the operating system
135 for you to retrieve later by name. Devices and partitions are accessed
136 by means of their associated file names.
137
138 @item Partition
139 Every part in which a device is divided. A partition normally contains a
140 file system. /dev/hda1, /dev/sdb3, are partition names.
141
142 @item Recoverable formats
143 As ddrescue uses standard library functions to read data from the device
144 being rescued, only mountable device formats can be rescued with
145 ddrescue. DVDs can be mounted and they can be rescued, "compact disc
146 digital audio" CDs can't, "video CDs"[1] maybe.@*
147 [1] http://en.wikipedia.org/wiki/Video_CD
148
149 @item Rescue domain
150 Block or set of blocks to be acted upon (rescued, listed, etc). You can
151 define it with the options @samp{--input-position}, @samp{--size} and
152 @samp{--domain-logfile}. The rescue domain defaults to the whole input
153 file or logfile.
154
155 @item Sector
156 Hardware block. Smallest accessible amount of data on a device.
157
158 @end table
159
160
161 @node Important advice
162 @chapter Using ddrescue safely
163 @cindex using ddrescue safely
164
165 Ddrescue is like any other power tool. You need to understand what it
166 does, and you need to understand some things about the machines it does
167 those things to, in order to use it safely.
168
169 Always use a logfile unless you know you won't need it. Without a
170 logfile, ddrescue can't resume a rescue, only reinitiate it.
171
172 Never try to rescue a r/w mounted partition. The resulting copy may be
173 useless.
174
175 Never try to repair a file system on a drive with I/O errors; you will
176 probably lose even more data.
177
178 If you use a device or a partition as destination, any data stored there
179 will be overwritten.
180
181 Some systems may change device names on reboot (eg. udev enabled
182 systems). If you reboot, check the device names before restarting
183 ddrescue.
184
185 If you interrupt the rescue and then reboot, any partially copied
186 partitions should be hidden before allowing them to be touched by any
187 operating system that tries to mount and "fix" the partitions it sees.
188
189
190 @node Algorithm
191 @chapter Algorithm
192 @cindex algorithm
193
194 GNU ddrescue manages efficiently the status of the rescue in progress
195 and tries to rescue the good parts first, scheduling reads inside bad
196 (or slow) areas for later. This maximizes the amount of data that can be
197 finally recovered from a failing drive.
198
199 The standard dd utility can be used to save data from a failing drive,
200 but it reads the data sequentially, which may wear out the drive without
201 rescuing anything if the errors are at the beginning of the drive.
202
203 Other programs switch to small size reads when they find errors, but
204 they still read the data sequentially. This is a bad idea because it
205 means spending more time at error areas, damaging the surface, the heads
206 and the drive mechanics, instead of getting out of them as fast as
207 possible. This behavior reduces the chances of rescuing the remaining
208 good data.
209
210 The algorithm of ddrescue is as follows (the user may interrupt the
211 process at any point, but be aware that a bad drive can block ddrescue
212 for a long time until the kernel gives up):
213
214 1) Optionally read a logfile describing the status of a multi-part or
215 previously interrupted rescue. If no logfile is specified or is empty or
216 does not exist, mark all the rescue domain as non-tried.
217
218 2) (First phase; Copying) Read the non-tried parts of the input file,
219 marking the failed blocks as non-trimmed and skipping beyond them, until
220 all the rescue domain is tried. Only non-tried areas are read in large
221 blocks. Trimming, splitting and retrying are done sector by sector. Each
222 sector is tried at most two times; the first in this step as part of a
223 large block read, the second in one of the steps below as a single
224 sector read.
225
226 3) (Second phase; Trimming) Read forwards one sector at a time from the
227 leading edge of the largest non-trimmed block, until a bad sector is
228 found. Then read backwards one sector at a time from the trailing edge
229 of the same block, until a bad sector is found. For each non-trimmed
230 block, mark the bad sectors found as bad-sector and mark the rest of
231 that block as non-split. Repeat until there are no more non-trimmed
232 blocks.
233
234 4) (Third phase; Splitting) Read forwards one sector at a time from the
235 center of the largest non-split block, until a bad sector is found. Then
236 read backwards one sector at a time from the center of the same block,
237 until a bad sector is found. If the logfile is larger than
238 @samp{--logfile-size}, read the smallest non-split blocks until the
239 number of entries in the logfile drops below @samp{--logfile-size}.
240 Repeat until all remaining non-split blocks have less than 5 sectors.
241 Then read the remaining non-split blocks sequentially.
242
243 5) (Fourth phase; Retrying) Optionally try to read again the bad sectors
244 until the specified number of retries is reached.
245
246 6) Optionally write a logfile for later use.
247
248 @sp 1
249 Note that as ddrescue splits the failed blocks, making them smaller, the
250 total error size may diminish while the number of errors increases.
251
252 The logfile is periodically saved to disc, as well as when ddrescue
253 finishes or is interrupted. So in case of a crash you can resume the
254 rescue with little recopying.
255
256 Also, the same logfile can be used for multiple commands that copy
257 different areas of the input file, and for multiple recovery attempts
258 over different subsets. See this example:
259
260 @noindent
261 Rescue the most important part of the disc first.
262 @example
263 ddrescue -i0 -s50MiB /dev/hdc hdimage logfile
264 ddrescue -i0 -s1MiB -d -r3 /dev/hdc hdimage logfile
265 @end example
266
267 @noindent
268 Then rescue some key disc areas.
269 @example
270 ddrescue -i30GiB -s10GiB /dev/hdc hdimage logfile
271 ddrescue -i230GiB -s5GiB /dev/hdc hdimage logfile
272 @end example
273
274 @noindent
275 Now rescue the rest (does not recopy what is already done).
276 @example
277 ddrescue /dev/hdc hdimage logfile
278 ddrescue -d -r3 /dev/hdc hdimage logfile
279 @end example
280
281
282 @node Invoking ddrescue
283 @chapter Invoking ddrescue
284 @cindex invoking ddrescue
285 @cindex options
286 @cindex usage
287 @cindex version
288
289 The format for running ddrescue is:
290
291 @example
292 ddrescue [@var{options}] @var{infile} @var{outfile} [@var{logfile}]
293 @end example
294
295 ddrescue supports the following options:
296
297 @table @samp
298 @item -h
299 @itemx --help
300 Print an informative help message describing the options and exit.
301
302 @item -V
303 @itemx --version
304 Print the version number of ddrescue on the standard output and exit.
305
306 @item -a @var{bytes}
307 @itemx --min-read-rate=@var{bytes}
308 Minimum read rate of good non-tried areas, in bytes per second. If the
309 read rate falls below this value, ddrescue will skip ahead a variable
310 amount depending on rate and error history. The skipped blocks are tried
311 in additional passes (before trimming) where the minimum read rate is
312 divided by ten before each pass, until there are no more non-tried
313 blocks left. If @var{bytes} is 0 (auto), the minimum read rate is
314 recalculated for each block read as @w{(average_rate / 10)}.
315
316 @item -A
317 @itemx --try-again
318 Mark all non-split and non-trimmed blocks inside the rescue domain as
319 non-tried before beginning the rescue. Try this if the drive stops
320 responding and ddrescue immediately starts splitting failed blocks when
321 restarted. If @samp{--retrim} is also specified, mark all failed blocks
322 inside the rescue domain as non-tried.
323
324 @item -b @var{bytes}
325 @itemx --sector-size=@var{bytes}
326 Sector (hardware block) size of input device in bytes (usually 512 for
327 hard discs and 3.5" floppies, 1024 for 5.25" floppies, and 2048 for
328 cdroms). Defaults to 512.
329
330 @item -B
331 @itemx --binary-prefixes
332 Show units with binary prefixes (powers of 1024).@*
333 SI prefixes (powers of 1000) are used by default. (See table below).
334
335 @item -c @var{sectors}
336 @itemx --cluster-size=@var{sectors}
337 Number of sectors to copy at a time. Defaults to @w{64 KiB / sector_size}.
338 Try smaller values for slow drives. The number of sectors per track (18
339 or 9) is a good value for floppies.
340
341 @item -C
342 @itemx --complete-only
343 Limit rescue domain to the blocks listed in the @var{logfile}. Do not
344 read new data beyond @var{logfile} limits. This is useful when reading
345 from devices of undefined size (like raw devices), when the drive
346 returns an incorrect size, or when reading from a partial copy. It can
347 only be used after a first rescue attempt, possibly limited with the
348 @samp{--size} option, has produced a complete @var{logfile}.
349
350 @item -d
351 @itemx --direct
352 Use direct disc access to read from @var{infile}, bypassing the kernel
353 cache. (Open the file with the O_DIRECT flag). Use it only on devices or
354 partitions, not on regular files. Sector size must be correctly set for
355 this to work. Not all systems support this.
356
357 If your system does not support direct disc access, ddrescue will warn
358 you. If the sector size is not correctly set, all reads will result in
359 errors, and no data will be rescued.
360
361 @item -D
362 @itemx --synchronous
363 Use synchronous writes for @var{outfile}. (Issue a fsync call after
364 every write). May be useful when forcing the drive to remap its bad
365 sectors.
366
367 @item -e [+]@var{n}
368 @itemx --max-errors=[+]@var{n}
369 Maximum number of error areas allowed before giving up. Defaults to
370 infinity. If @var{n} is preceded by @samp{+} the number refers to new
371 error areas found in this run, not counting those already annotated in
372 the @var{logfile}.
373
374 @item -E @var{bytes}
375 @itemx --max-error-rate=@var{bytes}
376 Maximum rate of errors allowed before giving up, in bytes per second.
377 Defaults to infinity. The rate being measured is that of actually failed
378 reads, so the rescue may finish because of this rate being exceeded even
379 if the total error size (errsize) does not change because the areas
380 being tried are already marked as errors.
381
382 @item -f
383 @itemx --force
384 Force overwrite of @var{outfile}. Needed when @var{outfile} is not a
385 regular file, but a device or partition.
386
387 @item -F @var{types}
388 @itemx --fill-mode=@var{types}
389 Fill the blocks in @var{outfile} specified as any of @var{types} in
390 @var{logfile}, with data read from @var{infile}. @var{types} contains
391 one or more of the status characters defined in the chapter Logfile
392 Structure (@pxref{Logfile structure}). See the chapter Fill mode
393 (@pxref{Fill mode}) for a complete description of the fill mode.
394
395 @item -g
396 @itemx --generate-mode
397 Generate an approximate @var{logfile} from the @var{infile} and
398 @var{outfile} of the original rescue run. Note that you must keep the
399 original offset between @samp{--input-position} and
400 @samp{--output-position} of the original rescue run. See the chapter
401 Generate mode (@pxref{Generate mode}) for a complete description of the
402 generate mode.
403
404 @item -i @var{bytes}
405 @itemx --input-position=@var{bytes}
406 Starting position in @var{infile}, in bytes. Defaults to 0. In fill mode
407 it refers to a position in the @var{infile} of the original rescue run.
408 See the chapter Fill mode (@pxref{Fill mode}) for details.
409
410 @item -I
411 @itemx --verify-input-size
412 Compare the size of @var{infile} with the size calculated from the list
413 of blocks contained in the @var{logfile}, and exit with status 1 if they
414 differ. This is not enabled by default because the size of some devices
415 can't be known in advance and because the size derived from the
416 @var{logfile} may be incomplete, for example after doing a partial
417 rescue.
418
419 @item -K @var{bytes}
420 @itemx --skip-size=@var{bytes}
421 Set the initial size to skip on the first read error or slow read. The
422 value given will be rounded to the next multiple of sector size. For
423 subsequent read errors or slow reads, ddrescue will modify the skip size
424 depending on error rate and error history. Valid values range from 64 KiB
425 to 1 GiB. Defaults to 64 KiB.
426
427 @item -l @var{entries}
428 @itemx --logfile-size=@var{entries}
429 During the splitting phase, do not grow logfile beyond this number of
430 entries. Logfile may be larger if it was larger at startup or if it
431 became larger during the copying or trimming phases. Defaults to 1000.
432 (Each entry is about 26-30 bytes in size).
433
434 @item -m @var{file}
435 @itemx --domain-logfile=@var{file}
436 Restrict the rescue domain to the blocks marked as finished in the
437 logfile @var{file}. This is useful if the destination drive fails during
438 the rescue.
439
440 @item -M
441 @itemx --retrim
442 Mark all failed blocks inside the rescue domain as non-trimmed before
443 beginning the rescue. The effect is similar to @samp{--retries=1}, but
444 the bad sectors are tried in a different order, making perhaps possible
445 to rescue some of them.
446
447 @item -n
448 @itemx --no-split
449 Skip the splitting phase. Avoids spending a lot of time trying to rescue
450 the most difficult parts of the file.
451
452 @item -o @var{bytes}
453 @itemx --output-position=@var{bytes}
454 Starting position in @var{outfile}, in bytes. Defaults to
455 @samp{--input-position}. The bytes below @var{bytes} aren't touched if
456 they exist and truncation is not requested. Else they are set to 0.
457
458 @item -p
459 @itemx --preallocate
460 Preallocate space on disc for @var{outfile}. Only space for regular
461 files can be preallocated. If preallocation succeeds, rescue will not
462 fail due to lack of free space on disc. If ddrescue can't determine the
463 size to preallocate, you may need to specify it with some combination of
464 the @samp{--input-position}, @samp{--output-position}, @samp{--size},
465 and @samp{--domain-logfile} options.
466
467 @item -q
468 @itemx --quiet
469 Quiet operation. Suppress all messages.
470
471 @item -r @var{n}
472 @itemx --retries=@var{n}
473 Exit after given number of retry passes. Defaults to 0. -1 means
474 infinity. Every bad sector is tried only one time per pass. To retry bad
475 sectors detected on a previous run, you must specify a non-zero number
476 of retries.
477
478 @item -R
479 @itemx --reverse
480 Reverse direction of copying, retrying, and the sequential part of
481 splitting, running them backwards from the end of the input file.
482
483 @item -s @var{bytes}
484 @itemx --size=@var{bytes}
485 Maximum size of the input data to be copied, in bytes. If ddrescue can't
486 determine the size of the input device, you may need to specify it with
487 this option. Note that this option specifies the size of the input data
488 to be copied, not the size of the resulting @var{outfile}. So, for
489 example, the following command creates an @var{outfile} 300 bytes long,
490 but only writes data on the last 200 bytes:
491
492 @example
493 ddrescue -i 100 -s 200 infile outfile logfile
494 @end example
495
496 @item -S
497 @itemx --sparse
498 Use sparse writes for @var{outfile}. (The blocks of zeros are not
499 actually allocated on disc). May save a lot of disc space in some cases.
500 Not all systems support this. Only regular files can be sparse.
501
502 @item -t
503 @itemx --truncate
504 Truncate @var{outfile} to zero size before writing to it. Only works for
505 regular files, not for drives or partitions.
506
507 @item -T @var{interval}
508 @itemx --timeout=@var{interval}
509 Maximum time since last successful read allowed before giving up.
510 Defaults to infinity. @var{interval} is a rational number (like 1.5 or
511 1/2) optionally followed by one of @samp{s}, @samp{m}, @samp{h} or
512 @samp{d}, meaning seconds, minutes, hours and days respectively. If no
513 unit is specified, it defaults to seconds.
514
515 @item -v
516 @itemx --verbose
517 Verbose mode. Further -v's (up to 4) increase the verbosity level.
518
519 @item -w
520 @itemx --ignore-write-errors
521 Make fill mode ignore write errors. This is useful to avoid ddrescue
522 exiting because of new errors developing while wiping the good sectors
523 of a failing drive. Fill mode normally writes to @var{outfile} one
524 cluster at a time. With this option, after the first write error is
525 found in an area, the rest of that area is filled sector by sector.
526
527 @item -x @var{bytes}
528 @itemx --extend-outfile=@var{bytes}
529 Extend the size of @var{outfile} to make it at least @var{bytes} long.
530 If the size of @var{outfile} is already equal or longer than @var{bytes}
531 then this option does nothing. Use this option to guarantee a minimum
532 size for @var{outfile}. Only regular files can be extended.
533
534 @end table
535
536 @sp 1
537 Numbers given as arguments to options (positions, sizes, retries, etc)
538 may be followed by a multiplier and an optional @samp{B} for "byte".
539
540 Table of SI and binary prefixes (unit multipliers):
541
542 @multitable {Prefix} {kilobyte (10^3 = 1000)} {|} {Prefix} {kibibyte (2^10 = 1024)}
543 @item Prefix @tab Value @tab | @tab Prefix @tab Value
544 @item @tab @tab | @tab s @tab sectors
545 @item k @tab kilobyte (10^3 = 1000) @tab | @tab Ki @tab kibibyte (2^10 = 1024)
546 @item M @tab megabyte (10^6) @tab | @tab Mi @tab mebibyte (2^20)
547 @item G @tab gigabyte (10^9) @tab | @tab Gi @tab gibibyte (2^30)
548 @item T @tab terabyte (10^12) @tab | @tab Ti @tab tebibyte (2^40)
549 @item P @tab petabyte (10^15) @tab | @tab Pi @tab pebibyte (2^50)
550 @item E @tab exabyte (10^18) @tab | @tab Ei @tab exbibyte (2^60)
551 @item Z @tab zettabyte (10^21) @tab | @tab Zi @tab zebibyte (2^70)
552 @item Y @tab yottabyte (10^24) @tab | @tab Yi @tab yobibyte (2^80)
553 @end multitable
554
555 @sp 1
556 Exit status: 0 for a normal exit, 1 for environmental problems (file not
557 found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
558 invalid input file, 3 for an internal consistency error (eg, bug) which
559 caused ddrescue to panic.
560
561
562 @node Logfile structure
563 @chapter Logfile structure
564 @cindex logfile structure
565
566 The logfile is a text file easy to read and edit. It is formed by three
567 parts, the heading comments, the status line, and the list of data
568 blocks. Any line beginning with @samp{#} is a comment line.
569
570 NOTE: Logfiles generated by a version of ddrescue prior to 1.6 lack the
571 status line. If you want to use an old logfile with ddrescue 1.6 or
572 later, you will have to insert a line like @samp{0 +} at the beginning
573 of the logfile.
574
575 The heading comments contain the version of ddrescue and the command
576 line used to create the logfile. They are intended as information for
577 the user.
578
579 The first non-comment line is the status line. It contains a
580 non-negative integer and a status character. The integer is the position
581 being tried in the input file. The status character is one of these:
582
583 @multitable {Character} {generating approximate logfile}
584 @item Character @tab Meaning
585 @item '?' @tab copying non-tried blocks
586 @item '*' @tab trimming non-trimmed blocks
587 @item '/' @tab splitting non-split blocks
588 @item '-' @tab retrying bad sectors
589 @item 'F' @tab filling specified blocks
590 @item 'G' @tab generating approximate logfile
591 @item '+' @tab finished
592 @end multitable
593
594 The blocks in the list of data blocks must be contiguous and
595 non-overlapping.
596
597 Every line in the list of data blocks describes a block of data. It
598 contains 2 non-negative integers and a status character. The first
599 integer is the starting position of the block in the input file, the
600 second integer is the size (in bytes) of the block. The status character
601 is one of these:
602
603 @multitable {Character} {failed block bad-sector(s)}
604 @item Character @tab Meaning
605 @item '?' @tab non-tried block
606 @item '*' @tab failed block non-trimmed
607 @item '/' @tab failed block non-split
608 @item '-' @tab failed block bad-sector(s)
609 @item '+' @tab finished block
610 @end multitable
611
612 @noindent
613 And here is an example logfile:
614
615 @noindent
616 # Rescue Logfile. Created by GNU ddrescue version @value{VERSION}@*
617 # Command line: ddrescue /dev/fd0 fdimage logfile@*
618 # current_pos current_status@*
619 0x00120000 ?@*
620 # pos size status@*
621 @multitable {0x00000000} {0x00000000} {status}
622 @item 0x00000000 @tab 0x00117000 @tab +
623 @item 0x00117000 @tab 0x00000200 @tab -
624 @item 0x00117200 @tab 0x00001000 @tab /
625 @item 0x00118200 @tab 0x00007E00 @tab *
626 @item 0x00120000 @tab 0x00048000 @tab ?
627 @end multitable
628
629 If you edit the file, you may use decimal, hexadecimal or octal values,
630 using the same syntax that integer constants in C++.
631
632
633 @node Examples
634 @chapter A small tutorial with examples
635 @cindex examples
636
637 This tutorial is for those already able to use the dd command. If you
638 don't know what dd is, better search the net for some introductory
639 material about dd and GNU ddrescue first.
640
641 A failing drive tends to develop more and more errors as time passes.
642 Because of this, you should rescue the data from a drive as soon as you
643 notice the first error. Be diligent because every time a physically
644 damaged drive powers up and is able to output some data, it may be the
645 very last time that it ever will.
646
647 You should make a copy of the failing drive with ddrescue, and then try
648 to repair the copy. If your data is really important, use the first copy
649 as a master for a second copy, and try to repair the second copy. If
650 something goes wrong, you have the master intact to try again.
651
652 If you are trying to rescue a whole partition, first repair the copy
653 with e2fsck or some other tool appropiate for the type of partition you
654 are trying to rescue, then mount the repaired copy somewhere and try to
655 recover the files in it.
656
657 If the drive is so damaged that the file system in the rescued partition
658 can't be repaired or mounted, you will have to browse the rescued data
659 with an hex editor and extract the desired parts by hand or use a file
660 recovery tool like photorec.
661
662 If the partition table is damaged, you may try to rescue the whole disc,
663 then try to repair the partition table and the partitions on the copy.
664
665 If the damaged drive is not listed in /dev, then you cannot rescue it.
666 At least not with ddrescue.
667
668 @sp 1
669 @noindent
670 Example 1: Rescue a whole disc with two ext2 partitions in /dev/hda to
671 /dev/hdb.@*
672 Note: you do not need to partition /dev/hdb beforehand, but if the
673 partition table on /dev/hda is damaged, you'll need to recreate it
674 somehow on /dev/hdb.
675
676 @example
677 ddrescue -f -n /dev/hda /dev/hdb logfile
678 ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
679 fdisk /dev/hdb
680 e2fsck -v -f /dev/hdb1
681 e2fsck -v -f /dev/hdb2
682 @end example
683
684 @sp 1
685 @noindent
686 Example 2: Rescue an ext2 partition in /dev/hda2 to /dev/hdb2.@*
687 Note: you need to create the hdb2 partition with fdisk first. hdb2
688 should be of appropiate type and size.
689
690 @example
691 ddrescue -f -n /dev/hda2 /dev/hdb2 logfile
692 ddrescue -d -f -r3 /dev/hda2 /dev/hdb2 logfile
693 e2fsck -v -f /dev/hdb2
694 mount -t ext2 -o ro /dev/hdb2 /mnt
695 (read rescued files from /mnt)
696 @end example
697
698 @sp 1
699 @noindent
700 Example 3: Rescue a CD-ROM in /dev/cdrom.
701
702 @example
703 ddrescue -n -b2048 /dev/cdrom cdimage logfile
704 ddrescue -d -b2048 /dev/cdrom cdimage logfile
705 (write cdimage to a blank CD-ROM)
706 @end example
707
708 @sp 1
709 @noindent
710 Example 4: Rescue a CD-ROM in /dev/cdrom from two copies.
711
712 @example
713 ddrescue -n -b2048 /dev/cdrom cdimage logfile
714 ddrescue -d -b2048 /dev/cdrom cdimage logfile
715 (insert second copy in the CD drive)
716 ddrescue -d -r1 -b2048 /dev/cdrom cdimage logfile
717 (write cdimage to a blank CD-ROM)
718 @end example
719
720 @sp 1
721 @anchor{lziprecover-example}
722 @noindent
723 Example 5: Rescue a lzip compressed backup from two copies on CD-ROM
724 with error-checked merging of copies
725 @ifnothtml
726 (@xref{Top,lziprecover manual,,lziprecover},
727 @end ifnothtml
728 @ifhtml
729 (See the
730 @uref{http://www.nongnu.org/lzip/manual/lziprecover_manual.html,,lziprecover manual}
731 @end ifhtml
732 for details about lziprecover).
733
734 @example
735 ddrescue -b2048 /dev/cdrom cdimage1 logfile1
736 mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage
737 cp /mnt/cdimage/backup.tar.lz rescued1.tar.lz
738 umount /mnt/cdimage
739 (insert second copy in the CD drive)
740 ddrescue -b2048 /dev/cdrom cdimage2 logfile2
741 mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage
742 cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz
743 umount /mnt/cdimage
744 lziprecover -m -v -o backup.tar.lz rescued1.tar.lz rescued2.tar.lz
745 @end example
746
747 @sp 1
748 @noindent
749 Example 6: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
750 freezes up at position 12345678.
751
752 @example
753 ddrescue -f /dev/hda /dev/hdb logfile <-- /dev/hda freezes here
754 (restart /dev/hda or reboot computer)
755 (restart copy at a safe distance from the troubled sector)
756 ddrescue -f -i 12350000 /dev/hda /dev/hdb logfile
757 (copy backwards down to the troubled sector)
758 ddrescue -f -R /dev/hda /dev/hdb logfile
759 @end example
760
761 @sp 1
762 @noindent
763 Example 7: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hdb
764 fails and you have to rescue data to a third drive, /dev/hdc.
765
766 @example
767 ddrescue -f -n /dev/hda /dev/hdb logfile1 <-- /dev/hdb fails here
768 ddrescue -f -m logfile1 /dev/hdb /dev/hdc logfile2
769 ddrescue -f -n /dev/hda /dev/hdc logfile2
770 ddrescue -d -f -r3 /dev/hda /dev/hdc logfile2
771 @end example
772
773 @sp 1
774 @noindent
775 Example 8: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
776 stops responding and disappears from /dev.
777
778 @example
779 ddrescue -f -n /dev/hda /dev/hdb logfile <-- /dev/hda fails here
780 (restart /dev/hda or reboot computer as many times as needed)
781 ddrescue -f -n -A /dev/hda /dev/hdb logfile
782 ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
783 @end example
784
785
786 @node Direct disc access
787 @chapter Direct disc access
788 @cindex direct disc access
789 @cindex raw devices
790
791 If you notice that the positions and sizes in the log file are ALWAYS
792 multiples of the sector size, maybe your kernel is caching the disc
793 accesses and grouping them. In this case you may want to use direct disc
794 access or a raw device to bypass the kernel cache and rescue more of
795 your data.
796
797 NOTE! Sector size must be correctly set with the @samp{--sector-size}
798 option for this to work. Only whole sectors can be read; both
799 @samp{--input-position} and @samp{--size} must be a multiple of sector
800 size.
801
802 Try the @samp{--direct} option first. If direct disc access is not
803 available in your system, try raw devices. Read your system
804 documentation to find how to bind a raw device to a regular block
805 device. Some OSs provide raw access through special device names, like
806 /dev/rdisk.
807
808 Ddrescue aligns its I/O buffer to the sector size so that it can be used
809 for direct disc access or to read from raw devices. For efficiency
810 reasons, also aligns it to the memory page size if page size is a
811 multiple of sector size. On some systems, ddrescue can't determine the
812 size of a raw device, so an explicit @samp{--size} or
813 @samp{--complete-only} option may be needed.
814
815 Using direct disc access, or reading from a raw device, may be slower or
816 faster than normal cached reading depending on your OS and hardware. In
817 case it is slower you may want to make a first pass using normal cached
818 reads and use direct disc access, or a raw device, only to recover the
819 good sectors inside the failed blocks.
820
821 @sp 1
822 @noindent
823 Example 1: using direct disc access.
824
825 @example
826 ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
827 ddrescue -d -f -r3 /dev/hdb1 /dev/hdc1 logfile
828 e2fsck -v -f /dev/hdc1
829 mount -t ext2 -o ro /dev/hdc1 /mnt
830 @end example
831
832 @sp 1
833 @noindent
834 Example 2: using a raw device.
835
836 @example
837 raw /dev/raw/raw1 /dev/hdb1
838 ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
839 ddrescue -C -f -r3 /dev/raw/raw1 /dev/hdc1 logfile
840 raw /dev/raw/raw1 0 0
841 e2fsck -v -f /dev/hdc1
842 mount -t ext2 -o ro /dev/hdc1 /mnt
843 @end example
844
845
846 @node Fill mode
847 @chapter Fill mode
848 @cindex fill Mode
849
850 When ddrescue is invoked with the @samp{--fill-mode} option it operates
851 in "fill mode", which is different from the default "rescue mode". That
852 is, if you use the @samp{--fill-mode} option, ddrescue does not rescue
853 anything. It only fills with data read from the input file the blocks of
854 the output file whose status character from the logfile coincides with
855 one of the type characters specified as argument to the
856 @samp{--fill-mode} option.
857
858 In fill mode the input file may have any size. If it is too small, the
859 data will be duplicated as many times as necessary to fill the input
860 buffer. If it is too big, only the data needed to fill the input buffer
861 will be read. Then the same data will be written to every cluster or
862 sector to be filled.
863
864 Note that in fill mode the input file is always read from position 0. If
865 you specify a @samp{--input-position}, it refers to the original input
866 file from which the logfile was built, and is only used to calculate the
867 offset between input and output positions.
868
869 Note also that when filling the input file of the original rescue run
870 you should set @samp{--input-position} and @samp{--output-position} to
871 identical values, whereas when filling the output file of the original
872 rescue run you should keep the original offset between
873 @samp{--input-position} and @samp{--output-position}.
874
875 The @samp{--fill-mode} option implies the @samp{--complete-only} option.
876
877 In fill mode the logfile is updated to allow resumability when
878 interrupted or in case of a crash, but as nothing is being rescued the
879 logfile is not destroyed. The status line is the only part of the
880 logfile that is modified.
881
882 @sp 1
883 @noindent
884 The fill mode has a number of uses. See the following examples:
885
886 @noindent
887 Example 1: Mark parts of the rescued copy to allow finding them when
888 examined in an hex editor. For example, the following command line fills
889 all blocks marked as @samp{-} (bad-sector) with copies of the string
890 @w{@samp{BAD SECTOR }}:
891
892 @example
893 printf "BAD SECTOR " > tmpfile
894 ddrescue --fill-mode=- tmpfile outfile logfile
895 @end example
896
897 @noindent
898 Example 2: Wipe only the good sectors, leaving the bad sectors alone.
899 This way, the drive will still test bad (i.e., with unreadable sectors).
900 This is the fastest way of wiping a failing drive, and is specially
901 useful when sending the drive back to the manufacturer for warranty
902 replacement.
903
904 @example
905 ddrescue --fill-mode=+ --force /dev/zero bad_drive logfile
906 @end example
907
908 @noindent
909 Example 3: Force the drive to remap the bad sectors, making it usable
910 again. If the drive has only a few bad sectors, and they are not caused
911 by drive age, you can probably just rewrite those sectors, and the drive
912 will reallocate them automatically to new "spare" sectors that it keeps
913 for just this purpose. WARNING! This may not work on your drive.
914
915 @example
916 ddrescue --fill-mode=- --force --synchronous /dev/zero bad_drive logfile
917 @end example
918
919 @sp 1
920 @noindent
921 Fill mode can also help you to figure out, independently of the file
922 system used, what files are partially or entirely in the bad areas of
923 the disc. Just follow these steps:
924
925 1) Copy the damaged drive with ddrescue until finished. Do not use
926 sparse writes. This yields a logfile with only finished (@samp{+}) and
927 bad-sector (@samp{-}) blocks.
928
929 2) Fill the bad-sector blocks of the copied drive or image file with a
930 string not present in any file, for example "DEADBEEF".
931
932 3) Mount the copied drive (or the image file, via loopback device).
933
934 4) Grep for the fill string in all the files. Those files containing the
935 string reside (at least partially) in damaged disc areas.
936
937 5) Unmount the copied drive or image file.
938
939 6) Optionally fill the bad-sector blocks of the copied drive or image
940 file with zeros to restore the disc image.
941
942 @noindent
943 Example 4: Figure out what files are in the bad areas of the disc.
944
945 @example
946 ddrescue -b2048 /dev/cdrom cdimage logfile
947 printf "DEADBEEF" > tmpfile
948 ddrescue --fill-mode=- tmpfile cdimage logfile
949 rm tmpfile
950 mount -t iso9660 -o loop,ro cdimage /mnt/cdimage
951 find /mnt/cdimage -type f -exec grep "DEADBEEF" '@{@}' ';'
952 umount /mnt/cdimage
953 ddrescue --fill-mode=- /dev/zero cdimage logfile
954 @end example
955
956
957 @node Generate mode
958 @chapter Generate mode
959 @cindex generate Mode
960
961 NOTE: When ddrescue is invoked with the @samp{--generate-mode} option it
962 operates in "generate mode", which is different from the default "rescue
963 mode". That is, if you use the @samp{--generate-mode} option, ddrescue
964 does not rescue anything. It only tries to generate a logfile for later
965 use.
966
967 So you didn't read the tutorial and started ddrescue without a logfile.
968 Now, two days later, your computer crashed and you can't know how much
969 data ddrescue managed to save. And even worse, you can't resume the
970 rescue; you have to restart it from the very beginning.
971
972 Or maybe you started copying a drive with @w{@code{dd
973 conv=noerror,sync}} and are now in the same situation described above.
974 In this case, note that you can't use a copy made by dd unless it was
975 invoked with the @samp{sync} conversion argument.
976
977 Don't despair (yet). Ddrescue can in some cases generate an approximate
978 logfile, from the input file and the (partial) copy, that is almost as
979 good as an exact logfile. It makes this by simply assuming that sectors
980 containing all zeros were not rescued.
981
982 However, if the destination of the copy was a drive or a partition, (or
983 an existing regular file and truncation was not requested), most
984 probably you will need to restart ddrescue from the very beginning.
985 (This time with a logfile, of course). The reason is that old data may
986 be present in the drive that have not been overwritten yet, and may be
987 thus non-tried but non-zero.
988
989 For example, if you first tried one of these commands:
990 @example
991 ddrescue infile outfile
992 or
993 dd if=infile of=outfile conv=noerror,sync
994 @end example
995
996 then you can generate an approximate logfile with this command:
997 @example
998 ddrescue --generate-mode infile outfile logfile
999 @end example
1000
1001 @noindent
1002 Note that you must keep the original offset between
1003 @samp{--input-position} and @samp{--output-position} of the original
1004 rescue run.
1005
1006
1007 @node Ddrescuelog
1008 @chapter Ddrescuelog
1009 @cindex ddrescuelog
1010
1011 Ddrescuelog is a tool that manipulates ddrescue logfiles, shows logfile
1012 contents, converts logfiles to/from other formats, compares logfiles,
1013 tests rescue status, and can delete a logfile if the rescue is done.
1014 Ddrescuelog operations can be restricted to one or several parts of the
1015 logfile if the domain setting options are used.
1016
1017 Here are some examples of how to use ddrescuelog, alone or in
1018 combination with other tools.
1019
1020 @sp 1
1021 @noindent
1022 Example 1: Delete the logfile if the rescue is finished (all data is
1023 recovered without errors left).
1024
1025 @example
1026 ddrescue -f /dev/hda /dev/hdb logfile
1027 ddrescuelog -d logfile
1028 @end example
1029
1030 @sp 1
1031 @noindent
1032 Example 2: Rescue two ext2 partitions in /dev/hda to
1033 /dev/hdb and repair the file systems using badblock lists generated with
1034 ddrescuelog. File system block size is 4096.@*
1035 Note: you do need to partition /dev/hdb beforehand.
1036
1037 @example
1038 fdisk /dev/hdb <-- partition /deb/hdb
1039 ddrescue -f /dev/hda1 /dev/hdb1 logfile1
1040 ddrescue -f /dev/hda2 /dev/hdb2 logfile2
1041 ddrescuelog -l- -b4096 logfile1 > badblocks1
1042 ddrescuelog -l- -b4096 logfile2 > badblocks2
1043 e2fsck -v -f -L badblocks1 /dev/hdb1
1044 e2fsck -v -f -L badblocks2 /dev/hdb2
1045 @end example
1046
1047 @sp 1
1048 @noindent
1049 Example 3: Rescue a whole disc with two ext2 partitions in /dev/hda to
1050 /dev/hdb and repair the file systems using badblock lists generated with
1051 ddrescuelog. Disc sector size is 512, file system block size is 4096.
1052 Arguments to options @samp{-i} and @samp{-s} are the starting positions
1053 and sizes of the partitions being rescued.@*
1054 Note: you do not need to partition /dev/hdb beforehand, but if the
1055 partition table on /dev/hda is damaged, you'll need to recreate it
1056 somehow on /dev/hdb.
1057
1058 @example
1059 ddrescue -f /dev/hda /dev/hdb logfile
1060 fdisk /dev/hdb <-- get partition sizes
1061 ddrescuelog -l- -b512 -i63b -o0 -s9767457b -b4096 logfile > badblocks1
1062 ddrescuelog -l- -b512 -i9767520b -o0 -s128520b -b4096 logfile > badblocks2
1063 e2fsck -v -f -L badblocks1 /dev/hdb1
1064 e2fsck -v -f -L badblocks2 /dev/hdb2
1065 @end example
1066
1067
1068 @node Invoking ddrescuelog
1069 @chapter Invoking ddrescuelog
1070 @cindex invoking ddrescuelog
1071
1072 The format for running ddrescuelog is:
1073
1074 @example
1075 ddrescuelog [@var{options}] @var{logfile}
1076 @end example
1077
1078 Ddrescuelog supports the following options:
1079
1080 @table @samp
1081 @item -h
1082 @itemx --help
1083 Print an informative help message describing the options and exit.
1084
1085 @item -V
1086 @itemx --version
1087 Print the version number of ddrescuelog on the standard output and exit.
1088
1089 @item -a @var{old_types},@var{new_types}
1090 @itemx --change-types=@var{old_types},@var{new_types}
1091 Change the status of every block in the rescue domain from one type in
1092 @var{old_types} to the corresponding type in @var{new_types}, much like
1093 the @samp{tr} command does, and write the resulting logfile to standard
1094 output. @var{old_types} and @var{new_types} are strings of block status
1095 characters as defined in the chapter Logfile structure (@pxref{Logfile
1096 structure}). Blocks whose status is not in @var{old_types} are left
1097 unchanged. If @var{new_types} is shorter than @var{old_types} the last
1098 type of @var{new_types} is repeated as many times as necessary.
1099
1100 @item -b @var{bytes}
1101 @itemx --block-size=@var{bytes}
1102 Block size used by ddrescuelog. Depending on the requested operation it
1103 may be the sector size of the input device, the block size of the
1104 rescued file system, etc. Defaults to 512.
1105
1106 @item -c[@var{type1}@var{type2}]
1107 @itemx --create-logfile[=@var{type1}@var{type2}]
1108 Create a logfile from a list of block numbers read from standard input.
1109 Only blocks included in the rescue domain will be added to @var{logfile}.
1110
1111 @var{type1} and @var{type2} are block status characters as defined in
1112 the chapter Logfile structure (@pxref{Logfile structure}). @var{type1}
1113 sets the type for blocks included in the list, while @var{type2} sets
1114 the type for the rest of the logfile. If not specified, @var{type1}
1115 defaults to @samp{+} and @var{type2} defaults to @samp{-}.
1116
1117 @item -d
1118 @itemx --delete-if-done
1119 Delete the given @var{logfile} if all the blocks in the rescue domain
1120 have been successfuly recovered. The exit status is 0 if @var{logfile}
1121 could be deleted, 1 otherwise.
1122
1123 @item -D
1124 @itemx --done-status
1125 Test if all the blocks in the rescue domain have been successfuly
1126 recovered. The exit status is 0 if all tested blocks are finished, 1
1127 otherwise.
1128
1129 @item -f
1130 @itemx --force
1131 Force overwrite of @var{logfile}.
1132
1133 @item -i @var{bytes}
1134 @itemx --input-position=@var{bytes}
1135 Starting position of the rescue domain, in bytes. Defaults to 0. It
1136 refers to a position in the original input file.
1137
1138 @item -l @var{types}
1139 @itemx --list-blocks=@var{types}
1140 Print on standard output the block numbers of the blocks specified as
1141 any of @var{types} in @var{logfile} and included in the rescue domain.
1142 @var{types} contains one or more of the block status characters defined
1143 in the chapter Logfile structure (@pxref{Logfile structure}).
1144
1145 The list format is one block number per line in decimal, like the output
1146 of the badblocks program, so that it can be used as input for e2fsck or
1147 other similar filesystem repairing tool.
1148
1149 @item -m @var{file}
1150 @itemx --domain-logfile=@var{file}
1151 Restrict the rescue domain to the blocks marked as finished in the
1152 logfile @var{file}.
1153
1154 @item -n
1155 @itemx --invert-logfile
1156 Invert the types of the blocks in @var{logfile} which are included in
1157 the rescue domain, and write the resulting logfile to standard output.
1158 Finished blocks (@samp{+}) are changed to bad-sector (@samp{-}), all
1159 other types are changed to finished. @samp{--invert-logfile} is
1160 equivalent to @samp{--change-types=?*/-+,++++-}
1161
1162 @item -o @var{bytes}
1163 @itemx --output-position=@var{bytes}
1164 Starting position in output file, in bytes. Is used by the
1165 @samp{--list-blocks} option. Defaults to @samp{--input-position}.
1166
1167 @item -p @var{file}
1168 @itemx --compare-logfile=@var{file}
1169 Compare the types of the blocks included in the rescue domain. The exit
1170 status is 0 if all tested blocks are the same in both files, 1
1171 otherwise.
1172
1173 @item -q
1174 @itemx --quiet
1175 Quiet operation. Suppress all messages.
1176
1177 @item -s @var{bytes}
1178 @itemx --size=@var{bytes}
1179 Maximum size of the rescue domain, in bytes. It refers to a size in the
1180 original input file.
1181
1182 @item -t
1183 @itemx --show-status
1184 Print a summary of @var{logfile} contents on the standard output. The
1185 summary can be restricted to one or several parts of @var{logfile} if
1186 the domain setting options are used.
1187
1188 @item -v
1189 @itemx --verbose
1190 Verbose mode. Further -v's (up to 4) increase the verbosity level.
1191
1192 @item -x @var{file}
1193 @itemx --xor-logfile=@var{file}
1194 Perform a logical XOR (exclusive OR) operation between the finished
1195 blocks in @var{file} and those in @var{logfile}, and write the resulting
1196 logfile to standard output. In other words, in the resulting logfile a
1197 block is only shown as finished if it was finished in either of the two
1198 input logfiles but not in both.
1199
1200 @item -y @var{file}
1201 @itemx --and-logfile=@var{file}
1202 Perform a logical AND operation between the finished blocks in
1203 @var{file} and those in @var{logfile}, and write the resulting logfile
1204 to standard output. In other words, in the resulting logfile a block is
1205 only shown as finished if it was finished in both input logfiles.
1206
1207 @item -z @var{file}
1208 @itemx --or-logfile=@var{file}
1209 Perform a logical OR operation between the finished blocks in @var{file}
1210 and those in @var{logfile}, and write the resulting logfile to standard
1211 output. In other words, in the resulting logfile a block is shown as
1212 finished if it was finished in either of the two input logfiles.
1213
1214 @end table
1215
1216 Exit status: 0 for a normal exit, 1 for environmental problems (file not
1217 found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
1218 invalid input file, 3 for an internal consistency error (eg, bug) which
1219 caused ddrescuelog to panic.
1220
1221
1222 @node Problems
1223 @chapter Reporting Bugs
1224 @cindex bugs
1225 @cindex getting help
1226
1227 There are probably bugs in ddrescue. There are certainly errors and
1228 omissions in this manual. If you report them, they will get fixed. If
1229 you don't, no one will ever know about them and they will remain unfixed
1230 for all eternity, if not longer.
1231
1232 If you find a bug in GNU ddrescue, please send electronic mail to
1233 @email{bug-ddrescue@@gnu.org}. Include the version number, which you can
1234 find by running @w{@samp{ddrescue --version}}.
1235
1236
1237 @node Concept index
1238 @unnumbered Concept index
1239
1240 @printindex cp
1241
1242 @bye
00 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
1 .TH DDRESCUELOG "1" "July 2013" "ddrescuelog 1.17" "User Commands"
1 .TH DDRESCUELOG "1" "June 2014" "ddrescuelog 1.18.1" "User Commands"
22 .SH NAME
33 ddrescuelog \- tool for ddrescue logfiles
44 .SH SYNOPSIS
1717 output version information and exit
1818 .TP
1919 \fB\-a\fR, \fB\-\-change\-types=\fR<ot>,<nt>
20 change the block types of a logfile
20 change the block types of logfile
2121 .TP
2222 \fB\-b\fR, \fB\-\-block\-size=\fR<bytes>
2323 block size in bytes [default 512]
2424 .TP
25 \fB\-B\fR, \fB\-\-binary\-prefixes\fR
26 show binary multipliers in numbers [SI]
27 .TP
2528 \fB\-c\fR, \fB\-\-create\-logfile[=\fR<tt>]
2629 create logfile from list of blocks [+\-]
30 .TP
31 \fB\-C\fR, \fB\-\-complete\-logfile[=\fR<t>]
32 complete logfile adding blocks of type t [?]
2733 .TP
2834 \fB\-d\fR, \fB\-\-delete\-if\-done\fR
2935 delete the logfile if rescue is finished
4046 \fB\-l\fR, \fB\-\-list\-blocks=\fR<types>
4147 print block numbers of given types (?*/\-+)
4248 .TP
49 \fB\-L\fR, \fB\-\-loose\-domain\fR
50 accept an incomplete domain logfile
51 .TP
4352 \fB\-m\fR, \fB\-\-domain\-logfile=\fR<file>
4453 restrict domain to finished blocks in file
4554 .TP
4655 \fB\-n\fR, \fB\-\-invert\-logfile\fR
47 invert block types (finished <\-> others)
56 invert block types (finished <\-\-> others)
4857 .TP
4958 \fB\-o\fR, \fB\-\-output\-position=\fR<bytes>
5059 starting position in output file [ipos]
5160 .TP
5261 \fB\-p\fR, \fB\-\-compare\-logfile=\fR<file>
5362 compare block types in domain of both files
63 .TP
64 \fB\-P\fR, \fB\-\-compare\-as\-domain=\fR<file>
65 like \fB\-p\fR but compare finished blocks only
5466 .TP
5567 \fB\-q\fR, \fB\-\-quiet\fR
5668 suppress all messages
7385 \fB\-z\fR, \fB\-\-or\-logfile=\fR<file>
7486 OR the finished blocks in file with logfile
7587 .PP
76 Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,
77 Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
88 Numbers may be in decimal, hexadecimal or octal, and may be followed by a
89 multiplier: s = sectors, k = 1000, Ki = 1024, M = 10^6, Mi = 2^20, etc...
7890 .PP
7991 Exit status: 0 for a normal exit, 1 for environmental problems (file
8092 not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
8799 .br
88100 General help using GNU software: http://www.gnu.org/gethelp
89101 .SH COPYRIGHT
90 Copyright \(co 2013 Antonio Diaz Diaz.
102 Copyright \(co 2014 Antonio Diaz Diaz.
91103 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
92104 .br
93105 This is free software: you are free to change and redistribute it.
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1717
1818 #define _FILE_OFFSET_BITS 64
1919
20 #include <algorithm>
2021 #include <climits>
2122 #include <cstdio>
23 #include <cstring>
24 #include <ctime>
2225 #include <string>
2326 #include <vector>
2427 #include <stdint.h>
3134 //
3235 int Fillbook::fill_areas( const std::string & filltypes )
3336 {
37 const char * const msg = "Filling blocks...";
3438 bool first_post = true;
3539
3640 for( int index = 0; index < sblocks(); ++index )
4246 Block b( sb.pos(), softbs() ); // fill the area a softbs at a time
4347 if( sb.includes( current_pos() ) ) b.pos( current_pos() );
4448 if( b.end() > sb.end() ) b.crop( sb );
45 current_status( filling );
49 current_status( filling, msg );
4650 while( b.size() > 0 )
4751 {
4852 current_pos( b.pos() );
4953 if( verbosity >= 0 )
50 { show_status( b.pos(), first_post ); first_post = false; }
54 { show_status( b.pos(), msg, first_post ); first_post = false; }
5155 if( interrupted() ) return -1;
5256 const int retval = fill_block( b );
5357 if( retval ) // write error
6367 ++filled_areas; --remaining_areas;
6468 }
6569 return 0;
70 }
71
72
73 void Fillbook::show_status( const long long ipos, const char * const msg,
74 bool force )
75 {
76 const char * const up = "\x1b[A";
77 if( t0 == 0 )
78 {
79 t0 = t1 = initial_time();
80 first_size = last_size = filled_size;
81 force = true;
82 std::printf( "\n\n\n" );
83 }
84
85 if( ipos >= 0 ) last_ipos = ipos;
86 const long t2 = std::time( 0 );
87 if( t2 > t1 || force )
88 {
89 if( t2 > t1 )
90 {
91 a_rate = ( filled_size - first_size ) / ( t2 - t0 );
92 c_rate = ( filled_size - last_size ) / ( t2 - t1 );
93 t1 = t2;
94 last_size = filled_size;
95 }
96 std::printf( "\r%s%s%s", up, up, up );
97 std::printf( "filled size: %10sB, filled areas: %6u, current rate: %9sB/s\n",
98 format_num( filled_size ), filled_areas,
99 format_num( c_rate, 99999 ) );
100 std::printf( "remain size: %10sB, remain areas: %6u, average rate: %9sB/s\n",
101 format_num( remaining_size ), remaining_areas,
102 format_num( a_rate, 99999 ) );
103 std::printf( "current pos: %10sB, run time: %9s\n",
104 format_num( last_ipos + offset() ), format_time( t1 - t0 ) );
105 if( msg && msg[0] )
106 {
107 const int len = std::strlen( msg ); std::printf( "\r%s", msg );
108 for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
109 oldlen = len;
110 }
111 std::fflush( stdout );
112 }
113 else if( t2 < t1 ) // clock jumped back
114 {
115 t0 -= std::min( t0, t1 - t2 );
116 t1 = t2;
117 }
66118 }
67119
68120
96148 if( logfile_exists() )
97149 {
98150 std::printf( "Initial status (read from logfile)\n" );
99 std::printf( "filled size: %10sB,", format_num( filled_size ) );
100 std::printf( " filled areas: %7u\n", filled_areas );
101 std::printf( "remaining size: %10sB,", format_num( remaining_size ) );
102 std::printf( " remaining areas: %7u\n", remaining_areas );
151 std::printf( "filled size: %10sB, filled areas: %7u\n",
152 format_num( filled_size ), filled_areas );
153 std::printf( "remaining size: %10sB, remaining areas: %7u\n",
154 format_num( remaining_size ), remaining_areas );
103155 std::printf( "Current status\n" );
104156 }
105157 }
106158 int retval = fill_areas( filltypes );
159 const bool signaled = ( retval == -1 );
160 if( signaled ) retval = 0;
107161 if( verbosity >= 0 )
108162 {
109 show_status( -1, true );
110 if( retval == 0 ) std::printf( "Finished" );
111 else if( retval == -2 ) std::printf( "\nLogfile error" );
112 else if( retval < 0 ) std::printf( "\nInterrupted by user" );
163 show_status( -1, ( retval || signaled ) ? 0 : "Finished", true );
164 if( retval == -2 ) std::printf( "\nLogfile error" );
165 else if( signaled ) std::printf( "\nInterrupted by user" );
113166 std::fputc( '\n', stdout );
114167 }
115168 if( retval == -2 ) retval = 1; // logfile error
116169 else
117170 {
118 if( retval == 0 ) current_status( finished );
119 else if( retval < 0 ) retval = 0; // interrupted by user
171 if( retval == 0 && !signaled ) current_status( finished );
120172 compact_sblock_vector();
121173 if( !update_logfile( odes_, true ) && retval == 0 ) retval = 1;
122174 }
123175 if( final_msg() ) show_error( final_msg(), final_errno() );
124 return retval;
176 if( retval ) return retval; // errors have priority over signals
177 if( signaled ) return signaled_exit();
178 return 0;
125179 }
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1717
1818 #define _FILE_OFFSET_BITS 64
1919
20 #include <algorithm>
2021 #include <cerrno>
2122 #include <climits>
2223 #include <cstdio>
2324 #include <cstring>
25 #include <ctime>
2426 #include <string>
2527 #include <vector>
2628 #include <stdint.h>
3436 //
3537 int Genbook::check_all()
3638 {
37 long long pos = ( ( offset() >= 0 ) ? 0 : -offset() );
39 const char * const msg = "Generating logfile...";
40 long long pos = ( offset() >= 0 ) ? 0 : -offset();
3841 if( current_status() == generating && domain().includes( current_pos() ) &&
3942 ( offset() >= 0 || current_pos() >= -offset() ) )
4043 pos = current_pos();
4346 while( pos >= 0 )
4447 {
4548 Block b( pos, softbs() );
46 find_chunk( b, Sblock::non_tried );
49 find_chunk( b, Sblock::non_tried, domain(), hardbs() );
4750 if( b.size() <= 0 ) break;
4851 pos = b.end();
49 current_status( generating );
52 current_status( generating, msg );
5053 current_pos( b.pos() );
5154 if( verbosity >= 0 )
52 { show_status( b.pos(), "Generating logfile...", first_post );
53 first_post = false; }
55 { show_status( b.pos(), msg, first_post ); first_post = false; }
5456 if( interrupted() ) return -1;
5557 int copied_size = 0, error_size = 0;
5658 check_block( b, copied_size, error_size );
5759 if( copied_size + error_size < b.size() && // EOF
5860 !truncate_vector( b.pos() + copied_size + error_size ) )
59 {
60 final_msg( "EOF found before end of logfile" );
61 return 1;
62 }
61 { final_msg( "EOF found before end of logfile" ); return 1; }
6362 if( !update_logfile() ) return -2;
6463 }
6564 return 0;
65 }
66
67
68 void Genbook::show_status( const long long ipos, const char * const msg,
69 bool force )
70 {
71 const char * const up = "\x1b[A";
72 if( t0 == 0 )
73 {
74 t0 = t1 = initial_time();
75 first_size = last_size = gensize;
76 force = true;
77 std::printf( "\n\n" );
78 }
79
80 if( ipos >= 0 ) last_ipos = ipos;
81 const long t2 = std::time( 0 );
82 if( t2 > t1 || force )
83 {
84 if( t2 > t1 )
85 {
86 a_rate = ( gensize - first_size ) / ( t2 - t0 );
87 c_rate = ( gensize - last_size ) / ( t2 - t1 );
88 t1 = t2;
89 last_size = gensize;
90 }
91 std::printf( "\r%s%s", up, up );
92 std::printf( "rescued: %10sB, generated:%10sB, current rate: %9sB/s\n",
93 format_num( recsize ), format_num( gensize ),
94 format_num( c_rate, 99999 ) );
95 std::printf( " opos: %10sB, run time: %9s, average rate: %9sB/s\n",
96 format_num( last_ipos + offset() ), format_time( t1 - t0 ),
97 format_num( a_rate, 99999 ) );
98 if( msg && msg[0] )
99 {
100 const int len = std::strlen( msg ); std::printf( "\r%s", msg );
101 for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
102 oldlen = len;
103 }
104 std::fflush( stdout );
105 }
106 else if( t2 < t1 ) // clock jumped back
107 {
108 t0 -= std::min( t0, t1 - t2 );
109 t1 = t2;
110 }
66111 }
67112
68113
89134 if( logfile_exists() )
90135 {
91136 std::printf( "Initial status (read from logfile)\n" );
92 std::printf( "rescued: %10sB,", format_num( recsize ) );
93 std::printf( " generated:%10sB\n", format_num( gensize ) );
137 std::printf( "rescued: %10sB, generated:%10sB\n",
138 format_num( recsize ), format_num( gensize ) );
94139 std::printf( "Current status\n" );
95140 }
96141 }
97142 int retval = check_all();
143 const bool signaled = ( retval == -1 );
144 if( signaled ) retval = 0;
98145 if( verbosity >= 0 )
99146 {
100 show_status( -1, (retval ? 0 : "Finished"), true );
147 show_status( -1, ( retval || signaled ) ? 0 : "Finished", true );
101148 if( retval == -2 ) std::printf( "\nLogfile error" );
102 else if( retval < 0 ) std::printf( "\nInterrupted by user" );
149 else if( signaled ) std::printf( "\nInterrupted by user" );
103150 std::fputc( '\n', stdout );
104151 }
105152 if( retval == -2 ) retval = 1; // logfile error
106153 else
107154 {
108 if( retval == 0 ) current_status( finished );
109 else if( retval < 0 ) retval = 0; // interrupted by user
155 if( retval == 0 && !signaled ) current_status( finished );
110156 compact_sblock_vector();
111157 if( !update_logfile( -1, true ) && retval == 0 ) retval = 1;
112158 }
113159 if( final_msg() ) show_error( final_msg(), final_errno() );
114 return retval;
160 if( retval ) return retval; // errors have priority over signals
161 if( signaled ) return signaled_exit();
162 return 0;
115163 }
+68
-199
io.cc less more
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
3232
3333 #include "block.h"
3434 #include "ddrescue.h"
35 #include "loggers.h"
3536
3637
3738 namespace {
3839
39 bool volatile interrupted_ = false; // user pressed Ctrl-C
40 extern "C" void sighandler( int ) { interrupted_ = true; }
40 int volatile signum_ = 0; // user pressed Ctrl-C or similar
41 extern "C" void sighandler( int signum )
42 { if( signum_ == 0 && signum > 0 ) signum_ = signum; }
43
44
45 int set_signal( const int signum, void (*handler)( int ) )
46 {
47 struct sigaction new_action;
48
49 new_action.sa_handler = handler;
50 sigemptyset( &new_action.sa_mask );
51 new_action.sa_flags = SA_RESTART;
52 return sigaction( signum, &new_action, 0 );
53 }
4154
4255
4356 bool block_is_zero( const uint8_t * const buf, const int size )
5366 int readblock( const int fd, uint8_t * const buf, const int size,
5467 const long long pos )
5568 {
56 int rest = size;
69 int sz = 0;
5770 errno = 0;
5871 if( lseek( fd, pos, SEEK_SET ) >= 0 )
59 while( rest > 0 )
72 while( sz < size )
6073 {
6174 errno = 0;
62 const int n = read( fd, buf + size - rest, rest );
63 if( n > 0 ) rest -= n;
75 const int n = read( fd, buf + sz, size - sz );
76 if( n > 0 ) sz += n;
6477 else if( n == 0 ) break; // EOF
65 else if( errno != EINTR && errno != EAGAIN ) break;
66 }
67 return size - rest;
78 else if( errno != EINTR ) break;
79 }
80 return sz;
6881 }
6982
7083
7487 int writeblock( const int fd, const uint8_t * const buf, const int size,
7588 const long long pos )
7689 {
77 int rest = size;
90 int sz = 0;
7891 errno = 0;
7992 if( lseek( fd, pos, SEEK_SET ) >= 0 )
80 while( rest > 0 )
93 while( sz < size )
8194 {
8295 errno = 0;
83 const int n = write( fd, buf + size - rest, rest );
84 if( n > 0 ) rest -= n;
85 else if( n < 0 && errno != EINTR && errno != EAGAIN ) break;
86 }
87 return size - rest;
96 const int n = write( fd, buf + sz, size - sz );
97 if( n > 0 ) sz += n;
98 else if( n < 0 && errno != EINTR ) break;
99 }
100 return sz;
88101 }
89102
90103 } // end namespace
94107 //
95108 int Fillbook::fill_block( const Block & b )
96109 {
97 if( b.size() <= 0 ) internal_error( "bad size filling a Block" );
110 if( b.size() <= 0 ) internal_error( "bad size filling a Block." );
98111 const int size = b.size();
99112
100113 if( writeblock( odes_, iobuf(), size, b.pos() + offset() ) != size ||
101114 ( synchronous_ && fsync( odes_ ) < 0 && errno != EINVAL ) )
102115 {
103 if( !ignore_write_errors_ )
104 { final_msg( "write error" ); final_errno( errno ); }
116 if( !ignore_write_errors_ ) final_msg( "Write error", errno );
105117 return 1;
106118 }
107119 filled_size += size; remaining_size -= size;
108120 return 0;
109 }
110
111
112 void Fillbook::show_status( const long long ipos, bool force )
113 {
114 const char * const up = "\x1b[A";
115 if( t0 == 0 )
116 {
117 t0 = t1 = std::time( 0 );
118 first_size = last_size = filled_size;
119 force = true;
120 std::printf( "\n\n\n" );
121 }
122
123 if( ipos >= 0 ) last_ipos = ipos;
124 const long t2 = std::time( 0 );
125 if( t2 > t1 || force )
126 {
127 if( t2 > t1 )
128 {
129 a_rate = ( filled_size - first_size ) / ( t2 - t0 );
130 c_rate = ( filled_size - last_size ) / ( t2 - t1 );
131 t1 = t2;
132 last_size = filled_size;
133 }
134 std::printf( "\r%s%s%s", up, up, up );
135 std::printf( "filled size: %10sB,", format_num( filled_size ) );
136 std::printf( " filled areas: %6u,", filled_areas );
137 std::printf( " current rate: %9sB/s\n", format_num( c_rate, 99999 ) );
138 std::printf( "remain size: %10sB,", format_num( remaining_size ) );
139 std::printf( " remain areas: %6u,", remaining_areas );
140 std::printf( " average rate: %9sB/s\n", format_num( a_rate, 99999 ) );
141 std::printf( "current pos: %10sB\n", format_num( last_ipos + offset() ) );
142 std::fflush( stdout );
143 }
144 else if( t2 < t1 ) // clock jumped back
145 {
146 t0 -= std::min( t0, t1 - t2 );
147 t1 = t2;
148 }
149121 }
150122
151123
166138 //
167139 void Genbook::check_block( const Block & b, int & copied_size, int & error_size )
168140 {
169 if( b.size() <= 0 ) internal_error( "bad size checking a Block" );
141 if( b.size() <= 0 ) internal_error( "bad size checking a Block." );
170142 copied_size = readblock( odes_, iobuf(), b.size(), b.pos() + offset() );
171143 if( errno ) error_size = b.size() - copied_size;
172144
175147 const int size = std::min( hardbs(), copied_size - pos );
176148 if( !block_is_zero( iobuf() + pos, size ) )
177149 {
178 change_chunk_status( Block( b.pos() + pos, size ), Sblock::finished );
150 change_chunk_status( Block( b.pos() + pos, size ),
151 Sblock::finished, domain() );
179152 recsize += size;
180153 }
181154 gensize += size;
182155 pos += size;
183 }
184 }
185
186
187 void Genbook::show_status( const long long ipos, const char * const msg,
188 bool force )
189 {
190 const char * const up = "\x1b[A";
191 if( t0 == 0 )
192 {
193 t0 = t1 = std::time( 0 );
194 first_size = last_size = gensize;
195 force = true;
196 std::printf( "\n\n" );
197 }
198
199 if( ipos >= 0 ) last_ipos = ipos;
200 const long t2 = std::time( 0 );
201 if( t2 > t1 || force )
202 {
203 if( t2 > t1 )
204 {
205 a_rate = ( gensize - first_size ) / ( t2 - t0 );
206 c_rate = ( gensize - last_size ) / ( t2 - t1 );
207 t1 = t2;
208 last_size = gensize;
209 }
210 std::printf( "\r%s%s", up, up );
211 std::printf( "rescued: %10sB,", format_num( recsize ) );
212 std::printf( " generated:%10sB,", format_num( gensize ) );
213 std::printf( " current rate: %9sB/s\n", format_num( c_rate, 99999 ) );
214 std::printf( " opos: %10sB, ",
215 format_num( last_ipos + offset() ) );
216 std::printf( " average rate: %9sB/s\n", format_num( a_rate, 99999 ) );
217 if( msg && msg[0] )
218 {
219 const int len = std::strlen( msg ); std::printf( "\r%s", msg );
220 for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
221 oldlen = len;
222 }
223 std::fflush( stdout );
224 }
225 else if( t2 < t1 ) // clock jumped back
226 {
227 t0 -= std::min( t0, t1 - t2 );
228 t1 = t2;
229156 }
230157 }
231158
254181 //
255182 int Rescuebook::copy_block( const Block & b, int & copied_size, int & error_size )
256183 {
257 if( b.size() <= 0 ) internal_error( "bad size copying a Block" );
258 copied_size = readblock( ides_, iobuf(), b.size(), b.pos() );
259 if( errno ) error_size = b.size() - copied_size;
184 if( b.size() <= 0 ) internal_error( "bad size copying a Block." );
185 if( !test_domain || test_domain->includes( b ) )
186 {
187 copied_size = readblock( ides_, iobuf(), b.size(), b.pos() );
188 error_size = errno ? b.size() - copied_size : 0;
189 }
190 else { copied_size = 0; error_size = b.size(); }
260191
261192 if( copied_size > 0 )
262193 {
270201 ( synchronous_ && fsync( odes_ ) < 0 && errno != EINVAL ) )
271202 {
272203 copied_size = 0; error_size = 0;
273 final_msg( "write error" ); final_errno( errno );
204 final_msg( "Write error", errno );
274205 return 1;
275206 }
276207 }
208 read_logger.print_line( b.pos(), b.size(), copied_size, error_size );
277209 return 0;
278210 }
279211
280212
281 void Rescuebook::update_rates( const bool force )
282 {
283 if( t0 == 0 )
284 {
285 t0 = t1 = ts = std::time( 0 );
286 first_size = last_size = recsize;
287 rates_updated = true;
288 if( verbosity >= 0 ) std::printf( "\n\n\n" );
289 }
290
291 long t2 = std::time( 0 );
292 if( force && t2 <= t1 ) t2 = t1 + 1; // force update of e_code
293 if( t2 > t1 )
294 {
295 a_rate = ( recsize - first_size ) / ( t2 - t0 );
296 c_rate = ( recsize - last_size ) / ( t2 - t1 );
297 if( !( e_code & 4 ) )
298 {
299 if( recsize != last_size ) { last_size = recsize; ts = t2; }
300 else if( timeout >= 0 && t2 - ts > timeout ) e_code |= 4;
301 }
302 if( max_error_rate >= 0 && !( e_code & 1 ) )
303 {
304 error_rate /= ( t2 - t1 );
305 if( error_rate > max_error_rate ) e_code |= 1;
306 else error_rate = 0;
307 }
308 t1 = t2;
309 rates_updated = true;
310 }
311 else if( t2 < t1 ) // clock jumped back
312 {
313 const long delta = std::min( t0, t1 - t2 );
314 t0 -= delta;
315 ts -= delta;
316 t1 = t2;
317 }
318 }
319
320
321 void Rescuebook::show_status( const long long ipos, const char * const msg,
322 const bool force )
323 {
324 const char * const up = "\x1b[A";
325
326 if( ipos >= 0 ) last_ipos = ipos;
327 if( rates_updated || force )
328 {
329 if( verbosity >= 0 )
330 {
331 std::printf( "\r%s%s%s", up, up, up );
332 std::printf( "rescued: %10sB,", format_num( recsize ) );
333 std::printf( " errsize:%9sB,", format_num( errsize, 99999 ) );
334 std::printf( " current rate: %9sB/s\n", format_num( c_rate, 99999 ) );
335 std::printf( " ipos: %10sB, errors: %7u, ",
336 format_num( last_ipos ), errors );
337 std::printf( " average rate: %9sB/s\n", format_num( a_rate, 99999 ) );
338 std::printf( " opos: %10sB,", format_num( last_ipos + offset() ) );
339 std::printf( " time since last successful read: %9s\n",
340 format_time( t1 - ts ) );
341 if( msg && msg[0] && !errors_or_timeout() )
342 {
343 const int len = std::strlen( msg ); std::printf( "\r%s", msg );
344 for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
345 oldlen = len;
346 }
347 std::fflush( stdout );
348 }
349 rates_updated = false;
350 }
351 }
352
353
354213 const char * format_time( long t )
355214 {
356 static char buf[16];
215 enum { buffers = 8, bufsize = 16 };
216 static char buffer[buffers][bufsize]; // circle of static buffers for printf
217 static int current = 0;
218 char * const buf = buffer[current++]; current %= buffers;
357219 int fraction = 0;
358220 char unit = 's';
359221
360 if( t >= 86400 ) { fraction = ( t % 86400 ) / 8640; t /= 86400; unit = 'd'; }
361 else if( t >= 3600 ) { fraction = ( t % 3600 ) / 360; t /= 3600; unit = 'h'; }
362 else if( t >= 60 ) { fraction = ( t % 60 ) / 6; t /= 60; unit = 'm'; }
222 if( t >= 86400 ) { fraction = ( t % 86400 ) / 864; t /= 86400; unit = 'd'; }
223 else if( t >= 3600 ) { fraction = ( t % 3600 ) / 36; t /= 3600; unit = 'h'; }
224 else if( t >= 60 ) { fraction = (10 * ( t % 60 )) / 6; t /= 60; unit = 'm'; }
363225 if( fraction == 0 )
364 snprintf( buf, sizeof buf, "%ld %c", t, unit );
226 snprintf( buf, bufsize, "%ld %c", t, unit );
365227 else
366 snprintf( buf, sizeof buf, "%ld.%d %c", t, fraction, unit );
228 snprintf( buf, bufsize, "%ld.%02d %c", t, fraction, unit );
367229 return buf;
368230 }
369231
370232
371 bool interrupted() { return interrupted_; }
233 bool interrupted() { return ( signum_ > 0 ); }
372234
373235
374236 void set_signals()
375237 {
376 interrupted_ = false;
377 std::signal( SIGINT, sighandler );
378 std::signal( SIGHUP, sighandler );
379 std::signal( SIGTERM, sighandler );
380 std::signal( SIGUSR1, SIG_IGN );
381 std::signal( SIGUSR2, SIG_IGN );
382 }
238 signum_ = 0;
239 set_signal( SIGHUP, sighandler );
240 set_signal( SIGINT, sighandler );
241 set_signal( SIGTERM, sighandler );
242 set_signal( SIGUSR1, SIG_IGN );
243 set_signal( SIGUSR2, SIG_IGN );
244 }
245
246 int signaled_exit()
247 {
248 set_signal( signum_, SIG_DFL );
249 std::raise( signum_ );
250 return 128 + signum_; // in case std::raise fails to exit
251 }
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1818 #define _FILE_OFFSET_BITS 64
1919
2020 #include <algorithm>
21 #include <cctype>
2221 #include <cerrno>
2322 #include <climits>
2423 #include <cstdio>
4443 show_error( buf );
4544 }
4645
47
48 int my_fgetc( FILE * const f )
49 {
50 int ch;
51 bool comment = false;
52
53 do {
54 ch = std::fgetc( f );
55 if( ch == '#' ) comment = true;
56 else if( ch == '\n' || ch == EOF ) comment = false;
57 }
58 while( comment );
59 return ch;
60 }
61
62
63 // Read a line discarding comments, leading whitespace and blank lines.
64 // Returns 0 if at EOF.
65 //
66 const char * my_fgets( FILE * const f, int & linenum )
67 {
68 const int maxlen = 127;
69 static char buf[maxlen+1];
70 int ch, len = 1;
71
72 while( len == 1 ) // while line is blank
73 {
74 do { ch = my_fgetc( f ); if( ch == '\n' ) ++linenum; }
75 while( std::isspace( ch ) );
76 len = 0;
77 while( true )
78 {
79 if( ch == EOF ) { if( len > 0 ) ch = '\n'; else break; }
80 if( len < maxlen ) buf[len++] = ch;
81 if( ch == '\n' ) { ++linenum; break; }
82 ch = my_fgetc( f );
83 }
84 }
85 if( len > 0 ) { buf[len] = 0; return buf; }
86 else return 0;
87 }
88
89
90 void extend_sblock_vector( std::vector< Sblock > & sblock_vector,
91 const long long isize )
92 {
93 if( sblock_vector.size() == 0 )
94 {
95 Sblock sb( 0, ( isize > 0 ) ? isize : -1, Sblock::non_tried );
96 sb.fix_size();
97 sblock_vector.push_back( sb );
98 return;
99 }
100 Sblock & front = sblock_vector.front();
101 if( front.pos() > 0 )
102 sblock_vector.insert( sblock_vector.begin(), Sblock( 0, front.pos(), Sblock::non_tried ) );
103 Sblock & back = sblock_vector.back();
104 const long long end = back.end();
105 if( isize > 0 )
106 {
107 if( back.pos() >= isize )
108 {
109 if( back.pos() == isize && back.status() != Sblock::finished )
110 { sblock_vector.pop_back(); return; }
111 show_error( "Last block in logfile begins past end of input file.\n"
112 " Use '-C' if you are reading from a partial copy.",
113 0, true );
114 std::exit( 1 );
115 }
116 if( end > isize )
117 {
118 if( back.status() != Sblock::finished )
119 { back.size( isize - back.pos() ); return; }
120 show_error( "Rescued data in logfile goes past end of input file.\n"
121 " Use '-C' if you are reading from a partial copy.",
122 0, true );
123 std::exit( 1 );
124 }
125 else if( end < isize )
126 sblock_vector.push_back( Sblock( end, isize - end, Sblock::non_tried ) );
127 }
128 else if( end >= 0 )
129 {
130 Sblock sb( end, -1, Sblock::non_tried );
131 sb.fix_size();
132 if( sb.size() > 0 ) sblock_vector.push_back( sb );
133 }
134 }
135
136
137 void show_logfile_error( const char * const filename, const int linenum )
138 {
139 char buf[80];
140 snprintf( buf, sizeof buf, "error in logfile %s, line %d.", filename, linenum );
141 show_error( buf );
142 }
143
144
145 // Returns true if logfile exists and is readable.
146 //
147 bool read_logfile( const char * const logname,
148 std::vector< Sblock > & sblock_vector,
149 long long & current_pos, Logbook::Status & current_status )
150 {
151 FILE * const f = std::fopen( logname, "r" );
152 if( !f ) return false;
153 int linenum = 0;
154 sblock_vector.clear();
155
156 const char * line = my_fgets( f, linenum );
157 if( line ) // status line
158 {
159 char ch;
160 int n = std::sscanf( line, "%lli %c\n", &current_pos, &ch );
161 if( n == 2 && current_pos >= 0 && Logbook::isstatus( ch ) )
162 current_status = Logbook::Status( ch );
163 else
164 {
165 show_logfile_error( logname, linenum );
166 show_error( "Are you using a logfile from ddrescue 1.5 or older?" );
167 std::exit( 2 );
168 }
169
170 while( true )
171 {
172 line = my_fgets( f, linenum );
173 if( !line ) break;
174 long long pos, size;
175 n = std::sscanf( line, "%lli %lli %c\n", &pos, &size, &ch );
176 if( n == 3 && pos >= 0 && Sblock::isstatus( ch ) &&
177 ( size > 0 || size == -1 || ( size == 0 && pos == 0 ) ) )
178 {
179 const Sblock::Status st = Sblock::Status( ch );
180 Sblock sb( pos, size, st ); sb.fix_size();
181 if( sblock_vector.size() > 0 && !sb.follows( sblock_vector.back() ) )
182 { show_logfile_error( logname, linenum ); std::exit( 2 ); }
183 sblock_vector.push_back( sb );
184 }
185 else
186 { show_logfile_error( logname, linenum ); std::exit( 2 ); }
187 }
188 }
189 std::fclose( f );
190 return true;
191 }
192
19346 } // end namespace
19447
19548
196 Domain::Domain( const long long p, const long long s,
197 const char * const logname )
198 {
199 Block b( p, s ); b.fix_size();
200 if( !logname || !logname[0] ) { block_vector.push_back( b ); return; }
201 std::vector< Sblock > sblock_vector;
202 long long current_pos; // not used
203 Logbook::Status current_status; // not used
204 if( !read_logfile( logname, sblock_vector, current_pos, current_status ) )
205 {
206 char buf[80];
207 snprintf( buf, sizeof buf,
208 "Logfile '%s' does not exist or is not readable.", logname );
209 show_error( buf );
210 std::exit( 1 );
211 }
212 for( unsigned i = 0; i < sblock_vector.size(); ++i )
213 {
214 const Sblock & sb = sblock_vector[i];
215 if( sb.status() == Sblock::finished ) block_vector.push_back( sb );
216 }
217 if( block_vector.size() == 0 ) block_vector.push_back( Block( 0, 0 ) );
218 else this->crop( b );
219 }
220
221
222 void Logbook::split_domain_border_sblocks()
223 {
224 for( unsigned i = 0; i < sblock_vector.size(); ++i )
225 {
226 Sblock & sb = sblock_vector[i];
227 const long long pos = domain_.breaks_block_by( sb );
228 if( pos > 0 )
229 {
230 const Sblock head( sb.split( pos ) );
231 if( head.size() > 0 ) insert_sblock( i, head );
232 else internal_error( "empty block created by split_domain_border_sblocks" );
233 }
234 }
235 }
236
237
238 Logbook::Logbook( const long long offset, const long long isize,
239 Domain & dom, const char * const logname,
240 const int cluster, const int hardbs,
241 const bool complete_only, const bool do_not_read )
242 : offset_( offset ), current_pos_( 0 ), logfile_isize_( 0 ),
243 current_status_( copying ), domain_( dom ), filename_( logname ),
244 hardbs_( hardbs ), softbs_( cluster * hardbs ),
245 final_msg_( 0 ), final_errno_( 0 ), index_( 0 ),
246 ul_t1( std::time( 0 ) ), logfile_exists_( false )
49 Logbook::Logbook( const long long offset, const long long isize, Domain & dom,
50 const char * const logname, const int cluster,
51 const int hardbs, const bool complete_only )
52 : Logfile( logname ), offset_( offset ), logfile_isize_( 0 ),
53 domain_( dom ), hardbs_( hardbs ), softbs_( cluster * hardbs ),
54 final_msg_( 0 ), final_errno_( 0 ),
55 ul_t1( initial_time() ), logfile_exists_( false )
24756 {
24857 int alignment = sysconf( _SC_PAGESIZE );
24958 if( alignment < hardbs_ || alignment % hardbs_ ) alignment = hardbs_;
26170 { input_pos_error( domain_.pos(), isize ); std::exit( 1 ); }
26271 domain_.crop_by_file_size( isize );
26372 }
264 if( filename_ && !do_not_read )
73 if( filename() )
26574 {
266 logfile_exists_ =
267 read_logfile( filename_, sblock_vector, current_pos_, current_status_ );
268 if( logfile_exists_ && sblock_vector.size() )
269 logfile_isize_ = sblock_vector.back().end();
75 logfile_exists_ = read_logfile();
76 if( logfile_exists_ ) logfile_isize_ = extent().end();
27077 }
271 if( !complete_only ) extend_sblock_vector( sblock_vector, isize );
272 else if( sblock_vector.size() ) // limit domain to blocks read from logfile
273 {
274 const Block b( sblock_vector.front().pos(),
275 sblock_vector.back().end() - sblock_vector.front().pos() );
276 domain_.crop( b );
277 }
78 if( !complete_only ) extend_sblock_vector( isize );
79 else domain_.crop( extent() ); // limit domain to blocks read from logfile
27880 compact_sblock_vector();
279 split_domain_border_sblocks();
280 if( sblock_vector.size() == 0 ) domain_.clear();
281 }
282
283
284 bool Logbook::blank() const
285 {
286 for( unsigned i = 0; i < sblock_vector.size(); ++i )
287 if( sblock_vector[i].status() != Sblock::non_tried )
288 return false;
289 return true;
290 }
291
292
293 void Logbook::compact_sblock_vector()
294 {
295 for( unsigned i = sblock_vector.size(); i >= 2; )
296 {
297 --i;
298 if( sblock_vector[i-1].join( sblock_vector[i] ) )
299 sblock_vector.erase( sblock_vector.begin() + i );
300 }
81 split_by_domain_borders( domain_ );
82 if( sblocks() == 0 ) domain_.clear();
30183 }
30284
30385
30486 // Writes periodically the logfile to disc.
30587 // Returns false only if update is attempted and fails.
30688 //
307 bool Logbook::update_logfile( const int odes, const bool force,
308 const bool retry )
89 bool Logbook::update_logfile( const int odes, const bool force )
30990 {
310 if( !filename_ ) return true;
91 if( !filename() ) return true;
31192 const int interval = 30 + std::min( 270, sblocks() / 38 ); // 30s to 5m
31293 const long t2 = std::time( 0 );
31394 if( !force && t2 - ul_t1 < interval ) return true;
31495 ul_t1 = t2;
31596 if( odes >= 0 ) fsync( odes );
31697
317 errno = 0;
318 FILE * const f = std::fopen( filename_, "w" );
319 if( f )
98 while( true )
32099 {
321 write_logfile( f );
322 if( std::fclose( f ) == 0 ) return true;
323 }
324
325 if( verbosity >= 0 )
326 {
100 errno = 0;
101 if( write_logfile( 0, true ) ) return true;
102 if( verbosity < 0 ) return false;
103 const int saved_errno = errno;
104 std::fprintf( stderr, "\n" );
327105 char buf[80];
328 snprintf( buf, sizeof buf, f ? "Error writing logfile '%s'." :
329 "Error opening logfile '%s' for writing.",
330 filename_ );
331 if( retry ) std::fprintf( stderr, "\n" );
332 show_error( buf, errno );
333 if( retry )
106 snprintf( buf, sizeof buf, "Error writing logfile '%s'", filename() );
107 show_error( buf, saved_errno );
108 std::fprintf( stderr, "Fix the problem and press ENTER to retry, "
109 "or Q+ENTER to abort. " );
110 std::fflush( stderr );
111 while( true )
334112 {
335 std::fprintf( stderr, "Fix the problem and press ENTER to retry, or Q+ENTER to abort. " );
336 std::fflush( stderr );
337 while( true )
338 {
339 const char c = std::tolower( std::fgetc( stdin ) );
340 if( c == '\r' || c == '\n' )
341 {
342 std::fprintf( stderr, "\n\n\n\n" );
343 return update_logfile( -1, true );
344 }
345 if( c == 'q' ) break;
346 }
113 const char c = std::tolower( std::fgetc( stdin ) );
114 if( c == '\r' || c == '\n' || c == 'q' )
115 { std::fprintf( stderr, "\n\n\n\n" );
116 if( c == 'q' ) return false; else break; }
347117 }
348118 }
349 return false;
350119 }
351
352
353 void Logbook::write_logfile( FILE * const f ) const
354 {
355 write_logfile_header( f );
356 std::fprintf( f, "# current_pos current_status\n" );
357 std::fprintf( f, "0x%08llX %c\n", current_pos_, current_status_ );
358 std::fprintf( f, "# pos size status\n" );
359 for( unsigned i = 0; i < sblock_vector.size(); ++i )
360 {
361 const Sblock & sb = sblock_vector[i];
362 std::fprintf( f, "0x%08llX 0x%08llX %c\n", sb.pos(), sb.size(), sb.status() );
363 }
364 }
365
366
367 // Returns false only if truncation would remove finished blocks and
368 // force is false.
369 //
370 bool Logbook::truncate_vector( const long long end, const bool force )
371 {
372 int i = sblocks() - 1;
373 while( i >= 0 && sblock_vector[i].pos() >= end ) --i;
374 if( i < 0 )
375 {
376 sblock_vector.clear();
377 sblock_vector.push_back( Sblock( 0, 0, Sblock::non_tried ) );
378 }
379 else
380 {
381 if( !force )
382 for( unsigned j = i + 1; j < sblock_vector.size(); ++j )
383 if( sblock_vector[j].status() == Sblock::finished ) return false;
384 Sblock & sb = sblock_vector[i];
385 if( sb.includes( end ) )
386 {
387 if( !force && sb.status() == Sblock::finished ) return false;
388 sb.size( end - sb.pos() );
389 }
390 sblock_vector.erase( sblock_vector.begin() + i + 1, sblock_vector.end() );
391 }
392 return true;
393 }
394
395
396 int Logbook::find_index( const long long pos ) const
397 {
398 if( index_ < 0 || index_ >= sblocks() ) index_ = sblocks() / 2;
399 while( index_ + 1 < sblocks() && pos >= sblock_vector[index_].end() )
400 ++index_;
401 while( index_ > 0 && pos < sblock_vector[index_].pos() )
402 --index_;
403 if( !sblock_vector[index_].includes( pos ) ) index_ = -1;
404 return index_;
405 }
406
407
408 int Logbook::find_largest_sblock( const Sblock::Status st ) const
409 {
410 long long size = 0;
411 int index = -1;
412 for( int i = 0; i < sblocks(); ++i )
413 {
414 const Sblock & sb = sblock_vector[i];
415 if( sb.status() == st && sb.size() > size && domain_.includes( sb ) )
416 { size = sb.size(); index = i; }
417 }
418 return index;
419 }
420
421
422 int Logbook::find_smallest_sblock( const Sblock::Status st ) const
423 {
424 long long size = LLONG_MAX;
425 int index = -1;
426 for( int i = 0; i < sblocks(); ++i )
427 {
428 const Sblock & sb = sblock_vector[i];
429 if( sb.status() == st &&
430 ( sb.size() < size || ( sb.size() == size && index < 0 ) ) &&
431 domain_.includes( sb ) )
432 { size = sb.size(); index = i; if( size <= hardbs_ ) break; }
433 }
434 return index;
435 }
436
437
438 // Find chunk from b.pos of size <= b.size and status st.
439 // if not found, puts b.size to 0.
440 //
441 void Logbook::find_chunk( Block & b, const Sblock::Status st,
442 const int alignment ) const
443 {
444 if( b.size() <= 0 ) return;
445 if( b.pos() < sblock_vector.front().pos() )
446 b.pos( sblock_vector.front().pos() );
447 if( find_index( b.pos() ) < 0 ) { b.size( 0 ); return; }
448 int i;
449 for( i = index_; i < sblocks(); ++i )
450 if( sblock_vector[i].status() == st &&
451 domain_.includes( sblock_vector[i] ) )
452 { index_ = i; break; }
453 if( i >= sblocks() ) { b.size( 0 ); return; }
454 if( b.pos() < sblock_vector[index_].pos() )
455 b.pos( sblock_vector[index_].pos() );
456 b.fix_size();
457 if( !sblock_vector[index_].includes( b ) )
458 b.crop( sblock_vector[index_] );
459 if( b.end() != sblock_vector[index_].end() )
460 b.align_end( alignment ? alignment : hardbs_ );
461 }
462
463
464 // Find chunk from b.end backwards of size <= b.size and status st.
465 // if not found, puts b.size to 0.
466 //
467 void Logbook::rfind_chunk( Block & b, const Sblock::Status st,
468 const int alignment ) const
469 {
470 if( b.size() <= 0 ) return;
471 b.fix_size();
472 if( sblock_vector.back().end() < b.end() )
473 b.end( sblock_vector.back().end() );
474 find_index( b.end() - 1 );
475 for( ; index_ >= 0; --index_ )
476 if( sblock_vector[index_].status() == st &&
477 domain_.includes( sblock_vector[index_] ) )
478 break;
479 if( index_ < 0 ) { b.size( 0 ); return; }
480 if( b.end() > sblock_vector[index_].end() )
481 b.end( sblock_vector[index_].end() );
482 if( !sblock_vector[index_].includes( b ) )
483 b.crop( sblock_vector[index_] );
484 if( b.pos() != sblock_vector[index_].pos() )
485 b.align_pos( alignment ? alignment : hardbs_ );
486 }
487
488
489 // Returns an adjust value (-1, 0, +1) to keep "errors" updated without
490 // having to call count_errors every time.
491 // - - - --> - + - return +1
492 // - - + --> - + + return 0
493 // - + - --> - - - return -1
494 // - + + --> - - + return 0
495 // + - - --> + + - return 0
496 // + - + --> + + + return -1
497 // + + - --> + - - return 0
498 // + + + --> + - + return +1
499 //
500 int Logbook::change_chunk_status( const Block & b, const Sblock::Status st )
501 {
502 if( b.size() <= 0 ) return 0;
503 if( !domain_.includes( b ) || find_index( b.pos() ) < 0 ||
504 !domain_.includes( sblock_vector[index_] ) )
505 internal_error( "can't change status of chunk not in rescue domain" );
506 if( !sblock_vector[index_].includes( b ) )
507 internal_error( "can't change status of chunk spread over more than 1 block" );
508 if( sblock_vector[index_].status() == st ) return 0;
509
510 const bool old_st_good = Sblock::is_good_status( sblock_vector[index_].status() );
511 const bool new_st_good = Sblock::is_good_status( st );
512 bool bl_st_good = ( index_ <= 0 ||
513 !domain_.includes( sblock_vector[index_-1] ) ||
514 Sblock::is_good_status( sblock_vector[index_-1].status() ) );
515 bool br_st_good = ( index_ + 1 >= sblocks() ||
516 !domain_.includes( sblock_vector[index_+1] ) ||
517 Sblock::is_good_status( sblock_vector[index_+1].status() ) );
518 if( sblock_vector[index_].pos() < b.pos() )
519 {
520 if( sblock_vector[index_].end() == b.end() &&
521 index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st &&
522 domain_.includes( sblock_vector[index_+1] ) )
523 {
524 sblock_vector[index_].inc_size( -b.size() );
525 sblock_vector[index_+1].pos( b.pos() );
526 sblock_vector[index_+1].inc_size( b.size() );
527 return 0;
528 }
529 insert_sblock( index_, sblock_vector[index_].split( b.pos() ) );
530 ++index_;
531 bl_st_good = old_st_good;
532 }
533 if( sblock_vector[index_].size() > b.size() )
534 {
535 sblock_vector[index_].pos( b.end() );
536 sblock_vector[index_].inc_size( -b.size() );
537 br_st_good = Sblock::is_good_status( sblock_vector[index_].status() );
538 if( index_ > 0 && sblock_vector[index_-1].status() == st &&
539 domain_.includes( sblock_vector[index_-1] ) )
540 sblock_vector[index_-1].inc_size( b.size() );
541 else
542 insert_sblock( index_, Sblock( b, st ) );
543 }
544 else
545 {
546 sblock_vector[index_].status( st );
547 if( index_ > 0 && sblock_vector[index_-1].status() == st &&
548 domain_.includes( sblock_vector[index_-1] ) )
549 {
550 sblock_vector[index_-1].inc_size( sblock_vector[index_].size() );
551 erase_sblock( index_ ); --index_;
552 }
553 if( index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st &&
554 domain_.includes( sblock_vector[index_+1] ) )
555 {
556 sblock_vector[index_].inc_size( sblock_vector[index_+1].size() );
557 erase_sblock( index_ + 1 );
558 }
559 }
560 int retval = 0;
561 if( new_st_good != old_st_good && bl_st_good == br_st_good )
562 { if( old_st_good == bl_st_good ) retval = +1; else retval = -1; }
563 return retval;
564 }
565
566
567 const char * Logbook::status_name( const Logbook::Status st )
568 {
569 switch( st )
570 {
571 case copying: return "copying";
572 case trimming: return "trimming";
573 case splitting: return "splitting";
574 case retrying: return "retrying";
575 case filling: return "filling";
576 case generating: return "generating";
577 case finished: return "finished";
578 }
579 return "unknown"; // should not be reached
580 }
0 /* GNU ddrescue - Data recovery tool
1 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013, 2014 Antonio Diaz Diaz.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define _FILE_OFFSET_BITS 64
19
20 #include <algorithm>
21 #include <cctype>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <string>
25 #include <vector>
26
27 #include "block.h"
28
29
30 namespace {
31
32 int my_fgetc( FILE * const f )
33 {
34 int ch = std::fgetc( f );
35 if( ch == '#' ) // comment
36 { do ch = std::fgetc( f ); while( ch != '\n' && ch != EOF ); }
37 return ch;
38 }
39
40
41 // Read a line discarding comments, leading whitespace and blank lines.
42 // Returns 0 if at EOF.
43 //
44 const char * my_fgets( FILE * const f, int & linenum )
45 {
46 const int maxlen = 127;
47 static char buf[maxlen+1];
48 int ch, len = 1;
49
50 while( len == 1 ) // while line is blank
51 {
52 do { ch = my_fgetc( f ); if( ch == '\n' ) ++linenum; }
53 while( std::isspace( ch ) );
54 len = 0;
55 while( true )
56 {
57 if( ch == EOF ) { if( len > 0 ) ch = '\n'; else break; }
58 if( len < maxlen ) buf[len++] = ch;
59 if( ch == '\n' ) { ++linenum; break; }
60 ch = my_fgetc( f );
61 }
62 }
63 if( len > 0 ) { buf[len] = 0; return buf; }
64 else return 0;
65 }
66
67
68 void show_logfile_error( const char * const logname, const int linenum )
69 {
70 char buf[80];
71 snprintf( buf, sizeof buf, "error in logfile %s, line %d.", logname, linenum );
72 show_error( buf );
73 }
74
75 } // end namespace
76
77
78 void Logfile::compact_sblock_vector()
79 {
80 std::vector< Sblock > new_vector;
81 unsigned l = 0;
82 while( l < sblock_vector.size() )
83 {
84 Sblock run = sblock_vector[l];
85 unsigned r = l + 1;
86 while( r < sblock_vector.size() &&
87 sblock_vector[r].status() == run.status() ) ++r;
88 if( r > l + 1 ) run.size( sblock_vector[r-1].end() - run.pos() );
89 new_vector.push_back( run );
90 l = r;
91 }
92 sblock_vector.swap( new_vector );
93 }
94
95
96 void Logfile::extend_sblock_vector( const long long isize )
97 {
98 if( sblock_vector.empty() )
99 {
100 const Sblock sb( 0, ( isize > 0 ) ? isize : -1, Sblock::non_tried );
101 sblock_vector.push_back( sb );
102 return;
103 }
104 Sblock & front = sblock_vector.front();
105 if( front.pos() > 0 )
106 sblock_vector.insert( sblock_vector.begin(), Sblock( 0, front.pos(), Sblock::non_tried ) );
107 Sblock & back = sblock_vector.back();
108 const long long end = back.end();
109 if( isize > 0 )
110 {
111 if( back.pos() >= isize )
112 {
113 if( back.pos() == isize && back.status() != Sblock::finished )
114 { sblock_vector.pop_back(); return; }
115 show_error( "Last block in logfile begins past end of input file.\n"
116 " Use '-C' if you are reading from a partial copy.",
117 0, true );
118 std::exit( 1 );
119 }
120 if( end > isize )
121 {
122 if( back.status() != Sblock::finished )
123 { back.size( isize - back.pos() ); return; }
124 show_error( "Rescued data in logfile goes past end of input file.\n"
125 " Use '-C' if you are reading from a partial copy.",
126 0, true );
127 std::exit( 1 );
128 }
129 else if( end < isize )
130 sblock_vector.push_back( Sblock( end, isize - end, Sblock::non_tried ) );
131 }
132 else if( end >= 0 )
133 {
134 const Sblock sb( end, -1, Sblock::non_tried );
135 if( sb.size() > 0 ) sblock_vector.push_back( sb );
136 }
137 }
138
139
140 // Returns false only if truncation would remove finished blocks and
141 // force is false.
142 //
143 bool Logfile::truncate_vector( const long long end, const bool force )
144 {
145 unsigned i = sblock_vector.size();
146 while( i > 0 && sblock_vector[i-1].pos() >= end ) --i;
147 if( !force )
148 for( unsigned j = i; j < sblock_vector.size(); ++j )
149 if( sblock_vector[j].status() == Sblock::finished ) return false;
150 if( i == 0 )
151 {
152 sblock_vector.clear();
153 sblock_vector.push_back( Sblock( 0, 0, Sblock::non_tried ) );
154 }
155 else
156 {
157 Sblock & sb = sblock_vector[i-1];
158 if( sb.includes( end ) )
159 {
160 if( !force && sb.status() == Sblock::finished ) return false;
161 sb.size( end - sb.pos() );
162 }
163 sblock_vector.erase( sblock_vector.begin() + i, sblock_vector.end() );
164 }
165 return true;
166 }
167
168
169 // Returns true if logfile exists and is readable.
170 // Fills the gaps if 'default_sblock_status' is a valid status character.
171 //
172 bool Logfile::read_logfile( const int default_sblock_status )
173 {
174 FILE * const f = std::fopen( filename_, "r" );
175 if( !f ) return false;
176 int linenum = 0;
177 const bool loose = Sblock::isstatus( default_sblock_status );
178 read_only_ = false;
179 sblock_vector.clear();
180
181 const char * line = my_fgets( f, linenum );
182 if( line ) // status line
183 {
184 char ch;
185 int n = std::sscanf( line, "%lli %c\n", &current_pos_, &ch );
186 if( n == 2 && current_pos_ >= 0 && isstatus( ch ) )
187 current_status_ = Status( ch );
188 else
189 {
190 show_logfile_error( filename_, linenum );
191 show_error( "Are you using a logfile from ddrescue 1.5 or older?" );
192 std::exit( 2 );
193 }
194
195 while( true )
196 {
197 line = my_fgets( f, linenum );
198 if( !line ) break;
199 long long pos, size;
200 n = std::sscanf( line, "%lli %lli %c\n", &pos, &size, &ch );
201 if( n == 3 && pos >= 0 && Sblock::isstatus( ch ) &&
202 ( size > 0 || ( size == 0 && pos == 0 ) ) )
203 {
204 const Sblock::Status st = Sblock::Status( ch );
205 const Sblock sb( pos, size, st );
206 const long long end = sblock_vector.size() ?
207 sblock_vector.back().end() : 0;
208 if( sb.pos() != end )
209 {
210 if( loose && sb.pos() > end )
211 { const Sblock sb2( end, sb.pos() - end,
212 Sblock::Status( default_sblock_status ) );
213 sblock_vector.push_back( sb2 ); }
214 else if( end > 0 )
215 { show_logfile_error( filename_, linenum ); std::exit( 2 ); }
216 }
217 sblock_vector.push_back( sb );
218 }
219 else
220 { show_logfile_error( filename_, linenum ); std::exit( 2 ); }
221 }
222 }
223 if( std::ferror( f ) )
224 { show_logfile_error( filename_, linenum ); std::exit( 2 ); }
225 if( std::freopen( filename_, "r+", f ) ) std::fclose( f );
226 else read_only_ = true;
227 return true;
228 }
229
230
231 int Logfile::write_logfile( FILE * f, const bool timestamp ) const
232 {
233 const bool f_given = ( f != 0 );
234
235 if( !f && !filename_ ) return false;
236 if( !f ) { f = std::fopen( filename_, "w" ); if( !f ) return false; }
237 write_logfile_header( f, "Rescue" );
238 if( timestamp ) write_timestamp( f );
239 if( current_msg.size() ) std::fprintf( f, "# %s\n", current_msg.c_str() );
240 std::fprintf( f, "# current_pos current_status\n" );
241 std::fprintf( f, "0x%08llX %c\n", current_pos_, current_status_ );
242 std::fprintf( f, "# pos size status\n" );
243 for( unsigned i = 0; i < sblock_vector.size(); ++i )
244 {
245 const Sblock & sb = sblock_vector[i];
246 std::fprintf( f, "0x%08llX 0x%08llX %c\n", sb.pos(), sb.size(), sb.status() );
247 }
248 return ( f_given || std::fclose( f ) == 0 );
249 }
250
251
252 bool Logfile::blank() const
253 {
254 for( unsigned i = 0; i < sblock_vector.size(); ++i )
255 if( sblock_vector[i].status() != Sblock::non_tried )
256 return false;
257 return true;
258 }
259
260
261 void Logfile::split_by_domain_borders( const Domain & domain )
262 {
263 if( domain.blocks() == 1 )
264 {
265 const Block & db = domain.block( 0 );
266 unsigned i = 0;
267 while( i < sblock_vector.size() && sblock_vector[i] < db ) ++i;
268 if( i < sblock_vector.size() ) try_split_sblock_by( db.pos(), i );
269 i = sblock_vector.size();
270 while( i > 0 && db < sblock_vector[i-1] ) --i;
271 if( i > 0 ) try_split_sblock_by( db.end(), i - 1 );
272 }
273 else
274 {
275 std::vector< Sblock > new_vector;
276 int j = 0;
277 for( unsigned i = 0; i < sblock_vector.size(); )
278 {
279 Sblock & sb = sblock_vector[i];
280 while( j < domain.blocks() && domain.block( j ) < sb ) ++j;
281 if( j >= domain.blocks() ) // end of domain tail copy
282 { new_vector.insert( new_vector.end(),
283 sblock_vector.begin() + i, sblock_vector.end() );
284 break; }
285 const Block & db = domain.block( j );
286 if( sb.strictly_includes( db.pos() ) )
287 new_vector.push_back( sb.split( db.pos() ) );
288 if( sb.strictly_includes( db.end() ) )
289 new_vector.push_back( sb.split( db.end() ) );
290 if( sb.pos() < db.end() ) { new_vector.push_back( sb ); ++i; }
291 }
292 sblock_vector.swap( new_vector );
293 }
294 }
295
296
297 void Logfile::split_by_logfile_borders( const Logfile & logfile )
298 {
299 std::vector< Sblock > new_vector;
300 int j = 0;
301 for( unsigned i = 0; i < sblock_vector.size(); )
302 {
303 Sblock & sb = sblock_vector[i];
304 while( j < logfile.sblocks() && logfile.sblock( j ) < sb ) ++j;
305 if( j >= logfile.sblocks() ) // end of logfile tail copy
306 { new_vector.insert( new_vector.end(),
307 sblock_vector.begin() + i, sblock_vector.end() );
308 break; }
309 const Sblock & db = logfile.sblock( j );
310 if( sb.strictly_includes( db.pos() ) )
311 new_vector.push_back( sb.split( db.pos() ) );
312 if( sb.strictly_includes( db.end() ) )
313 new_vector.push_back( sb.split( db.end() ) );
314 if( sb.pos() < db.end() ) { new_vector.push_back( sb ); ++i; }
315 }
316 sblock_vector.swap( new_vector );
317 }
318
319
320 int Logfile::find_index( const long long pos ) const
321 {
322 if( index_ < 0 || index_ >= sblocks() ) index_ = sblocks() / 2;
323 while( index_ + 1 < sblocks() && pos >= sblock_vector[index_].end() )
324 ++index_;
325 while( index_ > 0 && pos < sblock_vector[index_].pos() )
326 --index_;
327 if( !sblock_vector[index_].includes( pos ) ) index_ = -1;
328 return index_;
329 }
330
331
332 int Logfile::find_largest_sblock( const Sblock::Status st,
333 const Domain & domain ) const
334 {
335 long long size = 0;
336 int index = -1;
337 for( int i = 0; i < sblocks(); ++i )
338 {
339 const Sblock & sb = sblock_vector[i];
340 if( sb.status() == st && sb.size() > size && domain.includes( sb ) )
341 { size = sb.size(); index = i; }
342 }
343 return index;
344 }
345
346
347 int Logfile::find_smallest_sblock( const Sblock::Status st,
348 const Domain & domain, const int min_size ) const
349 {
350 long long size = LLONG_MAX;
351 int index = -1;
352 for( int i = 0; i < sblocks(); ++i )
353 {
354 const Sblock & sb = sblock_vector[i];
355 if( sb.status() == st && ( sb.size() < size || index < 0 ) &&
356 domain.includes( sb ) )
357 { size = sb.size(); index = i; if( size <= min_size ) break; }
358 }
359 return index;
360 }
361
362
363 // Find chunk from b.pos of size <= b.size and status st.
364 // If not found, put b.size to 0.
365 //
366 void Logfile::find_chunk( Block & b, const Sblock::Status st,
367 const Domain & domain, const int alignment ) const
368 {
369 if( b.size() <= 0 ) return;
370 if( b.pos() < sblock_vector.front().pos() )
371 b.pos( sblock_vector.front().pos() );
372 if( find_index( b.pos() ) < 0 ) { b.size( 0 ); return; }
373 int i;
374 for( i = index_; i < sblocks(); ++i )
375 if( sblock_vector[i].status() == st && domain.includes( sblock_vector[i] ) )
376 { index_ = i; break; }
377 if( i >= sblocks() ) { b.size( 0 ); return; }
378 if( b.pos() < sblock_vector[index_].pos() )
379 b.pos( sblock_vector[index_].pos() );
380 if( !sblock_vector[index_].includes( b ) )
381 b.crop( sblock_vector[index_] );
382 if( b.end() != sblock_vector[index_].end() )
383 b.align_end( alignment );
384 }
385
386
387 // Find chunk from b.end backwards of size <= b.size and status st.
388 // If not found, put b.size to 0.
389 //
390 void Logfile::rfind_chunk( Block & b, const Sblock::Status st,
391 const Domain & domain, const int alignment ) const
392 {
393 if( b.size() <= 0 ) return;
394 if( sblock_vector.back().end() < b.end() )
395 b.end( sblock_vector.back().end() );
396 if( find_index( b.end() - 1 ) < 0 ) { b.size( 0 ); return; }
397 int i;
398 for( i = index_; i >= 0; --i )
399 if( sblock_vector[i].status() == st && domain.includes( sblock_vector[i] ) )
400 { index_ = i; break; }
401 if( i < 0 ) { b.size( 0 ); return; }
402 if( b.end() > sblock_vector[index_].end() )
403 b.end( sblock_vector[index_].end() );
404 if( !sblock_vector[index_].includes( b ) )
405 b.crop( sblock_vector[index_] );
406 if( b.pos() != sblock_vector[index_].pos() )
407 b.align_pos( alignment );
408 }
409
410
411 // Returns an adjust value (-1, 0, +1) to keep "errors" updated without
412 // having to call count_errors every time.
413 // - - - --> - + - return +1
414 // - - + --> - + + return 0
415 // - + - --> - - - return -1
416 // - + + --> - - + return 0
417 // + - - --> + + - return 0
418 // + - + --> + + + return -1
419 // + + - --> + - - return 0
420 // + + + --> + - + return +1
421 //
422 int Logfile::change_chunk_status( const Block & b, const Sblock::Status st,
423 const Domain & domain )
424 {
425 if( b.size() <= 0 ) return 0;
426 if( !domain.includes( b ) || find_index( b.pos() ) < 0 ||
427 !domain.includes( sblock_vector[index_] ) )
428 internal_error( "can't change status of chunk not in rescue domain." );
429 if( !sblock_vector[index_].includes( b ) )
430 internal_error( "can't change status of chunk spread over more than 1 block." );
431 if( sblock_vector[index_].status() == st ) return 0;
432
433 const bool old_st_good = Sblock::is_good_status( sblock_vector[index_].status() );
434 const bool new_st_good = Sblock::is_good_status( st );
435 bool bl_st_good = ( index_ <= 0 ||
436 !domain.includes( sblock_vector[index_-1] ) ||
437 Sblock::is_good_status( sblock_vector[index_-1].status() ) );
438 bool br_st_good = ( index_ + 1 >= sblocks() ||
439 !domain.includes( sblock_vector[index_+1] ) ||
440 Sblock::is_good_status( sblock_vector[index_+1].status() ) );
441 if( sblock_vector[index_].pos() < b.pos() )
442 {
443 if( sblock_vector[index_].end() == b.end() &&
444 index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st &&
445 domain.includes( sblock_vector[index_+1] ) )
446 {
447 sblock_vector[index_].shift( sblock_vector[index_+1], b.pos() );
448 return 0;
449 }
450 insert_sblock( index_, sblock_vector[index_].split( b.pos() ) );
451 ++index_;
452 bl_st_good = old_st_good;
453 }
454 if( sblock_vector[index_].size() > b.size() )
455 {
456 br_st_good = Sblock::is_good_status( sblock_vector[index_].status() );
457 if( index_ > 0 && sblock_vector[index_-1].status() == st &&
458 domain.includes( sblock_vector[index_-1] ) )
459 sblock_vector[index_-1].shift( sblock_vector[index_], b.end() );
460 else
461 insert_sblock( index_,
462 Sblock( sblock_vector[index_].split( b.end() ), st ) );
463 }
464 else
465 {
466 sblock_vector[index_].status( st );
467 if( index_ > 0 && sblock_vector[index_-1].status() == st &&
468 domain.includes( sblock_vector[index_-1] ) )
469 {
470 sblock_vector[index_-1].join( sblock_vector[index_] );
471 erase_sblock( index_ ); --index_;
472 }
473 if( index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st &&
474 domain.includes( sblock_vector[index_+1] ) )
475 {
476 sblock_vector[index_].join( sblock_vector[index_+1] );
477 erase_sblock( index_ + 1 );
478 }
479 }
480 int retval = 0;
481 if( new_st_good != old_st_good && bl_st_good == br_st_good )
482 { if( old_st_good == bl_st_good ) retval = +1; else retval = -1; }
483 return retval;
484 }
485
486
487 const char * Logfile::status_name( const Logfile::Status st )
488 {
489 switch( st )
490 {
491 case copying: return "copying";
492 case trimming: return "trimming";
493 case splitting: return "splitting";
494 case retrying: return "retrying";
495 case filling: return "filling";
496 case generating: return "generating";
497 case finished: return "finished";
498 }
499 return "unknown"; // should not be reached
500 }
0 /* GNU ddrescue - Data recovery tool
1 Copyright (C) 2013, 2014 Antonio Diaz Diaz.
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #define _FILE_OFFSET_BITS 64
18
19 #include <cstdio>
20 #include <string>
21 #include <vector>
22
23 #include "block.h"
24 #include "loggers.h"
25
26
27 namespace {
28
29 const char * format_time_dhms( const long t )
30 {
31 static char buf[32];
32 const long s = t % 60;
33 const long m = ( t / 60 ) % 60;
34 const long h = ( t / 3600 ) % 24;
35 const long d = t / 86400;
36
37 if( d ) snprintf( buf, sizeof buf, "%lud:%02luh:%02lum:%02lus", d, h, m, s );
38 else if( h ) snprintf( buf, sizeof buf, "%luh:%02lum:%02lus", h, m, s );
39 else if( m ) snprintf( buf, sizeof buf, "%lum:%02lus", m, s );
40 else snprintf( buf, sizeof buf, "%lus", s );
41 return buf;
42 }
43
44 } // end namespace
45
46
47 Rate_logger rate_logger;
48 Read_logger read_logger;
49
50
51 bool Logger::close_file()
52 {
53 if( f && !error && !write_final_timestamp( f ) ) error = true;
54 if( f && std::fclose( f ) != 0 ) error = true;
55 f = 0;
56 return !error;
57 }
58
59
60 bool Rate_logger::open_file()
61 {
62 if( !filename_ ) return true;
63 if( !f )
64 {
65 last_time = -1;
66 f = std::fopen( filename_, "w" );
67 error = !f || !write_logfile_header( f, "Rates" ) ||
68 std::fprintf( f, "#Time Ipos Current_rate Average_rate Errors Errsize\n" ) < 0;
69 }
70 return !error;
71 }
72
73
74 bool Rate_logger::print_line( const long time, const long long ipos,
75 const long long a_rate, const long long c_rate,
76 const int errors, const long long errsize )
77 {
78 if( f && !error && time > last_time )
79 {
80 last_time = time;
81 if( std::fprintf( f, "%2lu 0x%08llX %8llu %8llu %7u %8llu\n",
82 time, ipos, c_rate, a_rate, errors, errsize ) < 0 )
83 error = true;
84 }
85 return !error;
86 }
87
88
89 bool Read_logger::open_file()
90 {
91 if( !filename_ ) return true;
92 if( !f )
93 {
94 prev_is_msg = true;
95 f = std::fopen( filename_, "w" );
96 error = !f || !write_logfile_header( f, "Reads" ) ||
97 std::fprintf( f, "# Ipos Size Copied_size Error_size\n" ) < 0;
98 }
99 return !error;
100 }
101
102
103 bool Read_logger::print_line( const long long ipos, const long long size,
104 const int copied_size, const int error_size )
105 {
106 if( f && !error &&
107 std::fprintf( f, "0x%08llX %llu %u %u\n",
108 ipos, size, copied_size, error_size ) < 0 )
109 error = true;
110 prev_is_msg = false;
111 return !error;
112 }
113
114
115 bool Read_logger::print_msg( const long time, const char * const msg )
116 {
117 if( f && !error &&
118 std::fprintf( f, "%s# %s %s\n", prev_is_msg ? "" : "\n\n",
119 format_time_dhms( time ), msg ) < 0 )
120 error = true;
121 prev_is_msg = true;
122 return !error;
123 }
124
125
126 bool Read_logger::print_time( const long time )
127 {
128 if( f && !error && time > 0 &&
129 std::fprintf( f, "# %s\n", format_time_dhms( time ) ) < 0 )
130 error = true;
131 return !error;
132 }
0 /* GNU ddrescue - Data recovery tool
1 Copyright (C) 2013, 2014 Antonio Diaz Diaz.
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 class Logger
18 {
19 protected:
20 const char * filename_;
21 FILE * f; // output stream
22 bool error;
23
24 public:
25 Logger() : f( 0 ), error( false ) {}
26
27 void set_filename( const char * const name ) { filename_ = name; }
28 bool close_file();
29 };
30
31
32 class Rate_logger : public Logger
33 {
34 long last_time;
35 public:
36 Rate_logger() : last_time( -1 ) {}
37 bool open_file();
38 bool print_line( const long time, const long long ipos,
39 const long long a_rate, const long long c_rate,
40 const int errors, const long long errsize );
41 };
42
43 extern Rate_logger rate_logger;
44
45
46 class Read_logger : public Logger
47 {
48 bool prev_is_msg;
49 public:
50 Read_logger() : prev_is_msg( true ) {}
51 bool open_file();
52 bool print_line( const long long ipos, const long long size,
53 const int copied_size, const int error_size );
54 bool print_msg( const long time, const char * const msg );
55 bool print_time( const long time );
56 };
57
58 extern Read_logger read_logger;
+188
-113
main.cc less more
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
2323
2424 #define _FILE_OFFSET_BITS 64
2525
26 #include <algorithm>
2627 #include <cerrno>
2728 #include <climits>
2829 #include <cstdio>
2930 #include <cstdlib>
3031 #include <cstring>
32 #include <ctime>
3133 #include <string>
3234 #include <vector>
3335 #include <fcntl.h>
3941 #include "rational.h"
4042 #include "block.h"
4143 #include "ddrescue.h"
44 #include "loggers.h"
45
46 #ifndef O_BINARY
47 #define O_BINARY 0
48 #endif
4249
4350 #ifndef O_DIRECT
4451 #define O_DIRECT 0
5461 enum Mode { m_none, m_fill, m_generate };
5562 const mode_t outmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
5663
57 #ifdef O_BINARY
58 const int o_binary = O_BINARY;
59 #else
60 const int o_binary = 0;
61 #endif
62
6364
6465 void show_help( const int cluster, const int hardbs, const int skipbs )
6566 {
6667 std::printf( "%s - Data recovery tool.\n", Program_name );
6768 std::printf( "Copies data from one file or block device to another,\n"
68 "trying hard to rescue data in case of read errors.\n"
69 "trying to rescue the good parts first in case of read errors.\n"
6970 "\nUsage: %s [options] infile outfile [logfile]\n", invocation_name );
7071 std::printf( "You should use a logfile unless you know what you are doing.\n"
7172 "If you reboot, check the device names before restarting ddrescue.\n"
72 "Do not use options '-F' or '-g' without reading the manual first.\n"
73 "Do not use options '-F' or '-G' without reading the manual first.\n"
7374 "\nOptions:\n"
7475 " -h, --help display this help and exit\n"
7576 " -V, --version output version information and exit\n"
8586 " -E, --max-error-rate=<bytes> maximum allowed rate of read errors per second\n"
8687 " -f, --force overwrite output device or partition\n"
8788 " -F, --fill-mode=<types> fill given type blocks with infile data (?*/-+)\n"
88 " -g, --generate-mode generate approximate logfile from partial copy\n"
89 " -G, --generate-mode generate approximate logfile from partial copy\n"
90 " -H, --test-mode=<file> set map of good/bad blocks from given logile\n"
8991 " -i, --input-position=<bytes> starting position in input file [0]\n"
9092 " -I, --verify-input-size verify input file size with size in logfile\n"
91 " -K, --skip-size=<bytes> initial size to skip on read error [%sB]\n",
93 " -K, --skip-size=<min>[,<max>] initial size to skip on read error [%sB]\n",
9294 format_num( skipbs, 9999, -1 ) );
93 std::printf( " -l, --logfile-size=<entries> do not grow logfile beyond this size [1000]\n"
95 std::printf( " -l, --logfile-size=<entries> do not grow logfile beyond this size [10000]\n"
96 " -L, --loose-domain accept an incomplete domain logfile\n"
9497 " -m, --domain-logfile=<file> restrict domain to finished blocks in file\n"
9598 " -M, --retrim mark all failed blocks as non-trimmed\n"
96 " -n, --no-split do not try to split or retry failed blocks\n"
99 " -n, --no-split skip the splitting phase\n"
100 " -N, --no-trim skip the trimming phase\n"
97101 " -o, --output-position=<bytes> starting position in output file [ipos]\n"
102 " -O, --reopen-on-error reopen input file after every read error\n"
98103 " -p, --preallocate preallocate space on disc for output file\n"
99104 " -q, --quiet suppress all messages\n"
100 " -r, --retries=<n> exit after given retries (-1=infinity) [0]\n"
101 " -R, --reverse reverse direction of copy operations\n"
105 " -r, --retry-passes=<n> exit after <n> retry passes (-1=infinity) [0]\n"
106 " -R, --reverse reverse direction of some copy operations\n"
102107 " -s, --size=<bytes> maximum size of input data to be copied\n"
103108 " -S, --sparse use sparse writes for output file\n"
104109 " -t, --truncate truncate output file to zero size\n"
106111 " -v, --verbose be verbose (a 2nd -v gives more)\n"
107112 " -w, --ignore-write-errors make fill mode ignore write errors\n"
108113 " -x, --extend-outfile=<bytes> extend outfile size to be at least this long\n"
109 "Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,\n"
110 "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
114 " -1, --log-rates=<file> log rates and error sizes in file\n"
115 " -2, --log-reads=<file> log all read operations in file\n"
116 "Numbers may be in decimal, hexadecimal or octal, and may be followed by a\n"
117 "multiplier: s = sectors, k = 1000, Ki = 1024, M = 10^6, Mi = 2^20, etc...\n"
111118 "Time intervals have the format 1[.5][smhd] or 1/2[smhd].\n"
112119 "\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
113120 "not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
233240
234241 Fillbook fillbook( offset, domain, logname, cluster, hardbs,
235242 ignore_write_errors, synchronous );
236 if( fillbook.domain().size() == 0 )
237 { show_error( "Nothing to do." ); return 0; }
238
239 const int ides = open( iname, O_RDONLY | o_binary );
243 if( !fillbook.logfile_exists() ) return not_readable( logname );
244 if( fillbook.domain().empty() ) return empty_domain();
245 if( fillbook.read_only() ) return not_writable( logname );
246
247 const int ides = open( iname, O_RDONLY | O_BINARY );
240248 if( ides < 0 )
241249 { show_error( "Can't open input file", errno ); return 1; }
242250 if( !fillbook.read_buffer( ides ) )
243251 { show_error( "Error reading fill data from input file." ); return 1; }
244252
245 const int odes = open( oname, O_CREAT | O_WRONLY | o_binary, outmode );
253 const int odes = open( oname, O_CREAT | O_WRONLY | O_BINARY, outmode );
246254 if( odes < 0 )
247255 { show_error( "Can't open output file", errno ); return 1; }
248256 if( lseek( odes, 0, SEEK_SET ) )
256264 iname, oname, filltypes.c_str() );
257265 std::printf( " Maximum size to fill: %sBytes\n",
258266 format_num( fillbook.domain().in_size() ) );
259 std::printf( " Starting positions: infile = %sB",
260 format_num( fillbook.domain().pos() ) );
261 std::printf( ", outfile = %sB\n",
267 std::printf( " Starting positions: infile = %sB, outfile = %sB\n",
268 format_num( fillbook.domain().pos() ),
262269 format_num( fillbook.domain().pos() + fillbook.offset() ) );
263270 std::printf( " Copy block size: %3d sectors\n", cluster );
264271 std::printf( "Sector size: %sBytes\n\n", format_num( hardbs, 99999 ) );
279286 return 1;
280287 }
281288
282 const int ides = open( iname, O_RDONLY | o_binary );
289 const int ides = open( iname, O_RDONLY | O_BINARY );
283290 if( ides < 0 )
284291 { show_error( "Can't open input file", errno ); return 1; }
285292 const long long isize = lseek( ides, 0, SEEK_END );
287294 { show_error( "Input file is not seekable." ); return 1; }
288295
289296 Genbook genbook( offset, isize, domain, logname, cluster, hardbs );
290 if( genbook.domain().size() == 0 )
291 { show_error( "Nothing to do." ); return 0; }
297 if( genbook.domain().empty() ) return empty_domain();
292298 if( !genbook.blank() && genbook.current_status() != Logbook::generating )
293299 {
294300 show_error( "Logfile alredy exists and is non-empty.", 0, true );
295301 return 1;
296302 }
297
298 const int odes = open( oname, O_RDONLY | o_binary );
303 if( genbook.read_only() ) return not_writable( logname );
304
305 const int odes = open( oname, O_RDONLY | O_BINARY );
299306 if( odes < 0 )
300307 { show_error( "Can't open output file", errno ); return 1; }
301308 if( lseek( odes, 0, SEEK_SET ) )
307314 {
308315 std::printf( "About to generate an approximate logfile for %s and %s\n",
309316 iname, oname );
310 std::printf( " Starting positions: infile = %sB",
311 format_num( genbook.domain().pos() ) );
312 std::printf( ", outfile = %sB\n",
317 std::printf( " Starting positions: infile = %sB, outfile = %sB\n",
318 format_num( genbook.domain().pos() ),
313319 format_num( genbook.domain().pos() + genbook.offset() ) );
314320 std::printf( " Copy block size: %3d sectors\n", cluster );
315321 std::printf( "Sector size: %sBytes\n\n", format_num( hardbs, 99999 ) );
319325
320326
321327 int do_rescue( const long long offset, Domain & domain,
322 const Rb_options & rb_opts,
328 const Domain * const test_domain, const Rb_options & rb_opts,
323329 const char * const iname, const char * const oname,
324330 const char * const logname, const int cluster,
325 const int hardbs, const int o_direct, const int o_trunc,
326 const bool preallocate, const bool reverse,
327 const bool synchronous, const bool verify_input_size )
328 {
329 const int ides = open( iname, O_RDONLY | o_direct | o_binary );
331 const int hardbs, const int o_trunc,
332 const bool preallocate, const bool synchronous,
333 const bool verify_input_size )
334 {
335 const int ides = open( iname, O_RDONLY | rb_opts.o_direct | O_BINARY );
330336 if( ides < 0 )
331337 { show_error( "Can't open input file", errno ); return 1; }
332 const long long isize = lseek( ides, 0, SEEK_END );
338 long long isize = lseek( ides, 0, SEEK_END );
333339 if( isize < 0 )
334340 { show_error( "Input file is not seekable." ); return 1; }
335
336 Rescuebook rescuebook( offset, isize, domain, rb_opts, iname, logname,
337 cluster, hardbs, synchronous );
341 if( test_domain )
342 { const long long size = test_domain->end();
343 if( isize <= 0 || isize > size ) isize = size; }
344
345 Rescuebook rescuebook( offset, isize, domain, test_domain, rb_opts, iname,
346 logname, cluster, hardbs, synchronous );
338347
339348 if( verify_input_size )
340349 {
352361 return 1;
353362 }
354363 }
355 if( rescuebook.domain().size() == 0 )
356 {
357 if( rb_opts.complete_only )
364 if( rescuebook.domain().empty() )
365 {
366 if( rescuebook.complete_only && !rescuebook.logfile_exists() )
358367 { show_error( "Nothing to complete; logfile is missing or empty.", 0, true );
359368 return 1; }
360 show_error( "Nothing to do." ); return 0;
369 return empty_domain();
361370 }
362371 if( o_trunc && !rescuebook.blank() )
363372 {
364373 show_error( "Outfile truncation and logfile input are incompatible.", 0, true );
365374 return 1;
366375 }
367
368 const int odes = open( oname, O_CREAT | O_WRONLY | o_trunc | o_binary,
376 if( rescuebook.read_only() ) return not_writable( logname );
377
378 const int odes = open( oname, O_CREAT | O_WRONLY | o_trunc | O_BINARY,
369379 outmode );
370380 if( odes < 0 )
371381 { show_error( "Can't open output file", errno ); return 1; }
372382 if( lseek( odes, 0, SEEK_SET ) )
373383 { show_error( "Output file is not seekable." ); return 1; }
374 while( preallocate )
384 if( preallocate )
375385 {
376386 #if defined _POSIX_ADVISORY_INFO && _POSIX_ADVISORY_INFO > 0
377387 if( posix_fallocate( odes, rescuebook.domain().pos() + rescuebook.offset(),
378 rescuebook.domain().size() ) == 0 ) break;
379 if( errno != EINTR )
388 rescuebook.domain().size() ) != 0 )
380389 { show_error( "Can't preallocate output file", errno ); return 1; }
381390 #else
382 show_error( "warning: Preallocation not available." ); break;
391 show_error( "warning: Preallocation not available." );
383392 #endif
384393 }
385
386 if( !rescuebook.update_logfile( -1, true ) ) return 1;
394 if( !rate_logger.open_file() )
395 { show_error( "Can't open file for logging rates", errno ); return 1; }
396 if( !read_logger.open_file() )
397 { show_error( "Can't open file for logging reads", errno ); return 1; }
387398
388399 if( verbosity >= 0 )
389400 std::printf( "\n\n%s %s\n", Program_name, PROGVERSION );
390401 if( verbosity >= 1 )
391402 {
392 std::printf( "About to copy %sBytes from %s to %s\n",
393 format_num( rescuebook.domain().in_size() ), iname, oname );
394 std::printf( " Starting positions: infile = %sB",
395 format_num( rescuebook.domain().pos() ) );
396 std::printf( ", outfile = %sB\n",
403 if( rescuebook.domain().full() )
404 std::printf( "About to copy an unknown number of bytes from %s to %s\n",
405 iname, oname );
406 else
407 std::printf( "About to copy %sBytes from %s to %s\n",
408 format_num( rescuebook.domain().in_size() ), iname, oname );
409 std::printf( " Starting positions: infile = %sB, outfile = %sB\n",
410 format_num( rescuebook.domain().pos() ),
397411 format_num( rescuebook.domain().pos() + rescuebook.offset() ) );
398412 std::printf( " Copy block size: %3d sectors", cluster );
399 std::printf( " Initial skip size: %d sectors\n",
400 rb_opts.skipbs / hardbs );
413 if( rescuebook.skipbs > 0 )
414 std::printf( " Initial skip size: %d sectors\n",
415 rescuebook.skipbs / hardbs );
416 else
417 std::printf( " Skipping disabled\n" );
401418 std::printf( "Sector size: %sBytes\n", format_num( hardbs, 99999 ) );
402419 if( verbosity >= 2 )
403420 {
404421 bool nl = false;
405 if( rb_opts.max_error_rate >= 0 )
406 { nl = true; std::printf( "Max error rate: %8sB/s ",
407 format_num( rb_opts.max_error_rate, 99999 ) ); }
408 if( rb_opts.max_errors >= 0 )
422 if( rescuebook.max_error_rate >= 0 )
423 { nl = true; std::printf( "Max error rate: %6sB/s ",
424 format_num( rescuebook.max_error_rate, 99999 ) ); }
425 if( rescuebook.max_errors >= 0 )
409426 {
410427 nl = true;
411 std::printf( "Max %serrors: %d ",
412 rb_opts.new_errors_only ? "new " : "", rb_opts.max_errors );
428 std::printf( "Max %serrors: %d ", rescuebook.new_errors_only ?
429 "new " : "", rescuebook.max_errors );
413430 }
414 if( rb_opts.max_retries >= 0 )
415 { nl = true; std::printf( "Max retries: %d ", rb_opts.max_retries ); }
431 if( rescuebook.max_retries >= 0 )
432 { nl = true;
433 std::printf( "Max retry passes: %d ", rescuebook.max_retries ); }
416434 if( nl ) { nl = false; std::printf( "\n" ); }
417435
418 if( rb_opts.min_read_rate >= 0 )
419 { nl = true; std::printf( "Min read rate: %8sB/s ",
420 format_num( rb_opts.min_read_rate, 99999 ) ); }
421 if( rb_opts.timeout >= 0 )
436 if( rescuebook.min_read_rate == 0 )
437 { nl = true; std::printf( "Min read rate: auto " ); }
438 else if( rescuebook.min_read_rate > 0 )
439 { nl = true; std::printf( "Min read rate: %6sB/s ",
440 format_num( rescuebook.min_read_rate, 99999 ) ); }
441 if( rescuebook.timeout >= 0 )
422442 { nl = true; std::printf( "Max time since last successful read: %s",
423 format_time( rb_opts.timeout ) ); }
443 format_time( rescuebook.timeout ) ); }
424444 if( nl ) { nl = false; std::printf( "\n" ); }
425445
426 std::printf( "Direct: %s ", o_direct ? "yes" : "no" );
427 std::printf( "Sparse: %s ", rb_opts.sparse ? "yes" : "no" );
428 std::printf( "Split: %s ", !rb_opts.nosplit ? "yes" : "no" );
446 std::printf( "Direct: %s ", rescuebook.o_direct ? "yes" : "no" );
447 std::printf( "Sparse: %s ", rescuebook.sparse ? "yes" : "no" );
448 std::printf( "Split: %s ", !rescuebook.nosplit ? "yes" : "no" );
449 std::printf( "Trim: %s ", !rescuebook.notrim ? "yes" : "no" );
429450 std::printf( "Truncate: %s ", o_trunc ? "yes" : "no" );
430 if( rb_opts.complete_only ) std::printf( "Complete only" );
431451 std::printf( "\n" );
432 if( reverse ) std::printf( "Reverse mode\n" );
452 if( rescuebook.complete_only )
453 { nl = true; std::printf( "Complete only " ); }
454 if( rescuebook.reverse ) { nl = true; std::printf( "Reverse mode" ); }
455 if( nl ) { nl = false; std::printf( "\n" ); }
433456 }
434457 std::printf( "\n" );
435458 }
436 return rescuebook.do_rescue( ides, odes, reverse );
459 return rescuebook.do_rescue( ides, odes );
437460 }
438461
439462 } // end namespace
440463
441464
442465 #include "main_common.cc"
466
467
468 namespace {
469
470 void parse_skipbs( const char * const arg, Rb_options & rb_opts,
471 const int hardbs )
472 {
473 const char * const arg2 = std::strchr( arg, ',' );
474
475 if( !arg2 || arg2 != arg )
476 rb_opts.skipbs = getnum( arg, hardbs, 0, Rb_options::max_max_skipbs, true );
477 if( arg2 )
478 rb_opts.max_skipbs = getnum( arg2 + 1, hardbs, Rb_options::default_skipbs,
479 Rb_options::max_max_skipbs );
480 if( rb_opts.skipbs > 0 && rb_opts.skipbs < Rb_options::default_skipbs )
481 {
482 show_error( "Minimum initial skip size is 64KiB." );
483 std::exit( 1 );
484 }
485 if( rb_opts.skipbs > rb_opts.max_skipbs )
486 {
487 show_error( "'initial skip size' is larger than 'max skip size'." );
488 std::exit( 1 );
489 }
490 }
491
492 } // end namespace
493
494
495 bool Rescuebook::reopen_infile()
496 {
497 if( ides_ >= 0 ) close( ides_ );
498 ides_ = open( iname_, O_RDONLY | o_direct | O_BINARY );
499 if( ides_ < 0 )
500 { final_msg( "Can't reopen input file", errno ); return false; }
501 const long long isize = lseek( ides_, 0, SEEK_END );
502 if( isize < 0 )
503 { final_msg( "Input file has become not seekable", errno ); return false; }
504 return true;
505 }
443506
444507
445508 int main( const int argc, const char * const argv[] )
448511 long long opos = -1;
449512 long long max_size = -1;
450513 const char * domain_logfile_name = 0;
514 const char * test_mode_logfile_name = 0;
451515 const int cluster_bytes = 65536;
452516 const int default_hardbs = 512;
453 const int max_hardbs = Rb_options::max_skipbs;
517 const int max_hardbs = Rb_options::max_max_skipbs;
454518 int cluster = 0;
455519 int hardbs = default_hardbs;
456 int o_direct = 0;
457520 int o_trunc = 0;
458521 Mode program_mode = m_none;
459 struct Rb_options rb_opts;
522 Rb_options rb_opts;
460523 bool force = false;
461524 bool ignore_write_errors = false;
525 bool loose = false;
462526 bool preallocate = false;
463 bool reverse = false;
464527 bool synchronous = false;
465528 bool verify_input_size = false;
466529 std::string filltypes;
468531 command_line = argv[0];
469532 for( int i = 1; i < argc; ++i )
470533 { command_line += ' '; command_line += argv[i]; }
534 initial_time_ = std::time( 0 );
471535
472536 const Arg_parser::Option options[] =
473537 {
538 { '1', "log-rates", Arg_parser::yes },
539 { '2', "log-reads", Arg_parser::yes },
474540 { 'a', "min-read-rate", Arg_parser::yes },
475541 { 'A', "try-again", Arg_parser::no },
476542 { 'b', "block-size", Arg_parser::yes },
484550 { 'E', "max-error-rate", Arg_parser::yes },
485551 { 'f', "force", Arg_parser::no },
486552 { 'F', "fill-mode", Arg_parser::yes },
487 { 'g', "generate-mode", Arg_parser::no },
553 { 'G', "generate-mode", Arg_parser::no },
488554 { 'h', "help", Arg_parser::no },
555 { 'H', "test-mode", Arg_parser::yes },
489556 { 'i', "input-position", Arg_parser::yes },
490557 { 'I', "verify-input-size", Arg_parser::no },
491558 { 'K', "skip-size", Arg_parser::yes },
492559 { 'l', "logfile-size", Arg_parser::yes },
560 { 'L', "loose-domain", Arg_parser::no },
493561 { 'm', "domain-logfile", Arg_parser::yes },
494562 { 'M', "retrim", Arg_parser::no },
495563 { 'n', "no-split", Arg_parser::no },
564 { 'N', "no-trim", Arg_parser::no },
496565 { 'o', "output-position", Arg_parser::yes },
566 { 'O', "reopen-on-error", Arg_parser::no },
497567 { 'p', "preallocate", Arg_parser::no },
498568 { 'q', "quiet", Arg_parser::no },
499 { 'r', "retries", Arg_parser::yes },
500 { 'r', "max-retries", Arg_parser::yes },
569 { 'r', "retry-passes", Arg_parser::yes },
501570 { 'R', "reverse", Arg_parser::no },
502571 { 's', "size", Arg_parser::yes },
503572 { 's', "max-size", Arg_parser::yes },
522591 const char * const arg = parser.argument( argind ).c_str();
523592 switch( code )
524593 {
594 case '1': rate_logger.set_filename( arg ); break;
595 case '2': read_logger.set_filename( arg ); break;
525596 case 'a': rb_opts.min_read_rate = getnum( arg, hardbs, 0 ); break;
526597 case 'A': rb_opts.try_again = true; break;
527598 case 'b': hardbs = getnum( arg, 0, 1, max_hardbs ); break;
528599 case 'B': format_num( 0, 0, -1 ); break; // set binary prefixes
529600 case 'c': cluster = getnum( arg, 0, 1, INT_MAX ); break;
530601 case 'C': rb_opts.complete_only = true; break;
531 case 'd': o_direct = O_DIRECT;
532 if( !o_direct )
602 case 'd': rb_opts.o_direct = O_DIRECT;
603 if( rb_opts.o_direct == 0 )
533604 { show_error( "Direct disc access not available." ); return 1; }
534605 break;
535606 case 'D': synchronous = true; break;
539610 case 'f': force = true; break;
540611 case 'F': set_mode( program_mode, m_fill ); filltypes = arg;
541612 check_types( filltypes, "fill-mode" ); break;
542 case 'g': set_mode( program_mode, m_generate ); break;
613 case 'G': set_mode( program_mode, m_generate ); break;
543614 case 'h': show_help( cluster_bytes / default_hardbs, default_hardbs,
544615 Rb_options::default_skipbs );
545616 return 0;
617 case 'H': set_name( &test_mode_logfile_name, arg, code ); break;
546618 case 'i': ipos = getnum( arg, hardbs, 0 ); break;
547619 case 'I': verify_input_size = true; break;
548 case 'K': rb_opts.skipbs = getnum( arg, hardbs, Rb_options::default_skipbs,
549 Rb_options::max_skipbs ); break;
620 case 'K': parse_skipbs( arg, rb_opts, hardbs ); break;
550621 case 'l': rb_opts.max_logfile_size = getnum( arg, 0, 1, INT_MAX ); break;
551 case 'm': set_name( &domain_logfile_name, arg ); break;
622 case 'L': loose = true; break;
623 case 'm': set_name( &domain_logfile_name, arg, code ); break;
552624 case 'M': rb_opts.retrim = true; break;
553625 case 'n': rb_opts.nosplit = true; break;
626 case 'N': rb_opts.notrim = true; break;
554627 case 'o': opos = getnum( arg, hardbs, 0 ); break;
628 case 'O': rb_opts.reopen_on_error = true; break;
555629 case 'p': preallocate = true; break;
556630 case 'q': verbosity = -1; break;
557631 case 'r': rb_opts.max_retries = getnum( arg, 0, -1, INT_MAX ); break;
558 case 'R': reverse = true; break;
632 case 'R': rb_opts.reverse = true; break;
559633 case 's': max_size = getnum( arg, hardbs, -1 ); break;
560634 case 'S': rb_opts.sparse = true; break;
561635 case 't': o_trunc = O_TRUNC; break;
564638 case 'V': show_version(); return 0;
565639 case 'w': ignore_write_errors = true; break;
566640 case 'x': rb_opts.min_outfile_size = getnum( arg, hardbs, 1 ); break;
567 default : internal_error( "uncaught option" );
641 default : internal_error( "uncaught option." );
568642 }
569643 } // end process options
570644
573647 if( cluster >= INT_MAX / hardbs ) cluster = ( INT_MAX / hardbs ) - 1;
574648 if( cluster < 1 ) cluster = cluster_bytes / hardbs;
575649 if( cluster < 1 ) cluster = 1;
576 if( rb_opts.skipbs < hardbs )
577 rb_opts.skipbs = hardbs;
578 else // make multiple of hardbs
579 rb_opts.skipbs = round_up( rb_opts.skipbs, hardbs );
580650
581651 const char *iname = 0, *oname = 0, *logname = 0;
582652 if( argind < parser.arguments() ) iname = parser.argument( argind++ ).c_str();
591661 program_mode == m_generate, preallocate, rb_opts.sparse ) )
592662 return 1;
593663
594 Domain domain( ipos, max_size, domain_logfile_name );
664 Domain domain( ipos, max_size, domain_logfile_name, loose );
595665
596666 switch( program_mode )
597667 {
598668 case m_fill:
599 if( rb_opts != Rb_options() || o_direct ||
600 verify_input_size || preallocate || reverse || o_trunc )
601 show_error( "warning: Options -aCdeEIMnOprRStTx are ignored in fill mode." );
669 if( rb_opts != Rb_options() || test_mode_logfile_name ||
670 verify_input_size || preallocate || o_trunc )
671 show_error( "warning: Options -aACdeEHIKlMnOprRStTx are ignored in fill mode." );
602672 return do_fill( opos - ipos, domain, iname, oname, logname, cluster,
603673 hardbs, filltypes, ignore_write_errors, synchronous );
604674 case m_generate:
605 if( rb_opts != Rb_options() || o_direct || synchronous ||
606 verify_input_size || preallocate || reverse || o_trunc ||
607 ignore_write_errors )
608 show_error( "warning: Options -aCdDeEIMnOprRStTwx are ignored in generate mode." );
675 if( rb_opts != Rb_options() || synchronous || test_mode_logfile_name ||
676 verify_input_size || preallocate || o_trunc || ignore_write_errors )
677 show_error( "warning: Options -aACdDeEHIKlMnOprRStTwx are ignored in generate mode." );
609678 return do_generate( opos - ipos, domain, iname, oname, logname,
610679 cluster, hardbs );
611680 case m_none:
681 {
612682 if( ignore_write_errors )
613683 { show_error( "Option '-w' is incompatible with rescue mode.", 0, true );
614684 return 1; }
615 return do_rescue( opos - ipos, domain, rb_opts, iname, oname, logname,
616 cluster, hardbs, o_direct, o_trunc, preallocate,
617 reverse, synchronous, verify_input_size );
618 }
619 }
685 const Domain * const test_domain = test_mode_logfile_name ?
686 new Domain( 0, -1, test_mode_logfile_name, loose ) : 0;
687 int tmp = do_rescue( opos - ipos, domain, test_domain, rb_opts, iname,
688 oname, logname, cluster, hardbs, o_trunc,
689 preallocate, synchronous, verify_input_size );
690 if( test_domain ) delete test_domain;
691 return tmp;
692 }
693 }
694 }
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1717
1818 namespace {
1919
20 const char * const program_year = "2013";
20 const char * const program_year = "2014";
2121 std::string command_line;
22 long initial_time_;
2223
2324
2425 void show_version()
2526 {
26 std::printf( "%s %s\n", Program_name, PROGVERSION );
27 std::printf( "GNU %s %s\n", program_name, PROGVERSION );
2728 std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
2829 std::printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
2930 "This is free software: you are free to change and redistribute it.\n"
3334
3435 long long getnum( const char * const ptr, const int hardbs,
3536 const long long min = LLONG_MIN + 1,
36 const long long max = LLONG_MAX )
37 const long long max = LLONG_MAX, const bool comma = false )
3738 {
3839 errno = 0;
39 char *tail;
40 char * tail;
4041 long long result = strtoll( ptr, &tail, 0 );
4142 if( tail == ptr )
4243 {
5253 switch( tail[0] )
5354 {
5455 case ' ': break;
56 case ',': if( !comma ) { bad_multiplier = true; } break;
5557 case 'b':
5658 case 's': if( hardbs > 0 ) { factor = hardbs; exponent = 1; }
5759 else bad_multiplier = true;
117119 }
118120
119121
120 void set_name( const char ** domain_logfile_name, const char * new_name )
121 {
122 if( *domain_logfile_name )
123 {
124 show_error( "Only one domain logfile can be specified.", 0, true );
125 std::exit( 1 );
126 }
127 *domain_logfile_name = new_name;
122 void set_name( const char ** name, const char * new_name, const char opt )
123 {
124 if( *name )
125 {
126 std::string msg( "Option '- ' can be specified only once." );
127 msg[9] = opt;
128 show_error( msg.c_str(), 0, true );
129 std::exit( 1 );
130 }
131 *name = new_name;
132 }
133
134
135 const char * get_timestamp( const long t = 0 )
136 {
137 static char buf[80];
138 const time_t tt = t ? t : std::time( 0 );
139 const struct tm * const tm = std::localtime( &tt );
140 if( !tm || std::strftime( buf, sizeof buf, "%Y-%m-%d %H:%M:%S", tm ) == 0 )
141 buf[0] = 0;
142 return buf;
128143 }
129144
130145 } // end namespace
154169 void internal_error( const char * const msg )
155170 {
156171 if( verbosity >= 0 )
157 std::fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
172 std::fprintf( stderr, "%s: internal error: %s\n", program_name, msg );
158173 std::exit( 3 );
159174 }
160175
161176
162 void write_logfile_header( FILE * const f )
163 {
164 std::fprintf( f, "# Rescue Logfile. Created by %s version %s\n",
165 Program_name, PROGVERSION );
166 std::fprintf( f, "# Command line: %s\n", command_line.c_str() );
177 int empty_domain() { show_error( "Empty domain." ); return 0; }
178
179
180 int not_readable( const char * const logname )
181 {
182 char buf[80];
183 snprintf( buf, sizeof buf,
184 "Logfile '%s' does not exist or is not readable.", logname );
185 show_error( buf );
186 return 1;
187 }
188
189
190 int not_writable( const char * const logname )
191 {
192 char buf[80];
193 snprintf( buf, sizeof buf, "Logfile '%s' is not writable.", logname );
194 show_error( buf );
195 return 1;
196 }
197
198
199 long initial_time() { return initial_time_; }
200
201
202 bool write_logfile_header( FILE * const f, const char * const logtype )
203 {
204 static std::string timestamp;
205
206 if( timestamp.empty() ) timestamp = get_timestamp( initial_time_ );
207 return ( std::fprintf( f, "# %s Logfile. Created by %s version %s\n"
208 "# Command line: %s\n"
209 "# Start time: %s\n",
210 logtype, Program_name, PROGVERSION, command_line.c_str(),
211 timestamp.c_str() ) >= 0 );
212 }
213
214
215 bool write_timestamp( FILE * const f )
216 {
217 const char * const timestamp = get_timestamp();
218
219 return ( !timestamp || !timestamp[0] ||
220 std::fprintf( f, "# Current time: %s\n", timestamp ) >= 0 );
221 }
222
223
224 bool write_final_timestamp( FILE * const f )
225 {
226 static std::string timestamp;
227
228 if( timestamp.empty() ) timestamp = get_timestamp();
229 return ( std::fprintf( f, "# End time: %s\n", timestamp.c_str() ) >= 0 );
167230 }
168231
169232
174237 { "k", "M", "G", "T", "P", "E", "Z", "Y" };
175238 const char * const binary_prefix[8] =
176239 { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
240 enum { buffers = 8, bufsize = 16 };
241 static char buffer[buffers][bufsize]; // circle of static buffers for printf
242 static int current = 0;
177243 static bool si = true;
178 static char buf[16];
179244
180245 if( set_prefix ) si = ( set_prefix > 0 );
181 const int factor = ( si ? 1000 : 1024 );
182 const char * const * prefix = ( si ? si_prefix : binary_prefix );
246 const int factor = si ? 1000 : 1024;
247 char * const buf = buffer[current++]; current %= buffers;
248 const char * const * prefix = si ? si_prefix : binary_prefix;
183249 const char * p = "";
184250 limit = std::max( 999LL, std::min( 999999LL, limit ) );
185251
186252 for( int i = 0; i < 8 && llabs( num ) > limit; ++i )
187253 { num /= factor; p = prefix[i]; }
188 snprintf( buf, sizeof buf, "%lld %s", num, p );
254 snprintf( buf, bufsize, "%lld %s", num, p );
189255 return buf;
190256 }
00 /* Rational - Rational number class with overflow detection.
1 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
2 Antonio Diaz Diaz.
1 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
2 2014 Antonio Diaz Diaz.
33
44 This library is free software: you have unlimited permission to
55 copy, distribute and modify it.
00 /* Rational - Rational number class with overflow detection.
1 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
2 Antonio Diaz Diaz.
1 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
2 2014 Antonio Diaz Diaz.
33
44 This library is free software: you have unlimited permission to
55 copy, distribute and modify it.
00 /* GNU ddrescue - Data recovery tool
11 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2 2013 Antonio Diaz Diaz.
2 2013, 2014 Antonio Diaz Diaz.
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1717
1818 #define _FILE_OFFSET_BITS 64
1919
20 #include <algorithm>
2021 #include <cerrno>
2122 #include <climits>
2223 #include <cstdio>
2324 #include <cstring>
25 #include <ctime>
2426 #include <string>
2527 #include <vector>
2628 #include <stdint.h>
2830
2931 #include "block.h"
3032 #include "ddrescue.h"
31
32
33 namespace {
34
35 int calculate_max_skip_size( const long long isize,
36 const int hardbs, const int skipbs )
37 {
38 int skip;
39
40 if( isize > 0 && isize / 100 < Rb_options::max_skipbs ) skip = isize / 100;
41 else skip = Rb_options::max_skipbs;
42 if( skip < hardbs || skip < skipbs ) skip = skipbs;
43 return round_up( skip, hardbs );
44 }
45
46 } // end namespace
33 #include "loggers.h"
4734
4835
4936 void Rescuebook::count_errors()
6855 }
6956
7057
58 // Return values: 1 error, 0 OK.
59 //
60 int Rescuebook::update( const Block & b, const Sblock::Status st,
61 const int copied_size, const int error_size )
62 {
63 int retval = 0;
64 if( copied_size + error_size < b.size() ) // EOF
65 {
66 if( complete_only ) truncate_domain( b.pos() + copied_size + error_size );
67 else if( !truncate_vector( b.pos() + copied_size + error_size ) )
68 { final_msg( "EOF found before end of logfile" ); retval = 1; }
69 }
70 if( copied_size > 0 )
71 {
72 errors += change_chunk_status( Block( b.pos(), copied_size ),
73 Sblock::finished, domain() );
74 recsize += copied_size;
75 }
76 if( error_size > 0 )
77 {
78 errors += change_chunk_status( Block( b.pos() + copied_size, error_size ),
79 ( error_size > hardbs() ) ? st : Sblock::bad_sector, domain() );
80 if( access_works && access( iname_, F_OK ) != 0 )
81 { final_msg( "Input file disappeared", errno ); retval = 1; }
82 }
83 return retval;
84 }
85
86
7187 // Return values: 1 I/O error, 0 OK, -1 interrupted.
7288 //
73 int Rescuebook::copy_and_update( const Block & b, const Sblock::Status st,
74 int & copied_size, int & error_size,
75 const char * const msg, bool & first_post,
76 const bool forward )
89 int Rescuebook::copy_and_update( const Block & b, int & error_size,
90 const char * const msg, const bool forward )
7791 {
7892 current_pos( forward ? b.pos() : b.end() );
79 show_status( current_pos(), msg, first_post );
80 first_post = false;
93 show_status( b.pos(), msg );
8194 if( errors_or_timeout() ) return 1;
8295 if( interrupted() ) return -1;
96 int copied_size = 0;
8397 int retval = copy_block( b, copied_size, error_size );
84 if( !retval )
85 {
86 if( copied_size + error_size < b.size() ) // EOF
87 {
88 if( complete_only ) truncate_domain( b.pos() + copied_size + error_size );
89 else if( !truncate_vector( b.pos() + copied_size + error_size ) )
90 {
91 final_msg( "EOF found before end of logfile" );
92 retval = 1;
93 }
94 }
95 if( copied_size > 0 )
96 {
97 errors += change_chunk_status( Block( b.pos(), copied_size ), Sblock::finished );
98 recsize += copied_size;
99 }
100 if( error_size > 0 )
101 {
102 errors += change_chunk_status( Block( b.pos() + copied_size, error_size ),
103 ( error_size > hardbs() ) ? st : Sblock::bad_sector );
104 if( iname_ && access( iname_, F_OK ) != 0 )
105 {
106 final_msg( "input file disappeared" ); final_errno( errno );
107 retval = 1;
108 }
109 }
110 }
98 if( retval == 0 )
99 {
100 if( copied_size > 0 ) errsize -= copied_size;
101 retval = update( b, Sblock::bad_sector, copied_size, error_size );
102 }
103 return retval;
104 }
105
106
107 // Return values: 1 I/O error, 0 OK, -1 interrupted.
108 //
109 int Rescuebook::copy_and_update2( const Block & b, int & copied_size,
110 int & error_size, const char * const msg,
111 const bool forward, const bool small_try )
112 {
113 if( first_post ) read_logger.print_msg( t1 - t0, msg );
114 current_pos( forward ? b.pos() : b.end() );
115 current_status( copying, msg );
116 show_status( b.pos(), msg );
117 if( errors_or_timeout() ) return 1;
118 if( interrupted() ) return -1;
119 if( small_try && b.size() > hardbs() ) // try one sector first
120 {
121 const Block b1( b.pos(), hardbs() );
122 const Block b2( b1.end(), b.size() - b1.size() );
123 int retval = copy_block( b1, copied_size, error_size );
124 if( retval ) return retval;
125 if( copied_size != b1.size() ) // mark full block on error
126 { error_size += b2.size();
127 return update( b, Sblock::non_trimmed, copied_size, error_size ); }
128 retval = copy_block( b2, copied_size, error_size );
129 if( retval ) return update( b1, Sblock::bad_sector, b1.size(), 0 );
130 copied_size += b1.size();
131 return update( b, Sblock::non_trimmed, copied_size, error_size );
132 }
133 int retval = copy_block( b, copied_size, error_size );
134 if( retval == 0 )
135 retval = update( b, Sblock::non_trimmed, copied_size, error_size );
111136 return retval;
112137 }
113138
117142 //
118143 int Rescuebook::copy_non_tried()
119144 {
120 bool first_post = true;
121
122 for( bool first_pass = true; ; first_pass = false )
123 {
124 long long pos = 0;
125 int skip_size = 0; // size to skip on error
126 bool block_found = false;
127
128 if( first_pass && current_status() == copying &&
129 domain().includes( current_pos() ) )
130 {
131 Block b( current_pos(), 1 );
132 find_chunk( b, Sblock::non_tried );
133 if( b.size() > 0 ) pos = b.pos(); // resume
134 }
135
136 while( pos >= 0 )
137 {
138 const int alignment = ( skip_size ? hardbs() : softbs() );
139 Block b( pos, alignment );
140 find_chunk( b, Sblock::non_tried, alignment );
141 if( b.size() <= 0 ) break;
142 if( pos != b.pos() ) skip_size = 0; // reset size on block change
143 pos = b.end();
144 current_status( copying );
145 block_found = true;
146 const Sblock::Status st =
147 ( ( b.size() > hardbs() ) ? Sblock::non_trimmed : Sblock::bad_sector );
148 int copied_size = 0, error_size = 0;
149 const int retval = copy_and_update( b, st, copied_size, error_size,
150 "Copying non-tried blocks...",
151 first_post, true );
152 if( error_size > 0 ) errsize += error_size;
153 else if( skip_size > 0 && copied_size > 0 )
154 { skip_size -= copied_size; if( skip_size < 0 ) skip_size = 0; }
155 if( retval ) return retval;
156 if( error_size > 0 ) error_rate += error_size;
157 update_rates();
158 if( error_size > 0 || slow_read() )
145 char msgbuf[80] = "Copying non-tried blocks... Pass ";
146 const int msglen = std::strlen( msgbuf );
147 bool forward = !reverse;
148
149 for( int pass = 1; ; ++pass )
150 {
151 first_post = true;
152 snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%d %s",
153 pass, forward ? "(forwards)" : "(backwards)" );
154 int retval = forward ? fcopy_non_tried( msgbuf, pass ) :
155 rcopy_non_tried( msgbuf, pass );
156 if( retval != -3 ) return retval;
157 reduce_min_read_rate();
158 forward = !forward;
159 }
160 }
161
162
163 // Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
164 // Read forwards the non-damaged part of the domain, skipping over the
165 // damaged areas.
166 //
167 int Rescuebook::fcopy_non_tried( const char * const msg, const int pass )
168 {
169 long long pos = 0;
170 int skip_size = 0; // size to skip on error if skipbs > 0
171 bool block_found = false;
172
173 if( pass == 1 && current_status() == copying &&
174 domain().includes( current_pos() ) )
175 {
176 Block b( current_pos(), 1 );
177 find_chunk( b, Sblock::non_tried, domain(), hardbs() );
178 if( b.size() > 0 ) pos = b.pos(); // resume
179 }
180
181 while( pos >= 0 )
182 {
183 Block b( pos, softbs() );
184 find_chunk( b, Sblock::non_tried, domain(), softbs() );
185 if( b.size() <= 0 ) break;
186 if( pos != b.pos() ) skip_size = 0; // reset size on block change
187 pos = b.end();
188 block_found = true;
189 int copied_size = 0, error_size = 0;
190 const int retval = copy_and_update2( b, copied_size, error_size,
191 msg, true, skip_size > 0 );
192 if( error_size > 0 ) { errsize += error_size; error_rate += error_size; }
193 if( retval ) return retval;
194 update_rates();
195 if( ( error_size > 0 || slow_read() ) && pos >= 0 )
196 {
197 if( skip_size > 0 ) // do not skip until 2nd error
159198 {
160 if( pos >= 0 && skip_size > 0 )
199 if( reopen_on_error && !reopen_infile() ) return 1;
200 if( skipbs > 0 && pass <= 2 ) // do not skip if skipbs == 0
161201 {
162 b.assign( pos, skip_size ); b.fix_size();
163 find_chunk( b, Sblock::non_tried );
202 b.assign( pos, skip_size );
203 find_chunk( b, Sblock::non_tried, domain(), hardbs() );
164204 if( pos == b.pos() && b.size() > 0 )
165205 {
166 if( error_size > 0 )
167 { errors += change_chunk_status( b, Sblock::non_trimmed );
206 if( error_size > 0 && b.size() <= softbs() && b.size() <= skip_size )
207 { errors += change_chunk_status( b, Sblock::non_trimmed, domain() );
168208 errsize += b.size(); }
169209 pos = b.end();
170210 }
171211 }
172 if( skip_size < skipbs ) skip_size = skipbs;
173 else if( skip_size <= max_skip_size / 2 ) skip_size *= 2;
174 else skip_size = max_skip_size;
175212 }
176 if( !update_logfile( odes_ ) ) return -2;
177 }
178 if( !block_found ) break;
179 reduce_min_read_rate();
180 }
181 return 0;
213 if( skip_size < skipbs ) skip_size = skipbs;
214 else if( skip_size <= max_skipbs / 2 ) skip_size *= 2;
215 else skip_size = max_skipbs;
216 }
217 else if( skip_size > 0 && copied_size > 0 ) // reset in two steps
218 { if( skip_size > skipbs ) skip_size = skipbs; else skip_size = 0; }
219 if( !update_logfile( odes_ ) ) return -2;
220 }
221 if( !block_found ) return 0;
222 return -3;
182223 }
183224
184225
185226 // Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
186 // Read the non-damaged part of the domain in reverse mode, skipping
187 // over the damaged areas.
188 //
189 int Rescuebook::rcopy_non_tried()
190 {
191 bool first_post = true;
192
193 for( bool first_pass = true; ; first_pass = false )
194 {
195 long long end = LLONG_MAX;
196 int skip_size = 0; // size to skip on error
197 bool block_found = false;
198
199 if( first_pass && current_status() == copying &&
200 domain().includes( current_pos() - 1 ) )
201 {
202 Block b( current_pos() - 1, 1 );
203 rfind_chunk( b, Sblock::non_tried );
204 if( b.size() > 0 ) end = b.end(); // resume
205 }
206
207 while( end > 0 )
208 {
209 const int alignment = ( skip_size ? hardbs() : softbs() );
210 long long pos = end - alignment;
211 if( pos < 0 ) pos = 0;
212 Block b( pos, end - pos );
213 rfind_chunk( b, Sblock::non_tried, alignment );
214 if( b.size() <= 0 ) break;
215 if( pos != b.pos() ) skip_size = 0; // reset size on block change
216 end = b.pos();
217 current_status( copying );
218 block_found = true;
219 const Sblock::Status st =
220 ( ( b.size() > hardbs() ) ? Sblock::non_trimmed : Sblock::bad_sector );
221 int copied_size = 0, error_size = 0;
222 const int retval = copy_and_update( b, st, copied_size, error_size,
223 "Copying non-tried blocks...",
224 first_post, false );
225 if( error_size > 0 ) errsize += error_size;
226 else if( skip_size > 0 && copied_size > 0 )
227 { skip_size -= copied_size; if( skip_size < 0 ) skip_size = 0; }
228 if( retval ) return retval;
229 if( error_size > 0 ) error_rate += error_size;
230 update_rates();
231 if( error_size > 0 || slow_read() )
227 // Read backwards the non-damaged part of the domain, skipping over the
228 // damaged areas.
229 //
230 int Rescuebook::rcopy_non_tried( const char * const msg, const int pass )
231 {
232 long long end = LLONG_MAX;
233 int skip_size = 0; // size to skip on error if skipbs > 0
234 bool block_found = false;
235
236 if( pass == 1 && current_status() == copying &&
237 domain().includes( current_pos() - 1 ) )
238 {
239 Block b( current_pos() - 1, 1 );
240 rfind_chunk( b, Sblock::non_tried, domain(), hardbs() );
241 if( b.size() > 0 ) end = b.end(); // resume
242 }
243
244 while( end > 0 )
245 {
246 Block b( end - softbs(), softbs() );
247 rfind_chunk( b, Sblock::non_tried, domain(), softbs() );
248 if( b.size() <= 0 ) break;
249 if( end != b.end() ) skip_size = 0; // reset size on block change
250 end = b.pos();
251 block_found = true;
252 int copied_size = 0, error_size = 0;
253 const int retval = copy_and_update2( b, copied_size, error_size,
254 msg, false, skip_size > 0 );
255 if( error_size > 0 ) { errsize += error_size; error_rate += error_size; }
256 if( retval ) return retval;
257 update_rates();
258 if( ( error_size > 0 || slow_read() ) && end > 0 )
259 {
260 if( skip_size > 0 ) // do not skip until 2nd error
232261 {
233 if( end > 0 && skip_size > 0 )
262 if( reopen_on_error && !reopen_infile() ) return 1;
263 if( skipbs > 0 && pass <= 2 ) // do not skip if skipbs == 0
234264 {
235 b.size( skip_size ); b.end( end ); pos = b.pos();
236 rfind_chunk( b, Sblock::non_tried );
237 if( pos == b.pos() && b.size() > 0 )
265 b.assign( end - skip_size, skip_size );
266 rfind_chunk( b, Sblock::non_tried, domain(), hardbs() );
267 if( end == b.end() && b.size() > 0 )
238268 {
239 if( error_size > 0 )
240 { errors += change_chunk_status( b, Sblock::non_trimmed );
269 if( error_size > 0 && b.size() <= softbs() && b.size() <= skip_size )
270 { errors += change_chunk_status( b, Sblock::non_trimmed, domain() );
241271 errsize += b.size(); }
242272 end = b.pos();
243273 }
244274 }
245 if( skip_size < skipbs ) skip_size = skipbs;
246 else if( skip_size <= max_skip_size / 2 ) skip_size *= 2;
247 else skip_size = max_skip_size;
248275 }
249 if( !update_logfile( odes_ ) ) return -2;
250 }
251 if( !block_found ) break;
252 reduce_min_read_rate();
253 }
254 return 0;
276 if( skip_size < skipbs ) skip_size = skipbs;
277 else if( skip_size <= max_skipbs / 2 ) skip_size *= 2;
278 else skip_size = max_skipbs;
279 }
280 else if( skip_size > 0 && copied_size > 0 ) // reset in two steps
281 { if( skip_size > skipbs ) skip_size = skipbs; else skip_size = 0; }
282 if( !update_logfile( odes_ ) ) return -2;
283 }
284 if( !block_found ) return 0;
285 return -3;
255286 }
256287
257288
258289 // Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
259 // Trim the damaged areas (largest first) from both edges.
290 // Trim the damaged areas (smallest first) from both edges.
260291 //
261292 int Rescuebook::trim_errors()
262293 {
263294 const char * const msg = "Trimming failed blocks...";
264 bool first_post = true;
295 first_post = true;
296 read_logger.print_msg( t1 - t0, msg );
265297
266298 while( true )
267299 {
268 const int index = find_largest_sblock( Sblock::non_trimmed );
300 const int index =
301 find_smallest_sblock( Sblock::non_trimmed, domain(), softbs() );
269302 if( index < 0 ) break; // no more blocks
270303 const Block block = sblock( index );
271304 long long pos = block.pos();
272305 while( pos >= 0 )
273306 {
274307 Block b( pos, hardbs() );
275 find_chunk( b, Sblock::non_trimmed );
308 find_chunk( b, Sblock::non_trimmed, domain(), hardbs() );
276309 if( pos != b.pos() || b.size() <= 0 ) break; // block change
277310 pos = b.end();
278 current_status( trimming );
279 int copied_size = 0, error_size = 0;
280 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
281 error_size, msg, first_post, true );
282 if( copied_size > 0 ) errsize -= copied_size;
311 current_status( trimming, msg );
312 int error_size = 0;
313 const int retval = copy_and_update( b, error_size, msg, true );
283314 if( retval ) return retval;
284315 if( error_size > 0 ) { error_rate += error_size; pos = -1; }
285316 update_rates();
288319 long long end = block.end();
289320 while( end > 0 )
290321 {
291 pos = end - hardbs();
292 if( pos < 0 ) pos = 0;
293 Block b( pos, end - pos );
294 rfind_chunk( b, Sblock::non_trimmed );
295 if( pos != b.pos() || b.size() <= 0 ) break; // block change
322 Block b( end - hardbs(), hardbs() );
323 rfind_chunk( b, Sblock::non_trimmed, domain(), hardbs() );
324 if( end != b.end() || b.size() <= 0 ) break; // block change
296325 end = b.pos();
297 current_status( trimming );
298 int copied_size = 0, error_size = 0;
299 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
300 error_size, msg, first_post, false );
301 if( copied_size > 0 ) errsize -= copied_size;
326 current_status( trimming, msg );
327 int error_size = 0;
328 const int retval = copy_and_update( b, error_size, msg, false );
302329 if( retval ) return retval;
303330 if( error_size > 0 ) error_rate += error_size;
304331 if( error_size > 0 && end > 0 )
306333 const int index = find_index( end - 1 );
307334 if( index >= 0 && domain().includes( sblock( index ) ) &&
308335 sblock( index ).status() == Sblock::non_trimmed )
309 errors += change_chunk_status( sblock( index ), Sblock::non_split );
336 errors += change_chunk_status( sblock( index ), Sblock::non_split,
337 domain() );
310338 end = -1;
311339 }
312340 update_rates();
319347
320348 // Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
321349 // Split the damaged areas (largest first).
322 // Then read the remaining small areas sequentially.
323 //
324 int Rescuebook::split_errors( const bool reverse )
350 // Then read the remaining small areas (less than 7 sectors) sequentially.
351 //
352 int Rescuebook::split_errors()
325353 {
326354 const char * const msg = "Splitting failed blocks...";
327 bool first_post = true;
355 first_post = true;
356 read_logger.print_msg( t1 - t0, msg );
328357
329358 while( true )
330359 {
360 const int index = find_largest_sblock( Sblock::non_split, domain() );
361 if( index < 0 ) break; // no more blocks
362 const Block block = sblock( index );
363 if( block.size() / hardbs() < 7 ) break; // no more large blocks
331364 if( sblocks() < max_logfile_size ) // split largest block
332365 {
333 const int index = find_largest_sblock( Sblock::non_split );
334 if( index < 0 ) break; // no more blocks
335 const Block block = sblock( index );
336 if( block.size() / hardbs() < 5 ) break; // no more large blocks
337 const long long midpos =
366 long long midpos =
338367 block.pos() + ( ( block.size() / ( 2 * hardbs() ) ) * hardbs() );
339368 long long pos = midpos;
340369 while( pos >= 0 )
341370 {
342371 Block b( pos, hardbs() );
343 find_chunk( b, Sblock::non_split );
372 find_chunk( b, Sblock::non_split, domain(), hardbs() );
344373 if( pos != b.pos() || b.size() <= 0 ) break; // block change
345374 pos = b.end();
346 current_status( splitting );
347 int copied_size = 0, error_size = 0;
348 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
349 error_size, msg, first_post, true );
350 if( copied_size > 0 ) errsize -= copied_size;
375 current_status( splitting, msg );
376 int error_size = 0;
377 const int retval = copy_and_update( b, error_size, msg, true );
351378 if( retval ) return retval;
352 if( error_size > 0 ) { error_rate += error_size; pos = -1; }
379 if( error_size > 0 )
380 { error_rate += error_size; pos = -1;
381 if( b.pos() == midpos ) midpos = -1; } // skip backwards reads
353382 update_rates();
354383 if( !update_logfile( odes_ ) ) return -2;
355384 }
356385 long long end = midpos;
357386 while( end > 0 )
358387 {
359 pos = end - hardbs();
360 if( pos < 0 ) pos = 0;
361 Block b( pos, end - pos );
362 rfind_chunk( b, Sblock::non_split );
363 if( pos != b.pos() || b.size() <= 0 ) break; // block change
388 Block b( end - hardbs(), hardbs() );
389 rfind_chunk( b, Sblock::non_split, domain(), hardbs() );
390 if( end != b.end() || b.size() <= 0 ) break; // block change
364391 end = b.pos();
365 current_status( splitting );
366 int copied_size = 0, error_size = 0;
367 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
368 error_size, msg, first_post, true );
369 if( copied_size > 0 ) errsize -= copied_size;
392 current_status( splitting, msg );
393 int error_size = 0;
394 const int retval = copy_and_update( b, error_size, msg, true );
370395 if( retval ) return retval;
371396 if( error_size > 0 ) { error_rate += error_size; end = -1; }
372397 update_rates();
373398 if( !update_logfile( odes_ ) ) return -2;
374399 }
375400 }
376 else // logfile is full; read smallest block
377 {
378 const int index = find_smallest_sblock( Sblock::non_split );
379 if( index < 0 ) break; // no more blocks
380 const Block block = sblock( index );
401 else // logfile is full; read largest block
402 {
381403 long long pos = block.pos();
382404 while( pos >= 0 )
383405 {
384406 Block b( pos, hardbs() );
385 find_chunk( b, Sblock::non_split );
407 find_chunk( b, Sblock::non_split, domain(), hardbs() );
386408 if( pos != b.pos() || b.size() <= 0 ) break; // block change
387409 pos = b.end();
388 current_status( splitting );
389 int copied_size = 0, error_size = 0;
390 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
391 error_size, msg, first_post, true );
392 if( copied_size > 0 ) errsize -= copied_size;
410 current_status( splitting, msg );
411 int error_size = 0;
412 const int retval = copy_and_update( b, error_size, msg, true );
393413 if( retval ) return retval;
394414 if( error_size > 0 ) error_rate += error_size;
395415 update_rates();
403423 while( pos >= 0 )
404424 {
405425 Block b( pos, hardbs() );
406 find_chunk( b, Sblock::non_split );
426 find_chunk( b, Sblock::non_split, domain(), hardbs() );
407427 if( b.size() <= 0 ) break; // no more blocks
408428 pos = b.end();
409 current_status( splitting );
410 int copied_size = 0, error_size = 0;
411 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
412 error_size, msg, first_post, true );
413 if( copied_size > 0 ) errsize -= copied_size;
429 current_status( splitting, msg );
430 int error_size = 0;
431 const int retval = copy_and_update( b, error_size, msg, true );
414432 if( retval ) return retval;
415433 if( error_size > 0 ) error_rate += error_size;
416434 update_rates();
422440 long long end = LLONG_MAX;
423441 while( end > 0 )
424442 {
425 long long pos = end - hardbs();
426 if( pos < 0 ) pos = 0;
427 Block b( pos, end - pos );
428 rfind_chunk( b, Sblock::non_split );
443 Block b( end - hardbs(), hardbs() );
444 rfind_chunk( b, Sblock::non_split, domain(), hardbs() );
429445 if( b.size() <= 0 ) break; // no more blocks
430446 end = b.pos();
431 current_status( splitting );
432 int copied_size = 0, error_size = 0;
433 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
434 error_size, msg, first_post, true );
435 if( copied_size > 0 ) errsize -= copied_size;
447 current_status( splitting, msg );
448 int error_size = 0;
449 const int retval = copy_and_update( b, error_size, msg, true );
436450 if( retval ) return retval;
437451 if( error_size > 0 ) error_rate += error_size;
438452 update_rates();
448462 //
449463 int Rescuebook::copy_errors()
450464 {
451 char msgbuf[80] = "Retrying bad sectors... Retry ";
465 char msgbuf[80] = "Retrying bad sectors (forwards)... Retry ";
452466 const int msglen = std::strlen( msgbuf );
453467
454468 for( int retry = 1; max_retries < 0 || retry <= max_retries; ++retry )
455469 {
456470 long long pos = 0;
457 bool first_post = true, block_found = false;
471 bool block_found = false;
472 first_post = true;
458473 snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%d", retry );
474 read_logger.print_msg( t1 - t0, msgbuf );
459475
460476 if( retry == 1 && current_status() == retrying &&
461477 domain().includes( current_pos() ) )
462478 {
463479 Block b( current_pos(), 1 );
464 find_chunk( b, Sblock::bad_sector );
480 find_chunk( b, Sblock::bad_sector, domain(), hardbs() );
465481 if( b.size() > 0 ) pos = b.pos(); // resume
466482 }
467483
468484 while( pos >= 0 )
469485 {
470486 Block b( pos, hardbs() );
471 find_chunk( b, Sblock::bad_sector );
472 if( b.size() <= 0 ) break;
487 find_chunk( b, Sblock::bad_sector, domain(), hardbs() );
488 if( b.size() <= 0 ) break; // no more blocks
473489 pos = b.end();
474 current_status( retrying );
490 current_status( retrying, msgbuf );
475491 block_found = true;
476 int copied_size = 0, error_size = 0;
477 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
478 error_size, msgbuf, first_post, true );
479 if( copied_size > 0 ) errsize -= copied_size;
492 int error_size = 0;
493 const int retval = copy_and_update( b, error_size, msgbuf, true );
480494 if( retval ) return retval;
481495 if( error_size > 0 ) error_rate += error_size;
482496 update_rates();
493507 //
494508 int Rescuebook::rcopy_errors()
495509 {
496 char msgbuf[80] = "Retrying bad sectors... Retry ";
510 char msgbuf[80] = "Retrying bad sectors (backwards)... Retry ";
497511 const int msglen = std::strlen( msgbuf );
498512
499513 for( int retry = 1; max_retries < 0 || retry <= max_retries; ++retry )
500514 {
501515 long long end = LLONG_MAX;
502 bool first_post = true, block_found = false;
516 bool block_found = false;
517 first_post = true;
503518 snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%d", retry );
519 read_logger.print_msg( t1 - t0, msgbuf );
504520
505521 if( retry == 1 && current_status() == retrying &&
506522 domain().includes( current_pos() - 1 ) )
507523 {
508524 Block b( current_pos() - 1, 1 );
509 rfind_chunk( b, Sblock::bad_sector );
525 rfind_chunk( b, Sblock::bad_sector, domain(), hardbs() );
510526 if( b.size() > 0 ) end = b.end(); // resume
511527 }
512528
513529 while( end > 0 )
514530 {
515 long long pos = end - hardbs();
516 if( pos < 0 ) pos = 0;
517 Block b( pos, end - pos );
518 rfind_chunk( b, Sblock::bad_sector );
519 if( b.size() <= 0 ) break;
531 Block b( end - hardbs(), hardbs() );
532 rfind_chunk( b, Sblock::bad_sector, domain(), hardbs() );
533 if( b.size() <= 0 ) break; // no more blocks
520534 end = b.pos();
521 current_status( retrying );
535 current_status( retrying, msgbuf );
522536 block_found = true;
523 int copied_size = 0, error_size = 0;
524 const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
525 error_size, msgbuf, first_post, false );
526 if( copied_size > 0 ) errsize -= copied_size;
537 int error_size = 0;
538 const int retval = copy_and_update( b, error_size, msgbuf, false );
527539 if( retval ) return retval;
528540 if( error_size > 0 ) error_rate += error_size;
529541 update_rates();
535547 }
536548
537549
550 void Rescuebook::update_rates( const bool force )
551 {
552 if( t0 == 0 )
553 {
554 t0 = t1 = ts = initial_time();
555 first_size = last_size = recsize;
556 rates_updated = true;
557 if( verbosity >= 0 ) std::printf( "\n\n\n" );
558 }
559
560 long t2 = std::time( 0 );
561 if( force && t2 <= t1 ) t2 = t1 + 1; // force update of e_code
562 if( t2 > t1 )
563 {
564 a_rate = ( recsize - first_size ) / ( t2 - t0 );
565 c_rate = ( recsize - last_size ) / ( t2 - t1 );
566 if( !( e_code & 4 ) )
567 {
568 if( recsize != last_size ) { last_size = recsize; ts = t2; }
569 else if( timeout >= 0 && t2 - ts > timeout ) e_code |= 4;
570 }
571 if( max_error_rate >= 0 && !( e_code & 1 ) )
572 {
573 error_rate /= ( t2 - t1 );
574 if( error_rate > max_error_rate ) e_code |= 1;
575 else error_rate = 0;
576 }
577 t1 = t2;
578 rates_updated = true;
579 }
580 else if( t2 < t1 ) // clock jumped back
581 {
582 const long delta = std::min( t0, t1 - t2 );
583 t0 -= delta;
584 ts -= delta;
585 t1 = t2;
586 }
587 }
588
589
590 void Rescuebook::show_status( const long long ipos, const char * const msg,
591 const bool force )
592 {
593 const char * const up = "\x1b[A";
594
595 if( ipos >= 0 ) last_ipos = ipos;
596 if( rates_updated || force || first_post )
597 {
598 if( verbosity >= 0 )
599 {
600 std::printf( "\r%s%s%s", up, up, up );
601 std::printf( "rescued: %10sB, errsize:%9sB, current rate: %9sB/s\n",
602 format_num( recsize ), format_num( errsize, 99999 ),
603 format_num( c_rate, 99999 ) );
604 std::printf( " ipos: %10sB, errors: %7u, average rate: %9sB/s\n",
605 format_num( last_ipos ), errors,
606 format_num( a_rate, 99999 ) );
607 std::printf( " opos: %10sB, run time: %9s, successful read: %9s ago\n",
608 format_num( last_ipos + offset() ),
609 format_time( t1 - t0 ), format_time( t1 - ts ) );
610 if( msg && msg[0] && !errors_or_timeout() )
611 {
612 const int len = std::strlen( msg ); std::printf( "\r%s", msg );
613 for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
614 oldlen = len;
615 }
616 std::fflush( stdout );
617 }
618 rate_logger.print_line( t1 - t0, last_ipos, a_rate, c_rate, errors, errsize );
619 if( !force && !first_post ) read_logger.print_time( t1 - t0 );
620 rates_updated = false;
621 first_post = false;
622 }
623 }
624
625
538626 Rescuebook::Rescuebook( const long long offset, const long long isize,
539 Domain & dom, const Rb_options & rb_opts,
540 const char * const iname, const char * const logname,
541 const int cluster, const int hardbs,
542 const bool synchronous )
627 Domain & dom, const Domain * const test_dom,
628 const Rb_options & rb_opts, const char * const iname,
629 const char * const logname, const int cluster,
630 const int hardbs, const bool synchronous )
543631 : Logbook( offset, isize, dom, logname, cluster, hardbs, rb_opts.complete_only ),
544632 Rb_options( rb_opts ),
545633 error_rate( 0 ),
546634 sparse_size( sparse ? 0 : -1 ),
547635 recsize( 0 ),
548636 errsize( 0 ),
549 iname_( ( access( iname, F_OK ) == 0 ) ? iname : 0 ),
550 max_skip_size( calculate_max_skip_size( isize, hardbs, skipbs ) ),
637 test_domain( test_dom ),
638 iname_( iname ),
551639 e_code( 0 ),
640 access_works( access( iname, F_OK ) == 0 ),
552641 synchronous_( synchronous ),
553642 a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ),
554643 last_ipos( 0 ), t0( 0 ), t1( 0 ), ts( 0 ), oldlen( 0 ),
555 rates_updated( false )
556 {
644 rates_updated( false ), first_post( false )
645 {
646 const long long csize = isize / 100;
647 if( isize > 0 && skipbs > 0 && max_skipbs == Rb_options::max_max_skipbs &&
648 csize < max_skipbs )
649 max_skipbs = std::max( (long long)skipbs, csize );
650 skipbs = round_up( skipbs, hardbs ); // make multiple of hardbs
651 max_skipbs = round_up( max_skipbs, hardbs );
652
557653 if( retrim )
558654 for( int index = 0; index < sblocks(); ++index )
559655 {
581677
582678 // Return values: 1 I/O error, 0 OK.
583679 //
584 int Rescuebook::do_rescue( const int ides, const int odes, const bool reverse )
680 int Rescuebook::do_rescue( const int ides, const int odes )
585681 {
586682 bool copy_pending = false, trim_pending = false, split_pending = false;
587683 ides_ = ides; odes_ = odes;
607703 if( logfile_exists() )
608704 {
609705 std::printf( "Initial status (read from logfile)\n" );
610 std::printf( "rescued: %10sB,", format_num( recsize ) );
611 std::printf( " errsize:%9sB,", format_num( errsize, 99999 ) );
612 std::printf( " errors: %7u\n", errors );
613706 if( verbosity >= 2 )
614707 {
615 std::printf( "current position: %10sB,", format_num( current_pos() ) );
616 std::printf( " current sector: %7lld\n", current_pos() / hardbs() );
708 std::printf( "current position: %10sB, current sector: %7lld\n",
709 format_num( current_pos() ), current_pos() / hardbs() );
617710 if( sblocks() )
618 std::printf( "last block size: %10sB\n",
711 std::printf( " last block size: %10sB\n",
619712 format_num( sblock( sblocks() - 1 ).size() ) );
620 std::printf( "\n" );
621713 }
622 std::printf( "Current status\n" );
714 if( domain().pos() > 0 || domain().end() < logfile_isize() )
715 std::printf( "(sizes below are limited to the domain %sB to %sB)\n",
716 format_num( domain().pos() ), format_num( domain().end() ) );
717 std::printf( "rescued: %10sB, errsize:%9sB, errors: %7u\n",
718 format_num( recsize ), format_num( errsize, 99999 ), errors );
719 std::printf( "\nCurrent status\n" );
623720 }
624721 }
625722 int retval = 0;
626723 update_rates(); // first call
627724 if( copy_pending && !errors_or_timeout() )
628 retval = ( reverse ? rcopy_non_tried() : copy_non_tried() );
629 if( !retval && trim_pending && !errors_or_timeout() )
725 retval = copy_non_tried();
726 if( retval == 0 && trim_pending && !notrim && !errors_or_timeout() )
630727 retval = trim_errors();
631 if( !retval && split_pending && !nosplit && !errors_or_timeout() )
632 retval = split_errors( reverse );
633 if( !retval && max_retries != 0 && !errors_or_timeout() )
634 retval = ( reverse ? rcopy_errors() : copy_errors() );
728 if( retval == 0 && split_pending && !nosplit && !errors_or_timeout() )
729 retval = split_errors();
730 if( retval == 0 && max_retries != 0 && !errors_or_timeout() )
731 retval = reverse ? rcopy_errors() : copy_errors();
635732 if( !rates_updated ) update_rates( true ); // force update of e_code
636 show_status( -1, (retval ? 0 : "Finished"), true );
637 if( !retval && errors_or_timeout() ) retval = 1;
733 show_status( -1, retval ? 0 : "Finished", true );
734
735 const bool signaled = ( retval == -1 );
736 if( signaled ) retval = 0;
737 if( retval == 0 && errors_or_timeout() ) retval = 1;
638738 if( verbosity >= 0 )
639739 {
640740 if( retval == -2 ) std::printf( "\nLogfile error" );
641 else if( retval < 0 ) std::printf( "\nInterrupted by user" );
741 else if( retval == 0 && signaled ) std::printf( "\nInterrupted by user" );
642742 else
643743 {
644744 if( e_code & 1 )
652752 if( retval == -2 ) retval = 1; // logfile error
653753 else
654754 {
655 if( retval == 0 ) current_status( finished );
656 else if( retval < 0 ) retval = 0; // interrupted by user
755 if( retval == 0 && !signaled ) current_status( finished );
657756 if( !extend_outfile_size() ) // sparse or -x option
658757 {
659758 show_error( "Error extending output file size." );
662761 compact_sblock_vector();
663762 if( !update_logfile( odes_, true ) && retval == 0 ) retval = 1;
664763 }
764 if( close( odes_ ) != 0 )
765 { show_error( "Can't close outfile", errno );
766 if( retval == 0 ) retval = 1; }
767 if( !rate_logger.close_file() )
768 show_error( "warning: Error closing the rates logging file." );
769 if( !read_logger.close_file() )
770 show_error( "warning: Error closing the reads logging file." );
665771 if( final_msg() ) show_error( final_msg(), final_errno() );
666 return retval;
667 }
772 if( retval ) return retval; // errors have priority over signals
773 if( signaled ) return signaled_exit();
774 return 0;
775 }
00 #! /bin/sh
11 # check script for GNU ddrescue - Data recovery tool
2 # Copyright (C) 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
2 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Antonio Diaz Diaz.
33 #
44 # This script is free software: you have unlimited permission
55 # to copy, distribute and modify it.
1212 DDRESCUELOG="${objdir}"/ddrescuelog
1313 framework_failure() { echo "failure in testing framework" ; exit 1 ; }
1414
15 if [ ! -x "${DDRESCUE}" ] ; then
15 if [ ! -f "${DDRESCUE}" ] || [ ! -x "${DDRESCUE}" ] ; then
1616 echo "${DDRESCUE}: cannot execute"
1717 exit 1
1818 fi
2424 in="${testdir}"/test.txt
2525 in1="${testdir}"/test1.txt
2626 in2="${testdir}"/test2.txt
27 blank="${testdir}"/logfile_blank
2728 logfile1="${testdir}"/logfile1
2829 logfile2="${testdir}"/logfile2
30 logfile2i="${testdir}"/logfile2i
31 logfile3="${testdir}"/logfile3
32 logfile4="${testdir}"/logfile4
33 logfile5="${testdir}"/logfile5
2934 fail=0
3035
3136 printf "testing ddrescue-%s..." "$2"
3237
3338 "${DDRESCUE}" -q ${in}
34 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
39 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
3540 "${DDRESCUE}" -q ${in} out logfile extra
36 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
41 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
3742 "${DDRESCUE}" -q ${in} ${in} logfile
38 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
43 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
3944 "${DDRESCUE}" -q ${in} out ${in}
40 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
45 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
4146 "${DDRESCUE}" -q ${in} out out
42 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
43 "${DDRESCUE}" -q -g ${in} out
44 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
47 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
4548 "${DDRESCUE}" -q -F- ${in} out
46 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
49 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
4750 "${DDRESCUE}" -q -F ${in} out logfile
48 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
49 "${DDRESCUE}" -q -F- -g ${in} out logfile
50 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
51 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
52 "${DDRESCUE}" -q -G ${in} out
53 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
54 "${DDRESCUE}" -q -F- -G ${in} out logfile
55 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
56 "${DDRESCUE}" -q -H ${logfile2i} ${in} out logfile
57 if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
58 "${DDRESCUE}" -q -K0, ${in} out
59 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
60 "${DDRESCUE}" -q -K0,65535 ${in} out
61 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
62 "${DDRESCUE}" -q -i 0, ${in} out
63 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
64 "${DDRESCUE}" -q -i -1 ${in} out
65 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
5166 "${DDRESCUE}" -q -m ${logfile1} -m ${logfile1} ${in} out logfile
52 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
67 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
68 "${DDRESCUE}" -q -m ${logfile2i} ${in} out logfile
69 if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
5370 "${DDRESCUE}" -q -w ${in} out logfile
54 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
55
56 if [ -r logfile ] ; then rm logfile || framework_failure ; fi
57 "${DDRESCUE}" -t -pq -i15000 ${in} out logfile || fail=1
58 "${DDRESCUE}" -D -fnq -s15000 ${in} out logfile || fail=1
59 cmp ${in} out || fail=1
60 printf .
61
62 rm out || framework_failure
63 rm logfile || framework_failure
64 "${DDRESCUE}" -qR -i15000 ${in} out logfile || fail=1
65 "${DDRESCUE}" -qR -s15000 ${in} out logfile || fail=1
66 cmp ${in} out || fail=1
67 printf .
68
69 rm out || framework_failure
70 "${DDRESCUE}" -qF+ -o15000 ${in} out2 logfile || fail=1
71 "${DDRESCUE}" -qRS -i15000 -o0 out2 out || fail=1
71 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
72
73 rm -f logfile
74 "${DDRESCUE}" -q -t -p -i15000 ${in} out logfile || fail=1
75 "${DDRESCUE}" -q -D -f -n -s15000 ${in} out logfile || fail=1
76 cmp ${in} out || fail=1
77 printf .
78
79 rm -f out
80 rm -f logfile
81 "${DDRESCUE}" -q -R -i15000 ${in} out logfile || fail=1
82 "${DDRESCUE}" -q -R -s15000 ${in} out logfile || fail=1
83 cmp ${in} out || fail=1
84 printf .
85
86 rm -f out
87 "${DDRESCUE}" -q -F+ -o15000 ${in} out2 logfile || fail=1
88 "${DDRESCUE}" -q -R -S -i15000 -o0 out2 out || fail=1
7289 cmp ${in} out || fail=1
7390 printf .
7491
7592 printf "garbage" >> out || framework_failure
76 "${DDRESCUE}" -qRt -i15000 -o0 out2 out || fail=1
77 cmp ${in} out || fail=1
78 printf .
79
80 rm out || framework_failure
81 "${DDRESCUE}" -q -m ${logfile1} ${in} out || fail=1
93 "${DDRESCUE}" -q -R -t -i15000 -o0 out2 out || fail=1
94 cmp ${in} out || fail=1
95 printf .
96
97 rm -f out
98 "${DDRESCUE}" -q -O -H ${logfile1} ${in} out || fail=1
8299 cmp ${in1} out || fail=1
83100 printf .
84 "${DDRESCUE}" -q -m ${logfile2} ${in} out || fail=1
85 cmp ${in} out || fail=1
86 printf .
87
88 rm out || framework_failure
89 "${DDRESCUE}" -qRm ${logfile2} ${in} out || fail=1
101 "${DDRESCUE}" -q -O -L -K0 -H ${logfile2i} ${in} out || fail=1
102 cmp ${in} out || fail=1
103 printf .
104
105 rm -f out
106 "${DDRESCUE}" -q -O -m ${logfile1} ${in} out || fail=1
107 cmp ${in1} out || fail=1
108 printf .
109 "${DDRESCUE}" -q -O -L -m ${logfile2i} ${in} out || fail=1
110 cmp ${in} out || fail=1
111 printf .
112
113 rm -f out
114 "${DDRESCUE}" -q -R -m ${logfile2} ${in} out || fail=1
90115 cmp ${in2} out || fail=1
91116 printf .
92 "${DDRESCUE}" -qRm ${logfile1} ${in} out || fail=1
93 cmp ${in} out || fail=1
94 printf .
95
96 rm out || framework_failure
117 "${DDRESCUE}" -q -R -K,64KiB -m ${logfile1} ${in} out || fail=1
118 cmp ${in} out || fail=1
119 printf .
120
121 rm -f out
97122 cat ${logfile1} > logfile || framework_failure
98 "${DDRESCUE}" -qI ${in} out logfile || fail=1
123 "${DDRESCUE}" -q -I ${in} out logfile || fail=1
99124 cat ${logfile2} > logfile || framework_failure
100 "${DDRESCUE}" -qI ${in} out logfile || fail=1
101 cmp ${in} out || fail=1
102 printf .
103
104 rm out || framework_failure
125 "${DDRESCUE}" -q -I ${in} out logfile || fail=1
126 cmp ${in} out || fail=1
127 printf .
128
129 rm -f out
105130 cat ${logfile1} > logfile || framework_failure
106 "${DDRESCUE}" -qR ${in} out logfile || fail=1
131 "${DDRESCUE}" -q -R ${in} out logfile || fail=1
107132 cat ${logfile2} > logfile || framework_failure
108 "${DDRESCUE}" -qR ${in} out logfile || fail=1
109 cmp ${in} out || fail=1
110 printf .
111
133 "${DDRESCUE}" -q -R ${in} out logfile || fail=1
134 cmp ${in} out || fail=1
135 printf .
136
137 rm -f out
138 fail2=0
139 for i in 0 8000 16000 24000 32000 ; do
140 "${DDRESCUE}" -q -i${i} -s4000 -m ${logfile1} ${in} out || fail2=1
141 done
142 cmp -s ${in} out && fail2=1
143 for i in 4000 12000 20000 28000 36000 ; do
144 "${DDRESCUE}" -q -i${i} -s4000 -m ${logfile1} ${in} out || fail2=1
145 done
146 cmp ${in1} out || fail2=1
147 for i in 0 8000 16000 24000 32000 ; do
148 "${DDRESCUE}" -q -i${i} -s4000 -m ${logfile2} ${in2} out || fail2=1
149 done
150 cmp -s ${in} out && fail2=1
151 for i in 4000 12000 20000 28000 36000 ; do
152 "${DDRESCUE}" -q -i${i} -s4000 -m ${logfile2} ${in2} out || fail2=1
153 done
154 cmp ${in} out || fail2=1
155 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
156
157 rm -f logfile
112158 cat ${in1} > out || framework_failure
113 rm logfile || framework_failure
114 "${DDRESCUE}" -qg ${in} out logfile || fail=1
159 "${DDRESCUE}" -q -G ${in} out logfile || fail=1
115160 "${DDRESCUE}" -q ${in2} out logfile || fail=1
116161 cmp ${in} out || fail=1
117162 printf .
118163
164 rm -f logfile
119165 cat ${in} > copy || framework_failure
120166 printf "garbage" >> copy || framework_failure
121167 cat ${in2} > out || framework_failure
122 rm logfile || framework_failure
123 "${DDRESCUE}" -qt -x 35744 ${in1} copy || fail=1
124 "${DDRESCUE}" -qg ${in} out logfile || fail=1
125 "${DDRESCUE}" -qR -T1.5d copy out logfile || fail=1
168 "${DDRESCUE}" -q -t -x 35744 ${in1} copy || fail=1
169 "${DDRESCUE}" -q -G ${in} out logfile || fail=1
170 "${DDRESCUE}" -q -R -T1.5d copy out logfile || fail=1
126171 cmp ${in} out || fail=1
127172 printf .
128173
129174 printf "\ntesting ddrescuelog-%s..." "$2"
130175
131176 "${DDRESCUELOG}" -q logfile
132 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
177 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
133178 "${DDRESCUELOG}" -q -d
134 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
179 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
135180 "${DDRESCUELOG}" -q -t -d logfile
136 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
181 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
182 "${DDRESCUELOG}" -q -m ${logfile2i} -t logfile
183 if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
184
185 "${DDRESCUELOG}" -a '?,+' -i3072 ${logfile1} > logfile
186 "${DDRESCUELOG}" -D logfile
187 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
188 "${DDRESCUELOG}" -a '?,+' -i2048 -s1024 logfile > logfile2
189 "${DDRESCUELOG}" -d logfile2
190 if [ $? = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
137191
138192 "${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail=1
139 cat out | "${DDRESCUELOG}" -b2048 -fc logfile || fail=1
193 "${DDRESCUELOG}" -b2048 -f -c logfile < out || fail=1
140194 "${DDRESCUELOG}" -b2048 -l+ logfile > copy || fail=1
141195 cmp out copy || fail=1
142196 printf .
143 cat out | "${DDRESCUELOG}" -b2048 -s35744 -fc?+ logfile || fail=1
197 "${DDRESCUELOG}" -q -p ${logfile1} logfile
198 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
199 "${DDRESCUELOG}" -P ${logfile1} logfile || fail=1
200 printf .
201 "${DDRESCUELOG}" -b2048 -s35744 -f -c?+ logfile < out || fail=1
144202 "${DDRESCUELOG}" -p ${logfile2} logfile || fail=1
145203 printf .
146 cat out | "${DDRESCUELOG}" -b2048 -fc?+ logfile || fail=1
204 "${DDRESCUELOG}" -b2048 -f -c?+ logfile < out || fail=1
147205 "${DDRESCUELOG}" -s35744 -p ${logfile2} logfile || fail=1
148206 printf .
149 "${DDRESCUELOG}" -s35745 -q -p ${logfile2} logfile
150 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
207 "${DDRESCUELOG}" -q -s35745 -p ${logfile2} logfile
208 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
209
210 printf "10\n12\n14\n16\n" | "${DDRESCUELOG}" -b2048 -f -c+? logfile || fail=1
211 "${DDRESCUELOG}" -q -p logfile ${logfile1}
212 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
213 "${DDRESCUELOG}" -q -i0x5000 -p logfile ${logfile1}
214 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
215 "${DDRESCUELOG}" -i0x5000 -s0x3800 -p logfile ${logfile1} || fail=1
216 printf .
217
218 "${DDRESCUELOG}" -C ${logfile2i} > logfile || fail=1
219 "${DDRESCUELOG}" -p ${logfile2} logfile || fail=1
220 printf .
151221
152222 cat ${logfile1} > logfile || framework_failure
153223 "${DDRESCUELOG}" -i1024 -s2048 -d logfile
154 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
224 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
155225 "${DDRESCUELOG}" -i1024 -s1024 -d logfile || fail=1
156226 printf .
157 "${DDRESCUELOG}" -i1024 -s1024 -d -q logfile
158 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
227 "${DDRESCUELOG}" -q -i1024 -s1024 -d logfile
228 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
159229
160230 cat ${logfile2} > logfile || framework_failure
161231 "${DDRESCUELOG}" -m ${logfile1} -D logfile
162 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
163 "${DDRESCUELOG}" -m ${logfile2} -D logfile || fail=1
232 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
233 "${DDRESCUELOG}" -L -m ${logfile2i} -D logfile || fail=1
164234 printf .
165235 "${DDRESCUELOG}" -i1024 -s2048 -d logfile
166 if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
236 if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
167237 "${DDRESCUELOG}" -i2048 -s2048 -d logfile || fail=1
168238 printf .
169239
170 cat ${logfile1} > logfile || framework_failure
171 "${DDRESCUELOG}" -b2048 -l+ logfile > out || fail=1
240 "${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail=1
172241 printf "0\n2\n4\n6\n8\n10\n12\n14\n16\n" > copy || framework_failure
173242 cmp out copy || fail=1
174243 printf .
175 "${DDRESCUELOG}" -b2048 -l?- logfile > out || fail=1
244 "${DDRESCUELOG}" -b2048 -l?- ${logfile1} > out || fail=1
176245 printf "1\n3\n5\n7\n9\n11\n13\n15\n17\n" > copy || framework_failure
177246 cmp out copy || fail=1
178247 printf .
179 "${DDRESCUELOG}" -b2048 -l+ -i6KiB -o0 -s16KiB logfile > out || fail=1
248 "${DDRESCUELOG}" -b2048 -l+ -i0x1800 -o0 -s0x4000 ${logfile1} > out || fail=1
180249 printf "1\n3\n5\n7\n" > copy || framework_failure
181250 cmp out copy || fail=1
182251 printf .
190259 printf "1\n3\n5\n7\n9\n11\n13\n15\n17\n" > copy || framework_failure
191260 cmp out copy || fail=1
192261 printf .
193 "${DDRESCUELOG}" -b2048 -l+ -i2048 -o0 -s16KiB logfile > out || fail=1
262 "${DDRESCUELOG}" -b2048 -l+ -i2048 -o0 -s0x4000 logfile > out || fail=1
194263 printf "1\n3\n5\n7\n" > copy || framework_failure
195264 cmp out copy || fail=1
196265 printf .
197266
198 "${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail=1
199 "${DDRESCUELOG}" -x ${logfile1} ${logfile1} > logfile || fail=1
200 "${DDRESCUELOG}" -b2048 -l- logfile > copy || fail=1
201 cmp out copy || fail=1
202 printf .
203 "${DDRESCUELOG}" -y ${logfile2} ${logfile1} > logfile || fail=1
204 "${DDRESCUELOG}" -b2048 -l- logfile > copy || fail=1
205 cmp out copy || fail=1
206 printf .
207 "${DDRESCUELOG}" -z ${logfile1} ${logfile2} > logfile || fail=1
208 "${DDRESCUELOG}" -d logfile || fail=1
209 printf .
267 "${DDRESCUELOG}" -q -P ${logfile2i} ${logfile2}
268 if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
269 "${DDRESCUELOG}" -L -P ${logfile2i} ${logfile2} || fail=1
270 printf .
271
272 fail2=0 # test XOR
273 for i in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
274 for j in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
275 "${DDRESCUELOG}" -x ${j} ${i} > out || fail2=1
276 "${DDRESCUELOG}" -x ${i} ${j} > copy || fail2=1
277 "${DDRESCUELOG}" -P out copy || fail2=1
278 "${DDRESCUELOG}" -x ${j} out > copy || fail2=1
279 "${DDRESCUELOG}" -P ${i} copy || fail2=1
280 done
281 done
282 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
283
284 fail2=0
285 "${DDRESCUELOG}" -x ${logfile1} ${logfile2} > out || fail2=1
286 "${DDRESCUELOG}" -x ${logfile2} ${logfile1} > copy || fail2=1
287 "${DDRESCUELOG}" -p out copy || fail2=1
288 "${DDRESCUELOG}" -d out || fail2=1
289 "${DDRESCUELOG}" -d copy || fail2=1
290 "${DDRESCUELOG}" -x ${logfile1} ${blank} > out || fail2=1
291 "${DDRESCUELOG}" -x ${blank} ${logfile1} > copy || fail2=1
292 "${DDRESCUELOG}" -p out copy || fail2=1
293 "${DDRESCUELOG}" -p out ${logfile1} || fail2=1
294 "${DDRESCUELOG}" -p ${logfile1} copy || fail2=1
295 "${DDRESCUELOG}" -x ${logfile2} ${logfile2} > logfile || fail2=1
296 "${DDRESCUELOG}" -P ${blank} logfile || fail2=1
297 "${DDRESCUELOG}" -x ${logfile1} ${logfile1} > logfile || fail2=1
298 "${DDRESCUELOG}" -P ${blank} logfile || fail2=1
299 "${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail2=1
300 "${DDRESCUELOG}" -b2048 -l- logfile > copy || fail2=1
301 cmp out copy || fail2=1
302 "${DDRESCUELOG}" -b2048 -i0x2000 -s0x2800 -l+ ${logfile1} > out || fail2=1
303 "${DDRESCUELOG}" -i0x1800 -s0x3800 -x ${logfile1} ${logfile1} > logfile || fail2=1
304 "${DDRESCUELOG}" -b2048 -l- logfile > copy || fail2=1
305 cmp out copy || fail2=1
306 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
307
308 fail2=0
309 "${DDRESCUELOG}" -x ${logfile3} ${logfile4} > out || fail2=1
310 "${DDRESCUELOG}" -x ${logfile4} ${logfile3} > copy || fail2=1
311 "${DDRESCUELOG}" -p out copy || fail2=1
312 "${DDRESCUELOG}" -x ${logfile3} ${logfile5} > out || fail2=1
313 "${DDRESCUELOG}" -x ${logfile5} ${logfile3} > copy || fail2=1
314 "${DDRESCUELOG}" -p out copy || fail2=1
315 "${DDRESCUELOG}" -x ${logfile4} ${logfile5} > out || fail2=1
316 "${DDRESCUELOG}" -x ${logfile5} ${logfile4} > copy || fail2=1
317 "${DDRESCUELOG}" -p out copy || fail2=1
318 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
319
320 fail2=0
321 "${DDRESCUELOG}" -x ${logfile3} ${logfile4} > out || fail2=1
322 "${DDRESCUELOG}" -D out && fail2=1
323 "${DDRESCUELOG}" -x out ${logfile5} > logfile || fail2=1
324 "${DDRESCUELOG}" -d logfile || fail2=1
325
326 "${DDRESCUELOG}" -x ${logfile3} ${logfile5} > out || fail2=1
327 "${DDRESCUELOG}" -D out && fail2=1
328 "${DDRESCUELOG}" -x out ${logfile4} > logfile || fail2=1
329 "${DDRESCUELOG}" -d logfile || fail2=1
330
331 "${DDRESCUELOG}" -x ${logfile4} ${logfile3} > out || fail2=1
332 "${DDRESCUELOG}" -D out && fail2=1
333 "${DDRESCUELOG}" -x out ${logfile5} > logfile || fail2=1
334 "${DDRESCUELOG}" -d logfile || fail2=1
335
336 "${DDRESCUELOG}" -x ${logfile4} ${logfile5} > out || fail2=1
337 "${DDRESCUELOG}" -D out && fail2=1
338 "${DDRESCUELOG}" -x out ${logfile3} > logfile || fail2=1
339 "${DDRESCUELOG}" -d logfile || fail2=1
340
341 "${DDRESCUELOG}" -x ${logfile5} ${logfile3} > out || fail2=1
342 "${DDRESCUELOG}" -D out && fail2=1
343 "${DDRESCUELOG}" -x out ${logfile4} > logfile || fail2=1
344 "${DDRESCUELOG}" -d logfile || fail2=1
345
346 "${DDRESCUELOG}" -x ${logfile5} ${logfile4} > out || fail2=1
347 "${DDRESCUELOG}" -D out && fail2=1
348 "${DDRESCUELOG}" -x out ${logfile3} > logfile || fail2=1
349 "${DDRESCUELOG}" -d logfile || fail2=1
350 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
351
352 fail2=0 # test AND
353 for i in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
354 for j in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
355 "${DDRESCUELOG}" -y ${j} ${i} > out || fail2=1
356 "${DDRESCUELOG}" -y ${i} ${j} > copy || fail2=1
357 "${DDRESCUELOG}" -P out copy || fail2=1
358 done
359 done
360 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
361
362 fail2=0
363 "${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail2=1
364 "${DDRESCUELOG}" -y ${logfile1} ${logfile2} > logfile || fail2=1
365 "${DDRESCUELOG}" -P ${blank} logfile || fail2=1
366 "${DDRESCUELOG}" -b2048 -l? logfile > copy || fail2=1
367 cmp out copy || fail2=1
368 "${DDRESCUELOG}" -y ${logfile2} ${logfile1} > logfile || fail2=1
369 "${DDRESCUELOG}" -P ${blank} logfile || fail2=1
370 "${DDRESCUELOG}" -b2048 -l- logfile > copy || fail2=1
371 cmp out copy || fail2=1
372 "${DDRESCUELOG}" -b2048 -i0x2000 -s0x2800 -l+ ${logfile1} > out || fail2=1
373 "${DDRESCUELOG}" -i0x1800 -s0x3800 -y ${logfile2} ${logfile1} > logfile || fail2=1
374 "${DDRESCUELOG}" -b2048 -l- logfile > copy || fail2=1
375 cmp out copy || fail2=1
376 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
377
378 fail2=0
379 "${DDRESCUELOG}" -y ${logfile3} ${logfile4} > out || fail2=1
380 "${DDRESCUELOG}" -P ${blank} out || fail2=1
381 "${DDRESCUELOG}" -y ${logfile3} ${logfile5} > out || fail2=1
382 "${DDRESCUELOG}" -P ${blank} out || fail2=1
383 "${DDRESCUELOG}" -y ${logfile4} ${logfile5} > out || fail2=1
384 "${DDRESCUELOG}" -P ${blank} out || fail2=1
385 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
386
387 fail2=0
388 "${DDRESCUELOG}" -i0x2000 -s0x2800 -z ${logfile2} ${logfile1} > logfile || fail2=1
389 "${DDRESCUELOG}" -D logfile
390 if [ $? != 1 ] ; then fail2=1 ; fi
391 "${DDRESCUELOG}" -i0x1C00 -s0x2C00 -D logfile
392 if [ $? != 1 ] ; then fail2=1 ; fi
393 "${DDRESCUELOG}" -i0x2000 -s0x2C00 -D logfile
394 if [ $? != 1 ] ; then fail2=1 ; fi
395 "${DDRESCUELOG}" -i0x2000 -s0x2800 -d logfile
396 if [ $? != 0 ] ; then fail2=1 ; fi
397 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
398
399 fail2=0 # test OR
400 for i in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
401 for j in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
402 "${DDRESCUELOG}" -z ${j} ${i} > out || fail2=1
403 "${DDRESCUELOG}" -z ${i} ${j} > copy || fail2=1
404 "${DDRESCUELOG}" -P out copy || fail2=1
405 done
406 done
407 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
408
409 fail2=0
410 "${DDRESCUELOG}" -z ${logfile1} ${logfile2} > out || fail2=1
411 "${DDRESCUELOG}" -z ${logfile2} ${logfile1} > copy || fail2=1
412 "${DDRESCUELOG}" -p out copy || fail2=1
413 "${DDRESCUELOG}" -d out || fail2=1
414 "${DDRESCUELOG}" -d copy || fail2=1
415 "${DDRESCUELOG}" -z ${logfile1} ${blank} > out || fail2=1
416 "${DDRESCUELOG}" -z ${blank} ${logfile1} > copy || fail2=1
417 "${DDRESCUELOG}" -p out copy || fail2=1
418 "${DDRESCUELOG}" -p out ${logfile1} || fail2=1
419 "${DDRESCUELOG}" -p ${logfile1} copy || fail2=1
420 "${DDRESCUELOG}" -z ${logfile3} ${logfile4} > out || fail2=1
421 "${DDRESCUELOG}" -z ${logfile4} ${logfile3} > copy || fail2=1
422 "${DDRESCUELOG}" -p out copy || fail2=1
423 "${DDRESCUELOG}" -z ${logfile3} ${logfile5} > out || fail2=1
424 "${DDRESCUELOG}" -z ${logfile5} ${logfile3} > copy || fail2=1
425 "${DDRESCUELOG}" -p out copy || fail2=1
426 "${DDRESCUELOG}" -z ${logfile4} ${logfile5} > out || fail2=1
427 "${DDRESCUELOG}" -z ${logfile5} ${logfile4} > copy || fail2=1
428 "${DDRESCUELOG}" -p out copy || fail2=1
429 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
430
431 fail2=0
432 "${DDRESCUELOG}" -z ${logfile3} ${logfile4} > out || fail2=1
433 "${DDRESCUELOG}" -D out && fail2=1
434 "${DDRESCUELOG}" -z out ${logfile5} > logfile || fail2=1
435 "${DDRESCUELOG}" -d logfile || fail2=1
436
437 "${DDRESCUELOG}" -z ${logfile3} ${logfile5} > out || fail2=1
438 "${DDRESCUELOG}" -D out && fail2=1
439 "${DDRESCUELOG}" -z out ${logfile4} > logfile || fail2=1
440 "${DDRESCUELOG}" -d logfile || fail2=1
441
442 "${DDRESCUELOG}" -z ${logfile4} ${logfile3} > out || fail2=1
443 "${DDRESCUELOG}" -D out && fail2=1
444 "${DDRESCUELOG}" -z out ${logfile5} > logfile || fail2=1
445 "${DDRESCUELOG}" -d logfile || fail2=1
446
447 "${DDRESCUELOG}" -z ${logfile4} ${logfile5} > out || fail2=1
448 "${DDRESCUELOG}" -D out && fail2=1
449 "${DDRESCUELOG}" -z out ${logfile3} > logfile || fail2=1
450 "${DDRESCUELOG}" -d logfile || fail2=1
451
452 "${DDRESCUELOG}" -z ${logfile5} ${logfile3} > out || fail2=1
453 "${DDRESCUELOG}" -D out && fail2=1
454 "${DDRESCUELOG}" -z out ${logfile4} > logfile || fail2=1
455 "${DDRESCUELOG}" -d logfile || fail2=1
456
457 "${DDRESCUELOG}" -z ${logfile5} ${logfile4} > out || fail2=1
458 "${DDRESCUELOG}" -D out && fail2=1
459 "${DDRESCUELOG}" -z out ${logfile3} > logfile || fail2=1
460 "${DDRESCUELOG}" -d logfile || fail2=1
461 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
462
463 fail2=0 # test ( a && b ) == !( !a || !b )
464 for i in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
465 for j in ${logfile1} ${logfile2} ${logfile3} ${logfile4} ${logfile5} ; do
466 "${DDRESCUELOG}" -n ${i} > na || fail2=1
467 "${DDRESCUELOG}" -n ${j} > nb || fail2=1
468 "${DDRESCUELOG}" -z nb na > out || fail2=1
469 "${DDRESCUELOG}" -n out > copy || fail2=1
470 "${DDRESCUELOG}" -y ${j} ${i} > out || fail2=1
471 "${DDRESCUELOG}" -P out copy || fail2=1
472 done
473 done
474 if [ ${fail2} = 0 ] ; then printf . ; else printf - ; fail=1 ; fi
210475
211476 echo
212477 if [ ${fail} = 0 ] ; then
0 # Rescue Logfile. Created by GNU ddrescue version 1.11
1 # current_pos current_status
2 0x00000000 +
3 # pos size status
4 0x00000800 0x00000800 +
5 0x00001800 0x00000800 +
6 0x00002800 0x00000800 +
7 0x00003800 0x00000800 +
8 0x00004800 0x00000800 +
9 0x00005800 0x00000800 +
10 0x00006800 0x00000800 +
11 0x00007800 0x00000800 +
12 0x00008800 0x000003A0 +
0 # Rescue Logfile. Created by GNU ddrescue version 1.11
1 # current_pos current_status
2 0x00000000 +
3 # pos size status
4 0x00000000 0x00000800 +
5 0x00000800 0x00001000 ?
6 0x00001800 0x00000800 +
7 0x00002000 0x00001000 ?
8 0x00003000 0x00000800 +
9 0x00003800 0x00001000 ?
10 0x00004800 0x00000800 +
11 0x00005000 0x00001000 ?
12 0x00006000 0x00000800 +
13 0x00006800 0x00001000 ?
14 0x00007800 0x00000800 +
15 0x00008000 0x00000BA0 ?
0 # Rescue Logfile. Created by GNU ddrescue version 1.11
1 # current_pos current_status
2 0x00000000 +
3 # pos size status
4 0x00000000 0x00000800 ?
5 0x00000800 0x00000800 +
6 0x00001000 0x00001000 ?
7 0x00002000 0x00000800 +
8 0x00002800 0x00001000 ?
9 0x00003800 0x00000800 +
10 0x00004000 0x00001000 ?
11 0x00005000 0x00000800 +
12 0x00005800 0x00001000 ?
13 0x00006800 0x00000800 +
14 0x00007000 0x00001000 ?
15 0x00008000 0x00000800 +
16 0x00008800 0x000003A0 ?
0 # Rescue Logfile. Created by GNU ddrescue version 1.11
1 # current_pos current_status
2 0x00000000 +
3 # pos size status
4 0x00000000 0x00001000 ?
5 0x00001000 0x00000800 +
6 0x00001800 0x00001000 ?
7 0x00002800 0x00000800 +
8 0x00003000 0x00001000 ?
9 0x00004000 0x00000800 +
10 0x00004800 0x00001000 ?
11 0x00005800 0x00000800 +
12 0x00006000 0x00001000 ?
13 0x00007000 0x00000800 +
14 0x00007800 0x00001000 ?
15 0x00008800 0x000003A0 +
0 # Rescue Logfile. Created by GNU ddrescue version 1.11
1 # current_pos current_status
2 0x00000000 +
3 # pos size status
4 0x00000000 0x00008BA0 ?