pax_global_header 0000666 0000000 0000000 00000000064 12235656145 0014523 g ustar 00root root 0000000 0000000 52 comment=4503d76cd899bd9aa39183a863ef7a676fb94ee8
gddrescue-1.17/ 0000775 0000000 0000000 00000000000 12235656145 0013420 5 ustar 00root root 0000000 0000000 gddrescue-1.17/AUTHORS 0000664 0000000 0000000 00000000325 12235656145 0014470 0 ustar 00root root 0000000 0000000 GNU ddrescue was written by Antonio Diaz Diaz.
Thanks to Dave Burton for his ideas about the logfile format and the raw
devices.
Thanks also to the many people who have contributed useful ideas,
testing, etc...
gddrescue-1.17/COPYING 0000664 0000000 0000000 00000104374 12235656145 0014464 0 ustar 00root root 0000000 0000000
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
gddrescue-1.17/ChangeLog 0000664 0000000 0000000 00000025364 12235656145 0015204 0 ustar 00root root 0000000 0000000 2013-07-09 Antonio Diaz Diaz
* Version 1.17 released.
* Added new option '-l, --logfile-size'.
* Added new option '-w, --ignore-write-errors'.
* Option '--fill' has been renamed to '--fill-mode'.
* Option '--generate-logfile' has been renamed to '--generate-mode'.
* Added option '--sector-size' as a synonym of '--block-size'.
* Added option '--retries' as a synonym of '--max-retries'.
* Added option '--size' as a synonym of '--max-size'.
* rescuebook.cc: Trimming is now done from both edges of each
non-trimmed block. Largest blocks are trimmed first.
* rescuebook.cc: Largest blocks are now split first until
logfile reaches '--logfile-size' entries.
* logbook.cc (extend_sblock_vector, truncate_vector): Terminate
if truncation would discard finished blocks.
* rescuebook.cc: Mark failed blocks with 1 sector as bad-sector.
* logbook.cc (extend_sblock_vector): Remove last block of
logfile if it starts at isize and is not marked as finished.
* io.cc (show_status,update_rates): Detect a jump back in time
and adjust status.
* ddrescue.h (slow_read): Return false for the first 10 seconds.
* io.cc (show_status) Leave cursor after message so that ^C does
not overwrite it.
* main.cc: Do not require '--force' for generate mode.
* ddrescue.h (Logbook::logfile_exists): Do not return false if
logfile exists but is empty.
* Added new chapter 'Using ddrescue safely' to the manual.
* Documented that 'direct disc access' only reads whole sectors.
* configure: Options now accept a separate argument.
* Makefile.in: Added new target 'install-bin'.
2012-06-11 Antonio Diaz Diaz
* Version 1.16 released.
* Added new option '-K, --skip-size'.
* Added new option '-T, --timeout'.
* Changed short name of option '--try-again' to '-A'.
* Maximum skip size is now limited to 1% of infile size or 1 GiB
(whichever is smaller), rounded to the next multiple of sector
size.
* Set current_pos to end of block when reading backwards.
* The '-E, --max-error-rate' option now checks the rate of
actually failed reads, not the growth of error size.
* The option '-v, --verbose' now increases verbosity if repeated.
* Changed quote characters in messages as advised by GNU Standards.
* configure: 'datadir' renamed to 'datarootdir'.
* New files rational.h, rational.cc.
2012-01-01 Antonio Diaz Diaz
* Version 1.15 released.
* Added new option '-a, --min-read-rate'.
* Added new option '-I, --verify-input-size'.
* Added new option '-x, --extend-outfile'.
* main.cc: Verify that infile, outfile and logfile are all
different.
* Non-tried blocks are now read aligned to cluster-size sectors.
* rescuebook.cc: Improved skip algorithm for the split pass.
* main.cc: Removed spurious warning about '-D' ignored in fill mode.
* ddrescue.texinfo: Improved description of algorithm.
* logbook.cc (change_chunk_status): Return an adjust value (-1, 0, 1)
to keep "errors" updated without calling count_errors every time.
* ddrescue.cc: Renamed to io.cc.
* Added 'ddrescuelog', a program for logfile manipulation.
2011-01-10 Antonio Diaz Diaz
* Version 1.14 released.
* Added new option '-R, --reverse'.
* Added new option '-E, --max-error-rate'.
* Extended syntax '--max-errors=+N' to specify new errors.
* Changed short name of option '--retrim' to '-M'.
* Removed spurious warning about 'preallocation not available'.
* Code reorganization. New class 'Genbook'.
2010-08-27 Antonio Diaz Diaz
* Version 1.13 released.
* Non-regular output files are no more overwritten by default.
* Added new option '-f, --force'.
* Added new option '-p, --preallocate'.
* main.cc (write_logfile_header): Write command line to logfile.
* ddrescue.texinfo: Added info about logfile and recoverable formats.
* ddrescue.texinfo: Added a couple more warnings to the tutorial.
* testsuite: 'test1' renamed to 'test.txt'
* Revert to use 'long' instead of 'time_t' for time variables.
Ddrescue only needs counting seconds and 'time_t' causes
warnings on some systems.
2010-04-06 Antonio Diaz Diaz
* Version 1.12 released.
* main.cc: Outfile is now created with mode 0666 if umask allows it.
* main.cc: New constant 'o_binary'.
* Makefile.in: Added quotes to directory names.
* Makefile.in: Added '--name' option to help2man invocation.
* testsuite/check.sh: Use 'test1' instead of 'COPYING' for testing.
* Use 'time_t' instead of 'long' for time variables.
2009-07-10 Antonio Diaz Diaz
* Version 1.11 released.
* logbook.cc (update_logfile): Ask user in case of write error.
* rescuebook.cc (split_errors): Modified the split threshold.
* rescuebook.cc (copy_and_update): Verify after every read error
that the input file does still exist.
* ddrescue.cc (Rescuebook::show_status): Show the time elapsed
since last successful read.
* ddrescue.cc (set_signals): Ignore SIGUSR1 and SIGUSR2.
* ddrescue.texinfo: Improved description of '-d', '-D' and '-S'.
* ddrescue.texinfo: Improved description of algorithm.
* testsuite/check.sh: Verify that files are open in binary mode.
* Added logfile usage warning to 'ddrescue --help' output.
2009-02-19 Antonio Diaz Diaz
* Version 1.10 released.
* Added new option '-T, --try-again'.
* rescuebook.cc: 'skip_size' has been made independent of 'softbs'.
* 'change_chunk_status' is now faster for large logfiles.
* Fixed overflow when reading from devices of undefined size.
* Block does no more admit negative sizes.
* 'make install-info' should now work on Debian and OS X.
* New file testsuite/check.sh.
2008-11-17 Antonio Diaz Diaz
* Version 1.9 released.
* Added new option '-m, --domain-logfile'.
* Verbosity control of messages has been simplified.
* Changed LONG_LONG_MAX to LLONG_MAX.
2008-02-24 Antonio Diaz Diaz
* Version 1.8 released.
* Added new option '-g, --generate-logfile'.
* Added new option '-D, --synchronous'.
* Fill mode now works when outfile offset differs from 0.
* Updated 'Fill Mode' chapter of the manual.
2008-01-04 Antonio Diaz Diaz
* Version 1.7 released.
* Skips faster over damaged areas (small read, big jump).
* Logfile is maintaned minimized at all times.
* Rescuebook::errors now counts the error areas found.
* Target 'check' added to Makefile.
* rescuebook.cc (split_errors): Added new variable 'error_counter'.
* Added new option '-R, --retrim'.
2007-11-16 Antonio Diaz Diaz
* Version 1.6 released.
* Code reorganization. New classes 'Fillbook' and 'Rescuebook'.
* logbook.cc (copy_non_tried): Added new variable 'skip_counter'.
* Added new pass that trims error areas backward before splitting.
* Added support for sparse output files.
* Blocks longer than hardbs are now split at sector boundaries.
* Added new option '-F, --fill'.
* Added new chapter 'Fill Mode' to the manual.
* Added status line to logfile.
* An interrupted retry pass is now resumed instead of reinitiated.
* Perfect resumability if interrupted during trimming or splitting.
* ddrescue.cc (set_signals): Handle also SIGHUP and SIGTERM.
* '--quiet' option also quiets error messages.
* Print a more informative error message when reading an old logfile.
* Added note to ddrescue.texinfo about old logfiles.
* Added some consistency checks.
2007-06-29 Antonio Diaz Diaz
* Version 1.5 released.
* License updated to GPL version 3 or later.
2007-06-18 Antonio Diaz Diaz
* Version 1.4 released.
* Added new option '-d, --direct'.
* Fixed a bug showing bad initial error size.
* Fixed error counting.
* Small changes to documentation.
2006-12-13 Antonio Diaz Diaz
* Version 1.3 released.
* Some fixes made to 'configure' script.
* Added 'sddrescue' target to Makefile.in.
2006-04-03 Antonio Diaz Diaz
* Version 1.2 released.
* Added new option '-C, --complete-only'.
* Added new argument parser that replaces 'getopt_long'.
* Logfile save interval is now dependent on logfile size.
* Small changes to documentation.
2005-10-10 Antonio Diaz Diaz
* Version 1.1 released.
* 'iobuf' is aligned to the sector size for use with raw devices.
* Added a small tutorial to the info file.
* Added two missing headers.
2005-06-07 Antonio Diaz Diaz
* Version 1.0 released.
* A new logfile format makes multi-part rescue possible.
* Logfile is saved every 30 seconds.
* Logfile is now also saved in case of write error on outfile.
* Fixed a race condition that could result in data not written
to outfile but annotated in logfile if computer crashes at
the wrong moment.
2005-01-04 Antonio Diaz Diaz
* Version 0.9 released.
* ddrescue is now part of the GNU project.
* Added configure script and info file.
* Two small bugs corrected.
* Added new option '-B, --binary-prefixes' to show binary
multipliers in numbers (SI prefixes are used by default).
* Numbers are accepted with decimal (SI) or binary multipliers.
* 'badblocks file' renamed to 'logfile'.
* Logfile is now also saved if max_errors are exceeded.
2004-12-14 Antonio Diaz Diaz
* Version 0.8 released.
* Added new option '-n, --no-split' to disable splitting of
damaged areas.
2004-10-30 Antonio Diaz Diaz
* Version 0.7 released.
* ddrescue now can be interrupted at any time, and resume
rescue at the same point later.
2004-09-28 Antonio Diaz Diaz
* Version 0.6 released.
* Skips faster over damaged areas (tries 1 block first).
* Error messages have been improved.
2004-09-15 Antonio Diaz Diaz
* Version 0.5 released.
* Badblocks file is now also saved if ddrescue is interrupted
while splitting damaged areas.
* Added man page.
2004-09-03 Antonio Diaz Diaz
* Version 0.4 released.
* The project name has been changed to 'ddrescue' to meet
command name standards.
* Added long option names.
2004-08-18 Antonio Diaz Diaz
* Version 0.3 released.
* Added badblocks file, making the rescue much more efficient.
2004-08-14 Antonio Diaz Diaz
* Version 0.2 released.
* Fixed bug that sometimes ignored the last sectors of a damaged area.
* The algorithm is now faster in presence of errors.
2004-08-12 Antonio Diaz Diaz
* Version 0.1 released.
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This file is a collection of facts, and thus it is not copyrightable,
but just in case, you have unlimited permission to copy, distribute and
modify it.
gddrescue-1.17/INSTALL 0000664 0000000 0000000 00000003367 12235656145 0014462 0 ustar 00root root 0000000 0000000 Requirements
------------
You will need a C++ compiler.
I use gcc 4.8.1 and 3.3.6, but the code should compile with any
standards compliant compiler.
Gcc is available at http://gcc.gnu.org.
Procedure
---------
1. Unpack the archive if you have not done so already:
lzip -cd ddrescue[version].tar.lz | tar -xf -
or
gzip -cd ddrescue[version].tar.gz | tar -xf -
This creates the directory ./ddrescue[version] containing the source from
the main archive.
2. Change to ddrescue directory and run configure.
(Try 'configure --help' for usage instructions).
cd ddrescue[version]
./configure
3. Run make.
make
4. Optionally, type 'make check' to run the tests that come with ddrescue.
5. Type 'make install' to install the program and any data files and
documentation.
You can install only the program, the info manual or the man page
typing 'make install-bin', 'make install-info' or 'make install-man'
respectively.
Another way
-----------
You can also compile ddrescue into a separate directory. To do this, you
must use a version of 'make' that supports the 'VPATH' variable, such
as GNU 'make'. 'cd' to the directory where you want the object files
and executables to go and run the 'configure' script. 'configure'
automatically checks for the source code in '.', in '..' and in the
directory that 'configure' is in.
'configure' recognizes the option '--srcdir=DIR' to control where to
look for the sources. Usually 'configure' can determine that directory
automatically.
After running 'configure', you can run 'make' and 'make install' as
explained above.
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy,
distribute and modify it.
gddrescue-1.17/Makefile.in 0000664 0000000 0000000 00000010122 12235656145 0015461 0 ustar 00root root 0000000 0000000
DISTNAME = $(pkgname)-$(pkgversion)
INSTALL = install
INSTALL_PROGRAM = $(INSTALL) -p -m 755
INSTALL_DATA = $(INSTALL) -p -m 644
INSTALL_DIR = $(INSTALL) -d -m 755
SHELL = /bin/sh
ddobjs = block.o fillbook.o genbook.o io.o logbook.o rescuebook.o main.o
objs = arg_parser.o rational.o $(ddobjs)
logobjs = arg_parser.o block.o logbook.o ddrescuelog.o
.PHONY : all install install-bin install-info install-man install-strip \
uninstall uninstall-bin uninstall-info uninstall-man \
doc info man check dist clean distclean
all : $(progname) ddrescuelog
$(progname) : $(objs)
$(CXX) $(LDFLAGS) -o $@ $(objs)
$(progname)_profiled : $(objs)
$(CXX) $(LDFLAGS) -pg -o $@ $(objs)
ddrescuelog : $(logobjs)
$(CXX) $(LDFLAGS) -o $@ $(logobjs)
static_$(progname) : $(objs)
$(CXX) $(LDFLAGS) -static -o $@ $(objs)
main.o : main.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
ddrescuelog.o : ddrescuelog.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
%.o : %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
$(objs) : Makefile
$(ddobjs) : block.h ddrescue.h
arg_parser.o : arg_parser.h
rational.o : rational.h
main.o : arg_parser.h rational.h main_common.cc
ddrescuelog.o : Makefile arg_parser.h block.h ddrescue.h main_common.cc
doc : info man
info : $(VPATH)/doc/$(pkgname).info
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/ddrescuelog.1
$(VPATH)/doc/$(progname).1 : $(progname)
help2man -n 'data recovery tool' \
-o $@ ./$(progname)
$(VPATH)/doc/ddrescuelog.1 : ddrescuelog
help2man -n 'tool for ddrescue logfiles' \
-o $@ --no-info ./ddrescuelog
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
./config.status
check : all
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
install : install-bin install-info install-man
install-bin : all
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
$(INSTALL_PROGRAM) ./ddrescuelog "$(DESTDIR)$(bindir)/ddrescuelog"
install-info :
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
-install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info"
install-man :
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
$(INSTALL_DATA) $(VPATH)/doc/ddrescuelog.1 "$(DESTDIR)$(mandir)/man1/ddrescuelog.1"
install-strip : all
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
uninstall : uninstall-bin uninstall-info uninstall-man
uninstall-bin :
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
-rm -f "$(DESTDIR)$(bindir)/ddrescuelog"
uninstall-info :
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"
uninstall-man :
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"
-rm -f "$(DESTDIR)$(mandir)/man1/ddrescuelog.1"
dist : doc
ln -sf $(VPATH) $(DISTNAME)
tar -cvf $(DISTNAME).tar \
$(DISTNAME)/AUTHORS \
$(DISTNAME)/COPYING \
$(DISTNAME)/ChangeLog \
$(DISTNAME)/INSTALL \
$(DISTNAME)/Makefile.in \
$(DISTNAME)/NEWS \
$(DISTNAME)/README \
$(DISTNAME)/configure \
$(DISTNAME)/doc/$(progname).1 \
$(DISTNAME)/doc/ddrescuelog.1 \
$(DISTNAME)/doc/$(pkgname).info \
$(DISTNAME)/doc/$(pkgname).texinfo \
$(DISTNAME)/testsuite/check.sh \
$(DISTNAME)/testsuite/logfile1 \
$(DISTNAME)/testsuite/logfile2 \
$(DISTNAME)/testsuite/test.txt \
$(DISTNAME)/testsuite/test1.txt \
$(DISTNAME)/testsuite/test2.txt \
$(DISTNAME)/*.h \
$(DISTNAME)/*.cc
rm -f $(DISTNAME)
lzip -v -9 $(DISTNAME).tar
clean :
-rm -f $(progname) $(progname)_profiled $(objs)
-rm -f static_$(progname) ddrescuelog ddrescuelog.o
distclean : clean
-rm -f Makefile config.status *.tar *.tar.lz
gddrescue-1.17/NEWS 0000664 0000000 0000000 00000003633 12235656145 0014124 0 ustar 00root root 0000000 0000000 Changes in version 1.17:
The new option "-l, --logfile-size" has been added.
The new option "-w, --ignore-write-errors", which makes fill mode ignore
write errors, has been added.
The option "--fill" has been renamed to "--fill-mode".
The option '--generate-logfile' has been renamed to '--generate-mode'.
The option "--sector-size" has been added as a synonym of "--block-size".
The option "--retries" has been added as a synonym of "--max-retries".
The option "--size" has been added as a synonym of "--max-size".
Trimming is now done from both edges of each non-trimmed block. Largest
blocks are trimmed first.
Largest blocks are now split first until logfile reaches
"--logfile-size" entries.
Ddrescue now terminates with an error if an unexpected EOF would discard
any successfully read data, just as it does when the input file
disappears from /dev.
During the copying phase, failed blocks containing one sector are marked
as bad-sector instead of as non-trimmed. This avoids reading a sector
twice when a cluster size of 1 is used.
Ddrescue now removes the last block from the logfile if it starts at the
end of the input file and is not marked as finished. This automatically
adjusts the logfile to shrinking input devices, like CD-ROMs written in
Track-At-Once mode.
A bug has been fixed that prevented status to update after the system
clock had been put back.
Slow reads are now ignored during the first 10 seconds.
Control-C no more overwrites status message.
Generate mode no more requires the "--force" option when outfile is not
a regular file.
Ddrescuelog no more says that the logfile does not exist when it exists
but is empty.
The new chapter "Using ddrescue safely" has been added to the manual.
The manual now explains that only whole sectors can be read when "direct
disc access" is used.
"configure" now accepts options with a separate argument.
The target "install-bin" has been added to the Makefile.
gddrescue-1.17/README 0000664 0000000 0000000 00000007330 12235656145 0014303 0 ustar 00root root 0000000 0000000 Description
GNU ddrescue is a data recovery tool. It copies data from one file or
block device (hard disc, cdrom, etc) to another, trying hard to rescue
data in case of read errors.
Ddrescuelog is a tool that manipulates ddrescue logfiles, shows logfile
contents, converts logfiles to/from other formats, compares logfiles,
tests rescue status, and can delete a logfile if the rescue is done.
Ddrescuelog operations can be restricted to one or several parts of the
logfile if the domain setting options are used.
The basic operation of ddrescue is fully automatic. That is, you don't
have to wait for an error, stop the program, read the log, restart it
from a new position, etc.
If you use the logfile feature of ddrescue, the data is rescued very
efficiently, (only the needed blocks are read). Also you can interrupt
the rescue at any time and resume it later at the same point.
Ddrescue does not write zeros to the output when it finds bad sectors in
the input, and does not truncate the output file if not asked to. So,
every time you run it on the same output file, it tries to fill in the
gaps without wiping out the data already rescued.
Automatic merging of backups: If you have two or more damaged copies of
a file, cdrom, etc, and run ddrescue on all of them, one at a time,
with the same output file, you will probably obtain a complete and
error-free file. This is so because the probability of having damaged
areas at the same places on different input files is very low. Using
the logfile, only the needed blocks are read from the second and
successive copies.
Ddrescue recommends lzip for compression of backups because of its
reliability and data recovery capabilities, including error-checked
merging of backup copies. Lziprecover makes lzip files resistant to
bit-flip, one of the most common forms of data corruption, and its
recovery capabilities contribute to make of the lzip format one of the
best formats for long-term data archiving. The combination ddrescue +
lziprecover is the best option for recovering data from multiple damaged
copies.
Recordable CD and DVD media keep their data only for a finite time
(typically for many years). After that time, data loss develops slowly
with read errors growing from the outer media region towards the inside.
Just make two (or more) copies of every important CD/DVD you burn so
that you can later recover them with ddrescue.
The logfile is periodically saved to disc. So in case of a crash you can
resume the rescue with little recopying.
Also, the same logfile can be used for multiple commands that copy
different areas of the file, and for multiple recovery attempts over
different subsets.
Because ddrescue needs to read and write at random places, it only works
on seekable (random access) input and output files.
If your system supports it, ddrescue can use direct disc access to read
the input file, bypassing the kernel cache.
Ddrescue aligns its I/O buffer to the sector size so that it can be used
for direct disc access or to read from raw devices. For efficiency
reasons, also aligns it to the memory page size if page size is a
multiple of sector size. Read the info file to learn how to use direct
disc access or raw devices with ddrescue.
Ddrescue also features a "fill mode" able to selectively overwrite parts
of the output file, which has a number of interesting uses like wiping
data, marking bad areas or even, in some cases, "repair" damaged
sectors.
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy,
distribute and modify it.
The file Makefile.in is a data file used by configure to produce the
Makefile. It has the same copyright owner and permissions that configure
itself.
gddrescue-1.17/arg_parser.cc 0000664 0000000 0000000 00000014414 12235656145 0016060 0 ustar 00root root 0000000 0000000 /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library. If not, see .
As a special exception, you may use this file as part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this
file, or you compile this file and link it with other files to
produce an executable, this file does not by itself cause the
resulting executable to be covered by the GNU General Public
License. This exception does not however invalidate any other
reasons why the executable file might be covered by the GNU General
Public License.
*/
#include
#include
#include
#include "arg_parser.h"
bool Arg_parser::parse_long_option( const char * const opt, const char * const arg,
const Option options[], int & argind )
{
unsigned len;
int index = -1;
bool exact = false, ambig = false;
for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
// Test all long options for either exact match or abbreviated matches.
for( int i = 0; options[i].code != 0; ++i )
if( options[i].name && std::strncmp( options[i].name, &opt[2], len ) == 0 )
{
if( std::strlen( options[i].name ) == len ) // Exact match found
{ index = i; exact = true; break; }
else if( index < 0 ) index = i; // First nonexact match found
else if( options[index].code != options[i].code ||
options[index].has_arg != options[i].has_arg )
ambig = true; // Second or later nonexact match found
}
if( ambig && !exact )
{
error_ = "option '"; error_ += opt; error_ += "' is ambiguous";
return false;
}
if( index < 0 ) // nothing found
{
error_ = "unrecognized option '"; error_ += opt; error_ += '\'';
return false;
}
++argind;
data.push_back( Record( options[index].code ) );
if( opt[len+2] ) // '--=' syntax
{
if( options[index].has_arg == no )
{
error_ = "option '--"; error_ += options[index].name;
error_ += "' doesn't allow an argument";
return false;
}
if( options[index].has_arg == yes && !opt[len+3] )
{
error_ = "option '--"; error_ += options[index].name;
error_ += "' requires an argument";
return false;
}
data.back().argument = &opt[len+3];
return true;
}
if( options[index].has_arg == yes )
{
if( !arg || !arg[0] )
{
error_ = "option '--"; error_ += options[index].name;
error_ += "' requires an argument";
return false;
}
++argind; data.back().argument = arg;
return true;
}
return true;
}
bool Arg_parser::parse_short_option( const char * const opt, const char * const arg,
const Option options[], int & argind )
{
int cind = 1; // character index in opt
while( cind > 0 )
{
int index = -1;
const unsigned char c = opt[cind];
if( c != 0 )
for( int i = 0; options[i].code; ++i )
if( c == options[i].code )
{ index = i; break; }
if( index < 0 )
{
error_ = "invalid option -- "; error_ += c;
return false;
}
data.push_back( Record( c ) );
if( opt[++cind] == 0 ) { ++argind; cind = 0; } // opt finished
if( options[index].has_arg != no && cind > 0 && opt[cind] )
{
data.back().argument = &opt[cind]; ++argind; cind = 0;
}
else if( options[index].has_arg == yes )
{
if( !arg || !arg[0] )
{
error_ = "option requires an argument -- "; error_ += c;
return false;
}
data.back().argument = arg; ++argind; cind = 0;
}
}
return true;
}
Arg_parser::Arg_parser( const int argc, const char * const argv[],
const Option options[], const bool in_order )
{
if( argc < 2 || !argv || !options ) return;
std::vector< std::string > non_options; // skipped non-options
int argind = 1; // index in argv
while( argind < argc )
{
const unsigned char ch1 = argv[argind][0];
const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 );
if( ch1 == '-' && ch2 ) // we found an option
{
const char * const opt = argv[argind];
const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0;
if( ch2 == '-' )
{
if( !argv[argind][2] ) { ++argind; break; } // we found "--"
else if( !parse_long_option( opt, arg, options, argind ) ) break;
}
else if( !parse_short_option( opt, arg, options, argind ) ) break;
}
else
{
if( !in_order ) non_options.push_back( argv[argind++] );
else { data.push_back( Record() ); data.back().argument = argv[argind++]; }
}
}
if( error_.size() ) data.clear();
else
{
for( unsigned i = 0; i < non_options.size(); ++i )
{ data.push_back( Record() ); data.back().argument.swap( non_options[i] ); }
while( argind < argc )
{ data.push_back( Record() ); data.back().argument = argv[argind++]; }
}
}
Arg_parser::Arg_parser( const char * const opt, const char * const arg,
const Option options[] )
{
if( !opt || !opt[0] || !options ) return;
if( opt[0] == '-' && opt[1] ) // we found an option
{
int argind = 1; // dummy
if( opt[1] == '-' )
{ if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
else
parse_short_option( opt, arg, options, argind );
if( error_.size() ) data.clear();
}
else { data.push_back( Record() ); data.back().argument = opt; }
}
gddrescue-1.17/arg_parser.h 0000664 0000000 0000000 00000007704 12235656145 0015726 0 ustar 00root root 0000000 0000000 /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library. If not, see .
As a special exception, you may use this file as part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this
file, or you compile this file and link it with other files to
produce an executable, this file does not by itself cause the
resulting executable to be covered by the GNU General Public
License. This exception does not however invalidate any other
reasons why the executable file might be covered by the GNU General
Public License.
*/
/* Arg_parser reads the arguments in 'argv' and creates a number of
option codes, option arguments and non-option arguments.
In case of error, 'error' returns a non-empty error message.
'options' is an array of 'struct Option' terminated by an element
containing a code which is zero. A null name means a short-only
option. A code value outside the unsigned char range means a
long-only option.
Arg_parser normally makes it appear as if all the option arguments
were specified before all the non-option arguments for the purposes
of parsing, even if the user of your program intermixed option and
non-option arguments. If you want the arguments in the exact order
the user typed them, call 'Arg_parser' with 'in_order' = true.
The argument '--' terminates all options; any following arguments are
treated as non-option arguments, even if they begin with a hyphen.
The syntax for optional option arguments is '-'
(without whitespace), or '--='.
*/
class Arg_parser
{
public:
enum Has_arg { no, yes, maybe };
struct Option
{
int code; // Short option letter or code ( code != 0 )
const char * name; // Long option name (maybe null)
Has_arg has_arg;
};
private:
struct Record
{
int code;
std::string argument;
explicit Record( const int c = 0 ) : code( c ) {}
};
std::string error_;
std::vector< Record > data;
bool parse_long_option( const char * const opt, const char * const arg,
const Option options[], int & argind );
bool parse_short_option( const char * const opt, const char * const arg,
const Option options[], int & argind );
public:
Arg_parser( const int argc, const char * const argv[],
const Option options[], const bool in_order = false );
// Restricted constructor. Parses a single token and argument (if any)
Arg_parser( const char * const opt, const char * const arg,
const Option options[] );
const std::string & error() const { return error_; }
// The number of arguments parsed (may be different from argc)
int arguments() const { return data.size(); }
// If code( i ) is 0, argument( i ) is a non-option.
// Else argument( i ) is the option's argument (or empty).
int code( const int i ) const
{
if( i >= 0 && i < arguments() ) return data[i].code;
else return 0;
}
const std::string & argument( const int i ) const
{
if( i >= 0 && i < arguments() ) return data[i].argument;
else return error_;
}
};
gddrescue-1.17/block.cc 0000664 0000000 0000000 00000005610 12235656145 0015023 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include "block.h"
#include "ddrescue.h"
// Align pos to next boundary if size is big enough
//
void Block::align_pos( const int alignment )
{
if( alignment > 1 )
{
const int disp = alignment - ( pos_ % alignment );
if( disp < alignment && disp < size_ )
{ pos_ += disp; size_ -= disp; }
}
}
// Align end to previous boundary if size is big enough
//
void Block::align_end( const int alignment )
{
if( alignment > 1 && size_ > 0 )
{
const long long new_end = end() - ( end() % alignment );
if( pos_ < new_end ) size_ = new_end - pos_;
}
}
void Block::crop( const Block & b )
{
const long long p = std::max( pos_, b.pos_ );
const long long s = std::max( 0LL, std::min( end(), b.end() ) - p );
pos_ = p; size_ = s;
}
bool Block::join( const Block & b )
{
if( this->follows( b ) ) pos_ = b.pos_;
else if( !b.follows( *this ) ) return false;
size_ += b.size_;
if( size_ < 0 || size_ > LLONG_MAX - pos_ )
internal_error( "size overflow joining two Blocks" );
return true;
}
Block Block::split( long long pos, const int hardbs )
{
if( hardbs > 1 ) pos -= pos % hardbs;
if( pos_ < pos && end() > pos )
{
const Block b( pos_, pos - pos_ );
pos_ = pos; size_ -= b.size_;
return b;
}
return Block( 0, 0 );
}
void Domain::crop( const Block & b )
{
for( unsigned i = block_vector.size(); i > 0; )
{
block_vector[--i].crop( b );
if( block_vector[i].size() <= 0 )
block_vector.erase( block_vector.begin() + i );
}
if( block_vector.size() == 0 ) block_vector.push_back( Block( 0, 0 ) );
}
void Domain::crop_by_file_size( const long long end )
{
unsigned i = block_vector.size();
while( i > 0 && block_vector[i-1].pos() >= end ) --i;
if( i == 0 )
block_vector[0].assign( 0, 0 );
else
{
Block & b = block_vector[--i];
if( b.includes( end ) ) b.size( end - b.pos() );
}
block_vector.erase( block_vector.begin() + i + 1, block_vector.end() );
}
gddrescue-1.17/block.h 0000664 0000000 0000000 00000012470 12235656145 0014667 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef LLONG_MAX
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
#endif
class Block
{
long long pos_, size_; // pos + size <= LLONG_MAX
public:
Block( const long long p, const long long s )
: pos_( p ), size_( s ) {}
long long pos() const { return pos_; }
long long size() const { return size_; }
long long end() const { return pos_ + size_; }
void pos( const long long p ) { pos_ = p; }
void size( const long long s ) { size_ = s; }
void end( const long long e )
{ pos_ = e - size_; if( pos_ < 0 ) { size_ += pos_; pos_ = 0; } }
Block & assign( const long long p, const long long s )
{ pos_ = p; size_ = s; return *this; }
void fix_size() // limit size_ to largest possible value
{ if( size_ < 0 || size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; }
void align_pos( const int alignment );
void align_end( const int alignment );
void inc_size( const long long delta ) { size_ += delta; }
bool operator==( const Block & b ) const
{ return pos_ == b.pos_ && size_ == b.size_; }
bool operator!=( const Block & b ) const
{ return pos_ != b.pos_ || size_ != b.size_; }
bool follows( const Block & b ) const
{ return ( pos_ == b.end() ); }
bool includes( const Block & b ) const
{ return ( pos_ <= b.pos_ && end() >= b.end() ); }
bool includes( const long long pos ) const
{ return ( pos_ <= pos && end() > pos ); }
void crop( const Block & b );
bool join( const Block & b );
Block split( long long pos, const int hardbs = 1 );
};
class Sblock : public Block
{
public:
enum Status
{ non_tried = '?', non_trimmed = '*', non_split = '/',
bad_sector = '-', finished = '+' };
private:
Status status_;
public:
Sblock( const Block & b, const Status st )
: Block( b ), status_( st ) {}
Sblock( const long long p, const long long s, const Status st )
: Block( p, s ), status_( st ) {}
Status status() const { return status_; }
void status( const Status st ) { status_ = st; }
bool operator!=( const Sblock & sb ) const
{ return Block::operator!=( sb ) || status_ != sb.status_; }
bool join( const Sblock & sb )
{ if( status_ == sb.status_ ) return Block::join( sb ); else return false; }
Sblock split( const long long pos, const int hardbs = 1 )
{ return Sblock( Block::split( pos, hardbs ), status_ ); }
static bool isstatus( const int st )
{ return ( st == non_tried || st == non_trimmed || st == non_split ||
st == bad_sector || st == finished ); }
static bool is_good_status( const Status st )
{ return ( st == non_tried || st == finished ); }
};
class Domain
{
std::vector< Block > block_vector; // blocks are ordered and don't overlap
public:
Domain( const long long p, const long long s, const char * const logname = 0 );
long long pos() const { return block_vector[0].pos(); }
long long size() const
{ return block_vector.back().end() - block_vector[0].pos(); }
long long end() const { return block_vector.back().end(); }
int blocks() const { return (int)block_vector.size(); }
long long in_size() const
{
long long s = 0;
for( unsigned i = 0; i < block_vector.size(); ++i )
s += block_vector[i].size();
return s;
}
bool operator!=( const Domain & d ) const
{
if( block_vector.size() != d.block_vector.size() ) return true;
for( unsigned i = 0; i < block_vector.size(); ++i )
if( block_vector[i] != d.block_vector[i] ) return true;
return false;
}
bool operator<( const Block & b ) const
{ return ( block_vector.back().end() <= b.pos() ); }
long long breaks_block_by( const Block & b ) const
{
for( unsigned i = 0; i < block_vector.size(); ++i )
{
const Block & db = block_vector[i];
if( b.includes( db.pos() ) && b.pos() < db.pos() ) return db.pos();
const long long end = db.end();
if( b.includes( end ) && b.pos() < end ) return end;
}
return 0;
}
bool includes( const Block & b ) const
{
for( unsigned i = 0; i < block_vector.size(); ++i )
if( block_vector[i].includes( b ) ) return true;
return false;
}
bool includes( const long long pos ) const
{
for( unsigned i = 0; i < block_vector.size(); ++i )
if( block_vector[i].includes( pos ) ) return true;
return false;
}
void clear()
{ block_vector.clear(); block_vector.push_back( Block( 0, 0 ) ); }
void crop( const Block & b );
void crop_by_file_size( const long long end );
};
gddrescue-1.17/configure 0000775 0000000 0000000 00000013147 12235656145 0015335 0 ustar 00root root 0000000 0000000 #! /bin/sh
# configure script for GNU ddrescue - Data recovery tool
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
# 2013 Antonio Diaz Diaz.
#
# This configure script is free software: you have unlimited permission
# to copy, distribute and modify it.
pkgname=ddrescue
pkgversion=1.17
progname=ddrescue
srctrigger=ddrescue.h
# clear some things potentially inherited from environment.
LC_ALL=C
export LC_ALL
srcdir=
prefix=/usr/local
exec_prefix='$(prefix)'
bindir='$(exec_prefix)/bin'
datarootdir='$(prefix)/share'
infodir='$(datarootdir)/info'
mandir='$(datarootdir)/man'
CXX=g++
CPPFLAGS=
CXXFLAGS='-Wall -W -O2'
LDFLAGS=
# checking whether we are using GNU C++.
${CXX} --version > /dev/null 2>&1
if [ $? != 0 ] ; then
CXX=c++
CXXFLAGS='-W -O2'
fi
# Loop over all args
args=
no_create=
while [ $# != 0 ] ; do
# Get the first arg, and shuffle
option=$1 ; arg2=no
shift
# Add the argument quoted to args
args="${args} \"${option}\""
# Split out the argument for options that take them
case ${option} in
*=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
esac
# Process the options
case ${option} in
--help | -h)
echo "Usage: configure [options]"
echo
echo "Options: [defaults in brackets]"
echo " -h, --help display this help and exit"
echo " -V, --version output version information and exit"
echo " --srcdir=DIR find the sources in DIR [. or ..]"
echo " --prefix=DIR install into DIR [${prefix}]"
echo " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]"
echo " --bindir=DIR user executables directory [${bindir}]"
echo " --datarootdir=DIR base directory for doc and data [${datarootdir}]"
echo " --infodir=DIR info files directory [${infodir}]"
echo " --mandir=DIR man pages directory [${mandir}]"
echo " CXX=COMPILER C++ compiler to use [g++]"
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
echo
exit 0 ;;
--version | -V)
echo "Configure script for GNU ${pkgname} version ${pkgversion}"
exit 0 ;;
--srcdir) srcdir=$1 ; arg2=yes ;;
--prefix) prefix=$1 ; arg2=yes ;;
--exec-prefix) exec_prefix=$1 ; arg2=yes ;;
--bindir) bindir=$1 ; arg2=yes ;;
--datarootdir) datarootdir=$1 ; arg2=yes ;;
--infodir) infodir=$1 ; arg2=yes ;;
--mandir) mandir=$1 ; arg2=yes ;;
--srcdir=*) srcdir=${optarg} ;;
--prefix=*) prefix=${optarg} ;;
--exec-prefix=*) exec_prefix=${optarg} ;;
--bindir=*) bindir=${optarg} ;;
--datarootdir=*) datarootdir=${optarg} ;;
--infodir=*) infodir=${optarg} ;;
--mandir=*) mandir=${optarg} ;;
--no-create) no_create=yes ;;
CXX=*) CXX=${optarg} ;;
CPPFLAGS=*) CPPFLAGS=${optarg} ;;
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
LDFLAGS=*) LDFLAGS=${optarg} ;;
--*)
echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;;
*=* | *-*-*) ;;
*)
echo "configure: unrecognized option: '${option}'" 1>&2
echo "Try 'configure --help' for more information." 1>&2
exit 1 ;;
esac
# Check if the option took a separate argument
if [ "${arg2}" = yes ] ; then
if [ $# != 0 ] ; then args="${args} \"$1\"" ; shift
else echo "configure: Missing argument to '${option}'" 1>&2
exit 1
fi
fi
done
# Find the source files, if location was not specified.
srcdirtext=
if [ -z "${srcdir}" ] ; then
srcdirtext="or . or .." ; srcdir=.
if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
## the sed command below emulates the dirname command
srcdir=`echo $0 | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
fi
fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" 1>&2
echo "configure: (At least ${srctrigger} is missing)." 1>&2
exit 1
fi
# Set srcdir to . if that's what it is.
if [ "`pwd`" = "`cd "${srcdir}" ; pwd`" ] ; then srcdir=. ; fi
echo
if [ -z "${no_create}" ] ; then
echo "creating config.status"
rm -f config.status
cat > config.status << EOF
#! /bin/sh
# This file was generated automatically by configure. Do not edit.
# Run this file to recreate the current configuration.
#
# This script is free software: you have unlimited permission
# to copy, distribute and modify it.
exec /bin/sh $0 ${args} --no-create
EOF
chmod +x config.status
fi
echo "creating Makefile"
echo "VPATH = ${srcdir}"
echo "prefix = ${prefix}"
echo "exec_prefix = ${exec_prefix}"
echo "bindir = ${bindir}"
echo "datarootdir = ${datarootdir}"
echo "infodir = ${infodir}"
echo "mandir = ${mandir}"
echo "CXX = ${CXX}"
echo "CPPFLAGS = ${CPPFLAGS}"
echo "CXXFLAGS = ${CXXFLAGS}"
echo "LDFLAGS = ${LDFLAGS}"
rm -f Makefile
cat > Makefile << EOF
# Makefile for GNU ddrescue - Data recovery tool
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
# 2013 Antonio Diaz Diaz.
# This file was generated automatically by configure. Do not edit.
#
# This Makefile is free software: you have unlimited permission
# to copy, distribute and modify it.
pkgname = ${pkgname}
pkgversion = ${pkgversion}
progname = ${progname}
VPATH = ${srcdir}
prefix = ${prefix}
exec_prefix = ${exec_prefix}
bindir = ${bindir}
datarootdir = ${datarootdir}
infodir = ${infodir}
mandir = ${mandir}
CXX = ${CXX}
CPPFLAGS = ${CPPFLAGS}
CXXFLAGS = ${CXXFLAGS}
LDFLAGS = ${LDFLAGS}
EOF
cat "${srcdir}/Makefile.in" >> Makefile
echo "OK. Now you can run make."
gddrescue-1.17/ddrescue.h 0000664 0000000 0000000 00000025572 12235656145 0015402 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
class Logbook
{
public:
enum Status
{ copying = '?', trimming = '*', splitting = '/', retrying = '-',
filling = 'F', generating = 'G', finished = '+' };
private:
const long long offset_; // outfile offset (opos - ipos);
long long current_pos_;
long long logfile_isize_;
Status current_status_;
Domain & domain_; // rescue domain
uint8_t *iobuf_base, *iobuf_; // iobuf is aligned to page and hardbs
const char * const filename_;
const int hardbs_, softbs_;
const char * final_msg_;
int final_errno_;
mutable int index_; // cached index of last find or change
std::vector< Sblock > sblock_vector; // note: blocks are consecutive
long ul_t1; // variable for update_logfile
bool logfile_exists_;
Logbook( const Logbook & ); // declared as private
void operator=( const Logbook & ); // declared as private
void erase_sblock( const int i )
{ sblock_vector.erase( sblock_vector.begin() + i ); }
void insert_sblock( const int i, const Sblock & sb )
{ sblock_vector.insert( sblock_vector.begin() + i, sb ); }
void split_domain_border_sblocks();
public:
Logbook( const long long offset, const long long isize,
Domain & dom, const char * const logname,
const int cluster, const int hardbs,
const bool complete_only, const bool do_not_read = false );
~Logbook() { delete[] iobuf_base; }
bool blank() const;
void compact_sblock_vector();
bool update_logfile( const int odes = -1, const bool force = false,
const bool retry = true );
void write_logfile( FILE * const f ) const;
long long current_pos() const { return current_pos_; }
Status current_status() const { return current_status_; }
const Domain & domain() const { return domain_; }
const char * filename() const { return filename_; }
uint8_t * iobuf() const { return iobuf_; }
int hardbs() const { return hardbs_; }
int softbs() const { return softbs_; }
long long offset() const { return offset_; }
const char * final_msg() const { return final_msg_; }
int final_errno() const { return final_errno_; }
bool logfile_exists() const { return logfile_exists_; }
long long logfile_isize() const { return logfile_isize_; }
void current_pos( const long long pos ) { current_pos_ = pos; }
void current_status( const Status st ) { current_status_ = st; }
void final_msg( const char * const msg ) { final_msg_ = msg; }
void final_errno( const int e ) { final_errno_ = e; }
const Sblock & sblock( const int i ) const
{ return sblock_vector[i]; }
int sblocks() const { return (int)sblock_vector.size(); }
void change_sblock_status( const int i, const Sblock::Status st )
{ sblock_vector[i].status( st ); }
void split_sblock_by( const long long pos, const int i )
{
if( sblock_vector[i].includes( pos ) )
insert_sblock( i, sblock_vector[i].split( pos ) );
}
bool truncate_vector( const long long end, const bool force = false );
void truncate_domain( const long long end )
{ domain_.crop_by_file_size( end ); }
int find_index( const long long pos ) const;
int find_largest_sblock( const Sblock::Status st ) const;
int find_smallest_sblock( const Sblock::Status st ) const;
void find_chunk( Block & b, const Sblock::Status st,
const int alignment = 0 ) const;
void rfind_chunk( Block & b, const Sblock::Status st,
const int alignment = 0 ) const;
int change_chunk_status( const Block & b, const Sblock::Status st );
static bool isstatus( const int st )
{ return ( st == copying || st == trimming || st == splitting ||
st == retrying || st == filling || st == generating ||
st == finished ); }
static const char * status_name( const Status st );
};
class Fillbook : public Logbook
{
long long filled_size; // size already filled
long long remaining_size; // size to be filled
int filled_areas; // areas already filled
int remaining_areas; // areas to be filled
int odes_; // output file descriptor
const bool ignore_write_errors_;
const bool synchronous_;
// variables for show_status
long long a_rate, c_rate, first_size, last_size;
long long last_ipos;
long t0, t1;
int fill_areas( const std::string & filltypes );
int fill_block( const Block & b );
void show_status( const long long ipos, bool force = false );
public:
Fillbook( const long long offset, Domain & dom,
const char * const logname, const int cluster, const int hardbs,
const bool ignore_write_errors, const bool synchronous )
: Logbook( offset, 0, dom, logname, cluster, hardbs, true ),
ignore_write_errors_( ignore_write_errors ),
synchronous_( synchronous ),
a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ),
last_ipos( 0 ), t0( 0 ), t1( 0 )
{}
int do_fill( const int odes, const std::string & filltypes );
bool read_buffer( const int ides );
};
class Genbook : public Logbook
{
long long recsize, gensize; // total recovered and generated sizes
int odes_; // output file descriptor
// variables for show_status
long long a_rate, c_rate, first_size, last_size;
long long last_ipos;
long t0, t1;
int oldlen;
void check_block( const Block & b, int & copied_size, int & error_size );
int check_all();
void show_status( const long long ipos, const char * const msg = 0,
bool force = false );
public:
Genbook( const long long offset, const long long isize,
Domain & dom, const char * const logname,
const int cluster, const int hardbs )
: Logbook( offset, isize, dom, logname, cluster, hardbs, false ),
a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ),
last_ipos( 0 ), t0( 0 ), t1( 0 ), oldlen( 0 )
{}
int do_generate( const int odes );
};
struct Rb_options
{
enum { default_skipbs = 65536, max_skipbs = 1 << 30 };
long long max_error_rate;
long long min_outfile_size;
long long min_read_rate;
long timeout;
int max_errors;
int max_logfile_size;
int max_retries;
int skipbs; // initial size to skip on read error
bool complete_only;
bool new_errors_only;
bool nosplit;
bool retrim;
bool sparse;
bool try_again;
Rb_options()
: max_error_rate( -1 ), min_outfile_size( -1 ), min_read_rate( -1 ),
timeout( -1 ), max_errors( -1 ), max_logfile_size( 1000 ),
max_retries( 0 ), skipbs( default_skipbs ), complete_only( false ),
new_errors_only( false ), nosplit( false ), retrim( false ),
sparse( false ), try_again( false )
{}
bool operator==( const Rb_options & o ) const
{ return ( max_error_rate == o.max_error_rate &&
min_outfile_size == o.min_outfile_size &&
min_read_rate == o.min_read_rate && timeout == o.timeout &&
max_errors == o.max_errors &&
max_logfile_size == o.max_logfile_size &&
max_retries == o.max_retries && skipbs == o.skipbs &&
complete_only == o.complete_only &&
new_errors_only == o.new_errors_only &&
nosplit == o.nosplit && retrim == o.retrim &&
sparse == o.sparse && try_again == o.try_again ); }
bool operator!=( const Rb_options & o ) const
{ return !( *this == o ); }
};
class Rescuebook : public Logbook, public Rb_options
{
long long error_rate;
long long sparse_size; // end position of pending writes
long long recsize, errsize; // total recovered and error sizes
const char * const iname_;
const int max_skip_size; // maximum size to skip on read error
int e_code; // error code for errors_or_timeout
// 1 rate, 2 errors, 4 timeout
int errors; // error areas found so far
int ides_, odes_; // input and output file descriptors
const bool synchronous_;
// variables for update_rates
long long a_rate, c_rate, first_size, last_size;
long long last_ipos;
long t0, t1, ts; // start, current, last successful
int oldlen;
bool rates_updated;
bool extend_outfile_size();
int copy_block( const Block & b, int & copied_size, int & error_size );
void count_errors();
bool errors_or_timeout()
{ if( max_errors >= 0 && errors > max_errors ) e_code |= 2;
return ( e_code != 0 ); }
void reduce_min_read_rate()
{ if( min_read_rate > 0 ) min_read_rate /= 10; }
bool slow_read() const
{ return ( t1 - t0 >= 10 && // no slow reads for first 10s
( ( min_read_rate > 0 && c_rate < min_read_rate &&
c_rate < a_rate / 2 ) ||
( min_read_rate == 0 && c_rate < a_rate / 10 ) ) ); }
int copy_and_update( const Block & b, const Sblock::Status st,
int & copied_size, int & error_size,
const char * const msg, bool & first_post,
const bool forward );
int copy_non_tried();
int rcopy_non_tried();
int trim_errors();
int split_errors( const bool reverse );
int copy_errors();
int rcopy_errors();
void update_rates( const bool force = false );
void show_status( const long long ipos, const char * const msg = 0,
const bool force = false );
public:
Rescuebook( const long long offset, const long long isize,
Domain & dom, const Rb_options & rb_opts,
const char * const iname, const char * const logname,
const int cluster, const int hardbs,
const bool synchronous );
int do_rescue( const int ides, const int odes, const bool reverse );
};
// Round "size" to the next multiple of sector size (hardbs).
//
inline int round_up( int size, const int hardbs )
{
if( size % hardbs )
{
size -= size % hardbs;
if( INT_MAX - size >= hardbs ) size += hardbs;
}
return size;
}
// Defined in io.cc
//
const char * format_time( long t );
bool interrupted();
void set_signals();
// Defined in main_common.cc
//
extern int verbosity;
void internal_error( const char * const msg );
void show_error( const char * const msg,
const int errcode = 0, const bool help = false );
void write_logfile_header( FILE * const f );
const char * format_num( long long num, long long limit = 999999,
const int set_prefix = 0 );
gddrescue-1.17/ddrescuelog.cc 0000664 0000000 0000000 00000056352 12235656145 0016242 0 ustar 00root root 0000000 0000000 /* GNU ddrescuelog - Tool for ddrescue logfiles
Copyright (C) 2011, 2012, 2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
Exit status: 0 for a normal exit, 1 for environmental problems
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
corrupt or invalid input file, 3 for an internal consistency error
(eg, bug) which caused ddrescuelog to panic.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "arg_parser.h"
#include "block.h"
#include "ddrescue.h"
namespace {
const char * const Program_name = "GNU ddrescuelog";
const char * const program_name = "ddrescuelog";
const char * invocation_name = 0;
enum Mode { m_none, m_and, m_change, m_compare, m_create, m_delete,
m_done_st, m_invert, m_list, m_or, m_status, m_xor };
void show_help( const int hardbs )
{
std::printf( "%s - Tool for ddrescue logfiles.\n", Program_name );
std::printf( "Manipulates ddrescue logfiles, shows their contents, converts them to/from\n"
"other formats, compares them, and tests rescue status.\n"
"\nUsage: %s [options] logfile\n", invocation_name );
std::printf( "\nOptions:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" -a, --change-types=, change the block types of a logfile\n"
" -b, --block-size= block size in bytes [default %d]\n", hardbs );
std::printf( " -c, --create-logfile[=] create logfile from list of blocks [+-]\n"
" -d, --delete-if-done delete the logfile if rescue is finished\n"
" -D, --done-status return 0 if rescue is finished\n"
" -f, --force overwrite existing output files\n"
" -i, --input-position= starting position of rescue domain [0]\n"
" -l, --list-blocks= print block numbers of given types (?*/-+)\n"
" -m, --domain-logfile= restrict domain to finished blocks in file\n"
" -n, --invert-logfile invert block types (finished <-> others)\n"
" -o, --output-position= starting position in output file [ipos]\n"
" -p, --compare-logfile= compare block types in domain of both files\n"
" -q, --quiet suppress all messages\n"
" -s, --size= maximum size of rescue domain to be processed\n"
" -t, --show-status show a summary of logfile contents\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" -x, --xor-logfile= XOR the finished blocks in file with logfile\n"
" -y, --and-logfile= AND the finished blocks in file with logfile\n"
" -z, --or-logfile= OR the finished blocks in file with logfile\n"
"Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
"invalid input file, 3 for an internal consistency error (eg, bug) which\n"
"caused ddrescuelog to panic.\n"
"\nReport bugs to bug-ddrescue@gnu.org\n"
"Ddrescue home page: http://www.gnu.org/software/ddrescue/ddrescue.html\n"
"General help using GNU software: http://www.gnu.org/gethelp\n" );
}
void set_types( const std::string & arg,
std::string & types1, std::string & types2 )
{
std::string * p = &types1;
bool error = false, comma_found = false;
types1.clear();
types2.clear();
for( unsigned i = 0; i < arg.size(); ++i )
{
const char ch = arg[i];
if( ch == ',' )
{
if( comma_found ) { error = true; break; }
else { comma_found = true; p = &types2; continue; }
}
if( !Sblock::isstatus( ch ) ) { error = true; break; }
*p += ch;
}
if( types1.size() == 0 || types2.size() == 0 ) error = true;
if( error )
{
show_error( "Invalid type for 'change-types' option.", 0, true );
std::exit( 1 );
}
if( types1.size() > types2.size() )
types2.append( types1.size() - types2.size(), types2[types2.size()-1] );
}
void set_types( const std::string & arg,
Sblock::Status & type1, Sblock::Status & type2 )
{
if( arg.size() == 0 ) return;
if( arg.size() != 2 || arg[0] == arg[1] ||
!Sblock::isstatus( arg[0] ) || !Sblock::isstatus( arg[1] ) )
{
show_error( "Invalid type for 'create-logfile' option.", 0, true );
std::exit( 1 );
}
type1 = Sblock::Status( arg[0] );
type2 = Sblock::Status( arg[1] );
}
void verify_logname_and_domain( const Logbook & logbook )
{
if( !logbook.logfile_exists() )
{
char buf[80];
snprintf( buf, sizeof buf, "Logfile '%s' does not exist.",
logbook.filename() );
show_error( buf );
std::exit( 1 );
}
if( logbook.domain().size() == 0 )
{ show_error( "Empty domain." ); std::exit( 0 ); }
}
int do_logic_ops( Domain & domain, const char * const logname,
const char * const second_logname, const Mode program_mode )
{
Domain domain2( domain );
Logbook logbook( 0, 0, domain, logname, 1, 1, true );
verify_logname_and_domain( logbook );
const Logbook logbook2( 0, 0, domain2, second_logname, 1, 1, true );
verify_logname_and_domain( logbook2 );
for( int i = 0; i < logbook.sblocks(); ++i )
{
const Sblock & sb = logbook.sblock( i );
if( !logbook.domain().includes( sb ) )
{ if( logbook.domain() < sb ) break; else continue; }
switch( program_mode )
{
case m_and:
{
if( sb.status() != Sblock::finished ) continue;
Block b( sb );
logbook2.find_chunk( b, Sblock::finished );
if( b.size() <= 0 || b.pos() >= sb.end() )
logbook.change_sblock_status( i, Sblock::bad_sector );
else if( b == sb ) continue;
else if( b.pos() == sb.pos() ) logbook.split_sblock_by( b.end(), i );
else
{ logbook.change_chunk_status( Block( sb.pos(), b.pos() - sb.pos() ),
Sblock::bad_sector ); --i; }
} break;
case m_or:
{
if( sb.status() == Sblock::finished ) continue;
Block b( sb );
logbook2.find_chunk( b, Sblock::finished );
if( b.size() <= 0 || b.pos() >= sb.end() ) continue;
else if( b == sb )
logbook.change_sblock_status( i, Sblock::finished );
else if( b.pos() == sb.pos() )
{ logbook.change_chunk_status( b, Sblock::finished ); --i; }
else logbook.split_sblock_by( b.end(), i );
} break;
case m_xor:
{
const Sblock::Status st = ( ( sb.status() == Sblock::finished ) ?
Sblock::bad_sector : Sblock::finished );
Block b( sb );
logbook2.find_chunk( b, Sblock::finished );
if( b.size() <= 0 || b.pos() >= sb.end() ) continue;
else if( b == sb ) logbook.change_sblock_status( i, st );
else if( b.pos() == sb.pos() )
{ logbook.change_chunk_status( b, st ); --i; }
else logbook.split_sblock_by( b.end(), i );
} break;
default: internal_error( "invalid program_mode" );
}
}
logbook.compact_sblock_vector();
logbook.write_logfile( stdout );
if( std::fclose( stdout ) != 0 )
{ show_error( "Can't close stdout", errno ); return 1; }
return 0;
}
int change_types( Domain & domain, const char * const logname,
const std::string & types1, const std::string & types2 )
{
Logbook logbook( 0, 0, domain, logname, 1, 1, true );
verify_logname_and_domain( logbook );
for( int i = 0; i < logbook.sblocks(); ++i )
{
const Sblock & sb = logbook.sblock( i );
if( !logbook.domain().includes( sb ) )
{ if( logbook.domain() < sb ) break; else continue; }
const unsigned j = types1.find( sb.status() );
if( j < types1.size() )
logbook.change_sblock_status( i, Sblock::Status( types2[j] ) );
}
logbook.compact_sblock_vector();
logbook.write_logfile( stdout );
if( std::fclose( stdout ) != 0 )
{ show_error( "Can't close stdout", errno ); return 1; }
return 0;
}
int compare_logfiles( Domain & domain, const char * const logname,
const char * const second_logname )
{
Domain domain2( domain );
const Logbook logbook( 0, 0, domain, logname, 1, 1, true );
verify_logname_and_domain( logbook );
const Logbook logbook2( 0, 0, domain2, second_logname, 1, 1, true );
verify_logname_and_domain( logbook2 );
int retval = 0;
if( logbook.domain() != logbook2.domain() ) retval = 1;
else for( int i = 0; i < logbook.sblocks(); ++i )
{
const Sblock & sb = logbook.sblock( i );
if( !logbook.domain().includes( sb ) )
{ if( logbook.domain() < sb ) break; else continue; }
const int j = logbook2.find_index( sb.pos() );
if( j < 0 || logbook2.sblock( j ) != sb ) { retval = 1; break; }
}
if( retval )
{
char buf[80];
snprintf( buf, sizeof buf, "Logfiles '%s' and '%s' differ.",
logbook.filename(), logbook2.filename() );
show_error( buf );
}
return retval;
}
int create_logfile( Domain & domain, const char * const logname,
const int hardbs, const Sblock::Status type1,
const Sblock::Status type2, const bool force )
{
char buf[80];
Logbook logbook( 0, 0, domain, logname, 1, hardbs, false, force );
if( logbook.logfile_exists() )
{
snprintf( buf, sizeof buf,
"Logfile '%s' exists. Use '--force' to overwrite it.", logname );
show_error( buf );
return 1;
}
if( logbook.domain().size() == 0 )
{ show_error( "Empty domain." ); return 0; }
for( int i = 0; i < logbook.sblocks(); ++i ) // mark all logfile as type2
logbook.change_sblock_status( i, type2 );
// mark every block read from stdin and in domain as type1
for( int linenum = 1; ; ++linenum )
{
long long block;
const int n = std::scanf( "%lli\n", &block );
if( n < 0 ) break; // EOF
if( n != 1 || block > LLONG_MAX / hardbs )
{
char buf[80];
snprintf( buf, sizeof buf,
"error reading block number from stdin, line %d", linenum );
show_error( buf );
return 2;
}
const Block b( block * hardbs, hardbs );
if( logbook.domain().includes( b ) )
logbook.change_chunk_status( b, type1 );
}
logbook.truncate_vector( logbook.domain().end(), true );
if( !logbook.update_logfile( -1, true, false ) ) return 1;
return 0;
}
int test_if_done( Domain & domain, const char * const logname, const bool del )
{
char buf[80];
const Logbook logbook( 0, 0, domain, logname, 1, 1, true );
verify_logname_and_domain( logbook );
for( int i = 0; i < logbook.sblocks(); ++i )
{
const Sblock & sb = logbook.sblock( i );
if( !logbook.domain().includes( sb ) )
{ if( logbook.domain() < sb ) break; else continue; }
if( sb.status() != Sblock::finished )
{
if( verbosity >= 1 )
{
snprintf( buf, sizeof buf, "Logfile '%s' not done.", logname );
show_error( buf );
}
return 1;
}
}
if( !del ) return 0;
if( std::remove( logname ) != 0 )
{
snprintf( buf, sizeof buf, "Error deleting logfile '%s'", logname );
show_error( buf, errno );
return 1;
}
if( verbosity >= 1 )
{
snprintf( buf, sizeof buf, "Logfile '%s' successfully deleted.", logname );
show_error( buf );
}
return 0;
}
int to_badblocks( const long long offset, Domain & domain,
const char * const logname, const int hardbs,
const std::string & blocktypes )
{
long long last_block = -1;
const Logbook logbook( offset, 0, domain, logname, 1, hardbs, true );
verify_logname_and_domain( logbook );
for( int i = 0; i < logbook.sblocks(); ++i )
{
const Sblock & sb = logbook.sblock( i );
if( !logbook.domain().includes( sb ) )
{ if( logbook.domain() < sb ) break; else continue; }
if( blocktypes.find( sb.status() ) >= blocktypes.size() ) continue;
for( long long block = ( sb.pos() + logbook.offset() ) / hardbs;
block * hardbs < sb.end() + logbook.offset(); ++block )
{
if( block > last_block )
{
last_block = block;
std::printf( "%lld\n", block );
}
else if( block < last_block ) internal_error( "block out of order" );
}
}
return 0;
}
// Shows the fraction "num/den" as a percentage with "prec" decimals.
// If 'prec' is negative, only the needed decimals are shown.
//
const char * format_percentage( long long num, long long den,
const int iwidth = 3, int prec = -2 )
{
static char buf[80];
if( den < 0 ) { num = -num; den = -den; }
if( llabs( num ) <= LLONG_MAX / 100 && den <= LLONG_MAX / 10 ) num *= 100;
else if( llabs( num ) <= LLONG_MAX / 10 ) { num *= 10; den /= 10; }
else den /= 100;
if( den == 0 )
{
if( num > 0 ) return "+INF";
else if( num < 0 ) return "-INF";
else return "NAN";
}
const bool trunc = ( prec < 0 );
if( prec < 0 ) prec = -prec;
unsigned i;
if( num < 0 && num / den == 0 )
i = snprintf( buf, sizeof( buf ), "%*s", iwidth, "-0" );
else i = snprintf( buf, sizeof( buf ), "%*lld", iwidth, num / den );
if( i < sizeof( buf ) - 2 )
{
long long rest = llabs( num ) % den;
if( prec > 0 && ( rest > 0 || !trunc ) )
{
buf[i++] = '.';
while( prec > 0 && ( rest > 0 || !trunc ) && i < sizeof( buf ) - 2 )
{ rest *= 10; buf[i++] = (char)( rest / den ) + '0';
rest %= den; --prec; }
}
}
else i = sizeof( buf ) - 2;
buf[i++] = '%';
buf[i] = 0;
return buf;
}
int do_show_status( Domain & domain, const char * const logname )
{
long long size_non_tried = 0, size_non_trimmed = 0, size_non_split = 0;
long long size_bad_sector = 0, size_finished = 0;
int areas_non_tried = 0, areas_non_trimmed = 0, areas_non_split = 0;
int areas_bad_sector = 0, areas_finished = 0;
int errors = 0;
Sblock::Status old_status = Sblock::non_tried;
bool first_block = true, good = true;
const Logbook logbook( 0, 0, domain, logname, 1, 1, true );
verify_logname_and_domain( logbook );
for( int i = 0; i < logbook.sblocks(); ++i )
{
const Sblock & sb = logbook.sblock( i );
if( !logbook.domain().includes( sb ) )
{
if( logbook.domain() < sb ) break;
else { first_block = true; good = true; continue; }
}
const bool sc = ( first_block || sb.status() != old_status );
first_block = false;
switch( sb.status() )
{
case Sblock::non_tried: size_non_tried += sb.size(); good = true;
if( sc ) ++areas_non_tried; break;
case Sblock::finished: size_finished += sb.size(); good = true;
if( sc ) ++areas_finished; break;
case Sblock::non_trimmed: size_non_trimmed += sb.size();
if( good ) { good = false; ++errors; }
if( sc ) ++areas_non_trimmed; break;
case Sblock::non_split: size_non_split += sb.size();
if( good ) { good = false; ++errors; }
if( sc ) ++areas_non_split; break;
case Sblock::bad_sector: size_bad_sector += sb.size();
if( good ) { good = false; ++errors; }
if( sc ) ++areas_bad_sector; break;
}
old_status = sb.status();
}
const long long domain_size = logbook.domain().in_size();
const long long errsize = size_non_trimmed + size_non_split + size_bad_sector;
std::printf( "\ncurrent pos: %10sB, current status: %s\n",
format_num( logbook.current_pos() ),
logbook.status_name( logbook.current_status() ) );
std::printf( "domain size: %10sB, in %4d area(s)\n",
format_num( domain_size ),
logbook.domain().blocks() );
std::printf( " rescued: %10sB, in %4d area(s) (%s)\n",
format_num( size_finished ), areas_finished,
format_percentage( size_finished, domain_size ) );
std::printf( " non-tried: %10sB, in %4d area(s) (%s)\n",
format_num( size_non_tried ), areas_non_tried,
format_percentage( size_non_tried, domain_size ) );
std::printf( "\n errsize: %10sB, errors: %7u (%s)\n",
format_num( errsize ), errors,
format_percentage( errsize, domain_size ) );
std::printf( "non-trimmed: %10sB, in %4d area(s) (%s)\n",
format_num( size_non_trimmed ), areas_non_trimmed,
format_percentage( size_non_trimmed, domain_size ) );
std::printf( " non-split: %10sB, in %4d area(s) (%s)\n",
format_num( size_non_split ), areas_non_split,
format_percentage( size_non_split, domain_size ) );
std::printf( " bad-sector: %10sB, in %4d area(s) (%s)\n",
format_num( size_bad_sector ), areas_bad_sector,
format_percentage( size_bad_sector, domain_size ) );
return 0;
}
} // end namespace
#include "main_common.cc"
int main( const int argc, const char * const argv[] )
{
long long ipos = 0;
long long opos = -1;
long long max_size = -1;
const char * domain_logfile_name = 0;
const char * second_logname = 0;
const int default_hardbs = 512;
int hardbs = default_hardbs;
Mode program_mode = m_none;
bool force = false;
std::string types1, types2;
Sblock::Status type1 = Sblock::finished, type2 = Sblock::bad_sector;
invocation_name = argv[0];
command_line = argv[0];
for( int i = 1; i < argc; ++i )
{ command_line += ' '; command_line += argv[i]; }
const Arg_parser::Option options[] =
{
{ 'a', "change-types", Arg_parser::yes },
{ 'b', "block-size", Arg_parser::yes },
{ 'b', "sector-size", Arg_parser::yes },
{ 'c', "create-logfile", Arg_parser::maybe },
{ 'd', "delete-if-done", Arg_parser::no },
{ 'D', "done-status", Arg_parser::no },
{ 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
{ 'i', "input-position", Arg_parser::yes },
{ 'l', "list-blocks", Arg_parser::yes },
{ 'm', "domain-logfile", Arg_parser::yes },
{ 'n', "invert-logfile", Arg_parser::no },
{ 'o', "output-position", Arg_parser::yes },
{ 'p', "compare-logfile", Arg_parser::yes },
{ 'q', "quiet", Arg_parser::no },
{ 's', "size", Arg_parser::yes },
{ 's', "max-size", Arg_parser::yes },
{ 't', "show-status", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ 'x', "xor-logfile", Arg_parser::yes },
{ 'y', "and-logfile", Arg_parser::yes },
{ 'z', "or-logfile", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 1; }
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
switch( code )
{
case 'a': set_mode( program_mode, m_change );
set_types( arg, types1, types2 ); break;
case 'b': hardbs = getnum( arg, 0, 1, INT_MAX ); break;
case 'c': set_mode( program_mode, m_create );
set_types( arg, type1, type2 ); break;
case 'd': set_mode( program_mode, m_delete ); break;
case 'D': set_mode( program_mode, m_done_st ); break;
case 'f': force = true; break;
case 'h': show_help( default_hardbs ); return 0;
case 'i': ipos = getnum( arg, hardbs, 0 ); break;
case 'l': set_mode( program_mode, m_list ); types1 = arg;
check_types( types1, "list-blocks" ); break;
case 'm': set_name( &domain_logfile_name, arg ); break;
case 'n': set_mode( program_mode, m_invert ); break;
case 'o': opos = getnum( arg, hardbs, 0 ); break;
case 'p': set_mode( program_mode, m_compare );
second_logname = arg; break;
case 'q': verbosity = -1; break;
case 's': max_size = getnum( arg, hardbs, -1 ); break;
case 't': set_mode( program_mode, m_status ); break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
case 'x': set_mode( program_mode, m_xor );
second_logname = arg; break;
case 'y': set_mode( program_mode, m_and );
second_logname = arg; break;
case 'z': set_mode( program_mode, m_or );
second_logname = arg; break;
default : internal_error( "uncaught option" );
}
} // end process options
if( program_mode == m_none )
{
show_error( "You must specify the operation to be performed.", 0, true );
return 1;
}
if( opos < 0 ) opos = ipos;
if( argind + 1 != parser.arguments() )
{
if( argind < parser.arguments() )
show_error( "Too many files.", 0, true );
else
show_error( "A logfile must be specified.", 0, true );
return 1;
}
const char * const logname = parser.argument( argind++ ).c_str();
// end scan arguments
Domain domain( ipos, max_size, domain_logfile_name );
switch( program_mode )
{
case m_none: internal_error( "invalid operation" ); break;
case m_and:
case m_or:
case m_xor:
return do_logic_ops( domain, logname, second_logname, program_mode );
case m_change: return change_types( domain, logname, types1, types2 );
case m_compare: return compare_logfiles( domain, logname, second_logname );
case m_create: return create_logfile( domain, logname, hardbs,
type1, type2, force );
case m_delete: return test_if_done( domain, logname, true );
case m_done_st: return test_if_done( domain, logname, false );
case m_invert: return change_types( domain, logname, "?*/-+", "++++-" );
case m_list:
return to_badblocks( opos - ipos, domain, logname, hardbs, types1 );
case m_status: return do_show_status( domain, logname );
}
}
gddrescue-1.17/doc/ 0000775 0000000 0000000 00000000000 12235656145 0014165 5 ustar 00root root 0000000 0000000 gddrescue-1.17/doc/ddrescue.1 0000664 0000000 0000000 00000010647 12235656145 0016055 0 ustar 00root root 0000000 0000000 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH DDRESCUE "1" "July 2013" "ddrescue 1.17" "User Commands"
.SH NAME
ddrescue \- data recovery tool
.SH SYNOPSIS
.B ddrescue
[\fIoptions\fR] \fIinfile outfile \fR[\fIlogfile\fR]
.SH DESCRIPTION
GNU ddrescue \- Data recovery tool.
Copies data from one file or block device to another,
trying hard to rescue data in case of read errors.
.PP
You should use a logfile unless you know what you are doing.
If you reboot, check the device names before restarting ddrescue.
Do not use options '\-F' or '\-g' without reading the manual first.
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
display this help and exit
.TP
\fB\-V\fR, \fB\-\-version\fR
output version information and exit
.TP
\fB\-a\fR, \fB\-\-min\-read\-rate=\fR
minimum read rate of good areas in bytes/s
.TP
\fB\-A\fR, \fB\-\-try\-again\fR
mark non\-split, non\-trimmed blocks as non\-tried
.TP
\fB\-b\fR, \fB\-\-sector\-size=\fR
sector size of input device [default 512]
.TP
\fB\-B\fR, \fB\-\-binary\-prefixes\fR
show binary multipliers in numbers [SI]
.TP
\fB\-c\fR, \fB\-\-cluster\-size=\fR
sectors to copy at a time [128]
.TP
\fB\-C\fR, \fB\-\-complete\-only\fR
do not read new data beyond logfile limits
.TP
\fB\-d\fR, \fB\-\-direct\fR
use direct disc access for input file
.TP
\fB\-D\fR, \fB\-\-synchronous\fR
use synchronous writes for output file
.TP
\fB\-e\fR, \fB\-\-max\-errors\fR=\fI[\fR+]
maximum number of [new] error areas allowed
.TP
\fB\-E\fR, \fB\-\-max\-error\-rate=\fR
maximum allowed rate of read errors per second
.TP
\fB\-f\fR, \fB\-\-force\fR
overwrite output device or partition
.TP
\fB\-F\fR, \fB\-\-fill\-mode=\fR
fill given type blocks with infile data (?*/\-+)
.TP
\fB\-g\fR, \fB\-\-generate\-mode\fR
generate approximate logfile from partial copy
.TP
\fB\-i\fR, \fB\-\-input\-position=\fR
starting position in input file [0]
.TP
\fB\-I\fR, \fB\-\-verify\-input\-size\fR
verify input file size with size in logfile
.TP
\fB\-K\fR, \fB\-\-skip\-size=\fR
initial size to skip on read error [64 KiB]
.TP
\fB\-l\fR, \fB\-\-logfile\-size=\fR
do not grow logfile beyond this size [1000]
.TP
\fB\-m\fR, \fB\-\-domain\-logfile=\fR
restrict domain to finished blocks in file
.TP
\fB\-M\fR, \fB\-\-retrim\fR
mark all failed blocks as non\-trimmed
.TP
\fB\-n\fR, \fB\-\-no\-split\fR
do not try to split or retry failed blocks
.TP
\fB\-o\fR, \fB\-\-output\-position=\fR
starting position in output file [ipos]
.TP
\fB\-p\fR, \fB\-\-preallocate\fR
preallocate space on disc for output file
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
\fB\-r\fR, \fB\-\-retries=\fR
exit after given retries (\fB\-1\fR=\fIinfinity\fR) [0]
.TP
\fB\-R\fR, \fB\-\-reverse\fR
reverse direction of copy operations
.TP
\fB\-s\fR, \fB\-\-size=\fR
maximum size of input data to be copied
.TP
\fB\-S\fR, \fB\-\-sparse\fR
use sparse writes for output file
.TP
\fB\-t\fR, \fB\-\-truncate\fR
truncate output file to zero size
.TP
\fB\-T\fR, \fB\-\-timeout=\fR
maximum time since last successful read
.TP
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-w\fR, \fB\-\-ignore\-write\-errors\fR
make fill mode ignore write errors
.TP
\fB\-x\fR, \fB\-\-extend\-outfile=\fR
extend outfile size to be at least this long
.PP
Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,
Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
Time intervals have the format 1[.5][smhd] or 1/2[smhd].
.PP
Exit status: 0 for a normal exit, 1 for environmental problems (file
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused ddrescue to panic.
.SH "REPORTING BUGS"
Report bugs to bug\-ddrescue@gnu.org
.br
Ddrescue home page: http://www.gnu.org/software/ddrescue/ddrescue.html
.br
General help using GNU software: http://www.gnu.org/gethelp
.SH COPYRIGHT
Copyright \(co 2013 Antonio Diaz Diaz.
License GPLv3+: GNU GPL version 3 or later
.br
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B ddrescue
is maintained as a Texinfo manual. If the
.B info
and
.B ddrescue
programs are properly installed at your site, the command
.IP
.B info ddrescue
.PP
should give you access to the complete manual.
gddrescue-1.17/doc/ddrescue.info 0000664 0000000 0000000 00000133045 12235656145 0016646 0 ustar 00root root 0000000 0000000 This is ddrescue.info, produced by makeinfo version 4.13 from
ddrescue.texinfo.
INFO-DIR-SECTION GNU Packages
START-INFO-DIR-ENTRY
* Ddrescue: (ddrescue). Data recovery tool
END-INFO-DIR-ENTRY
File: ddrescue.info, Node: Top, Next: Introduction, Up: (dir)
GNU ddrescue Manual
*******************
This manual is for GNU ddrescue (version 1.17, 9 July 2013).
* Menu:
* Introduction:: Purpose and features of GNU ddrescue
* Basic concepts:: Blocks, clusters, devices, files, sectors, etc
* Important advice:: Read this or risk losing your data
* Algorithm:: How ddrescue recovers the data
* Invoking ddrescue:: Command line interface
* Logfile structure:: Detailed format of the logfile
* Examples:: A small tutorial with examples
* Direct disc access:: Bypassing the kernel cache
* Fill mode:: Selectively overwriting the output file
* Generate mode:: Generating an approximate logfile
* Ddrescuelog:: Tool for ddrescue logfiles
* Invoking ddrescuelog:: Command line interface
* Problems:: Reporting bugs
* Concept index:: Index of concepts
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to
copy, distribute and modify it.
File: ddrescue.info, Node: Introduction, Next: Basic concepts, Prev: Top, Up: Top
1 Introduction
**************
GNU ddrescue is a data recovery tool. It copies data from one file or
block device (hard disc, cdrom, etc) to another, trying hard to rescue
data in case of read errors.
The basic operation of ddrescue is fully automatic. That is, you
don't have to wait for an error, stop the program, read the log,
restart it from a new position, etc.
If you use the logfile feature of ddrescue, the data is rescued very
efficiently, (only the needed blocks are read). Also you can interrupt
the rescue at any time and resume it later at the same point.
Ddrescue does not write zeros to the output when it finds bad
sectors in the input, and does not truncate the output file if not
asked to. So, every time you run it on the same output file, it tries
to fill in the gaps without wiping out the data already rescued.
Automatic merging of backups: If you have two or more damaged copies
of a file, cdrom, etc, and run ddrescue on all of them, one at a time,
with the same output file, you will probably obtain a complete and
error-free file. This is so because the probability of having damaged
areas at the same places on different input files is very low. Using
the logfile, only the needed blocks are read from the second and
successive copies.
Ddrescue recommends lzip for compression of backups because of its
reliability and data recovery capabilities, including error-checked
merging of backup copies. Lziprecover makes lzip files resistant to
bit-flip, one of the most common forms of data corruption, and its
recovery capabilities contribute to make of the lzip format one of the
best formats for long-term data archiving. The combination ddrescue +
lziprecover is the best option for recovering data from multiple damaged
copies. *Note lziprecover-example::, for an example.
Recordable CD and DVD media keep their data only for a finite time
(typically for many years). After that time, data loss develops slowly
with read errors growing from the outer media region towards the inside.
Just make two (or more) copies of every important CD/DVD you burn so
that you can later recover them with ddrescue.
Because ddrescue needs to read and write at random places, it only
works on seekable (random access) input and output files.
If your system supports it, ddrescue can use direct disc access to
read the input file, bypassing the kernel cache.
Ddrescue also features a "fill mode" able to selectively overwrite
parts of the output file, which has a number of interesting uses like
wiping data, marking bad areas or even, in some cases, "repair" damaged
sectors.
File: ddrescue.info, Node: Basic concepts, Next: Important advice, Prev: Introduction, Up: Top
2 Basic concepts
****************
Block
Any amount of data. A block is described by its starting position
and its size.
Cluster
Group of consecutive sectors read or written in one go.
Device
Piece of hardware containing data. Hard disc drives, cdrom drives,
USB pendrives, are devices. /dev/hda, /dev/sdb, are device names.
File
Files are named units of data which are stored by the operating
system for you to retrieve later by name. Devices and partitions
are accessed by means of their associated file names.
Partition
Every part in which a device is divided. A partition normally
contains a file system. /dev/hda1, /dev/sdb3, are partition names.
Recoverable formats
As ddrescue uses standard library functions to read data from the
device being rescued, only mountable device formats can be rescued
with ddrescue. DVDs can be mounted and they can be rescued,
"compact disc digital audio" CDs can't, "video CDs"[1] maybe.
[1] http://en.wikipedia.org/wiki/Video_CD
Rescue domain
Block or set of blocks to be acted upon (rescued, listed, etc).
You can define it with the options `--input-position', `--size' and
`--domain-logfile'. The rescue domain defaults to the whole input
file or logfile.
Sector
Hardware block. Smallest accessible amount of data on a device.
File: ddrescue.info, Node: Important advice, Next: Algorithm, Prev: Basic concepts, Up: Top
3 Using ddrescue safely
***********************
Ddrescue is like any other power tool. You need to understand what it
does, and you need to understand some things about the machines it does
those things to, in order to use it safely.
Always use a logfile unless you know you won't need it. Without a
logfile, ddrescue can't resume a rescue, only reinitiate it.
Never try to rescue a r/w mounted partition. The resulting copy may
be useless.
Never try to repair a file system on a drive with I/O errors; you
will probably lose even more data.
If you use a device or a partition as destination, any data stored
there will be overwritten.
Some systems may change device names on reboot (eg. udev enabled
systems). If you reboot, check the device names before restarting
ddrescue.
If you interrupt the rescue and then reboot, any partially copied
partitions should be hidden before allowing them to be touched by any
operating system that tries to mount and "fix" the partitions it sees.
File: ddrescue.info, Node: Algorithm, Next: Invoking ddrescue, Prev: Important advice, Up: Top
4 Algorithm
***********
GNU ddrescue manages efficiently the status of the rescue in progress
and tries to rescue the good parts first, scheduling reads inside bad
(or slow) areas for later. This maximizes the amount of data that can be
finally recovered from a failing drive.
The standard dd utility can be used to save data from a failing
drive, but it reads the data sequentially, which may wear out the drive
without rescuing anything if the errors are at the beginning of the
drive.
Other programs switch to small size reads when they find errors, but
they still read the data sequentially. This is a bad idea because it
means spending more time at error areas, damaging the surface, the heads
and the drive mechanics, instead of getting out of them as fast as
possible. This behavior reduces the chances of rescuing the remaining
good data.
The algorithm of ddrescue is as follows (the user may interrupt the
process at any point, but be aware that a bad drive can block ddrescue
for a long time until the kernel gives up):
1) Optionally read a logfile describing the status of a multi-part or
previously interrupted rescue. If no logfile is specified or is empty or
does not exist, mark all the rescue domain as non-tried.
2) (First phase; Copying) Read the non-tried parts of the input file,
marking the failed blocks as non-trimmed and skipping beyond them, until
all the rescue domain is tried. Only non-tried areas are read in large
blocks. Trimming, splitting and retrying are done sector by sector. Each
sector is tried at most two times; the first in this step as part of a
large block read, the second in one of the steps below as a single
sector read.
3) (Second phase; Trimming) Read forwards one sector at a time from
the leading edge of the largest non-trimmed block, until a bad sector is
found. Then read backwards one sector at a time from the trailing edge
of the same block, until a bad sector is found. For each non-trimmed
block, mark the bad sectors found as bad-sector and mark the rest of
that block as non-split. Repeat until there are no more non-trimmed
blocks.
4) (Third phase; Splitting) Read forwards one sector at a time from
the center of the largest non-split block, until a bad sector is found.
Then read backwards one sector at a time from the center of the same
block, until a bad sector is found. If the logfile is larger than
`--logfile-size', read the smallest non-split blocks until the number
of entries in the logfile drops below `--logfile-size'. Repeat until
all remaining non-split blocks have less than 5 sectors. Then read the
remaining non-split blocks sequentially.
5) (Fourth phase; Retrying) Optionally try to read again the bad
sectors until the specified number of retries is reached.
6) Optionally write a logfile for later use.
Note that as ddrescue splits the failed blocks, making them smaller,
the total error size may diminish while the number of errors increases.
The logfile is periodically saved to disc, as well as when ddrescue
finishes or is interrupted. So in case of a crash you can resume the
rescue with little recopying.
Also, the same logfile can be used for multiple commands that copy
different areas of the input file, and for multiple recovery attempts
over different subsets. See this example:
Rescue the most important part of the disc first.
ddrescue -i0 -s50MiB /dev/hdc hdimage logfile
ddrescue -i0 -s1MiB -d -r3 /dev/hdc hdimage logfile
Then rescue some key disc areas.
ddrescue -i30GiB -s10GiB /dev/hdc hdimage logfile
ddrescue -i230GiB -s5GiB /dev/hdc hdimage logfile
Now rescue the rest (does not recopy what is already done).
ddrescue /dev/hdc hdimage logfile
ddrescue -d -r3 /dev/hdc hdimage logfile
File: ddrescue.info, Node: Invoking ddrescue, Next: Logfile structure, Prev: Algorithm, Up: Top
5 Invoking ddrescue
*******************
The format for running ddrescue is:
ddrescue [OPTIONS] INFILE OUTFILE [LOGFILE]
ddrescue supports the following options:
`-h'
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of ddrescue on the standard output and
exit.
`-a BYTES'
`--min-read-rate=BYTES'
Minimum read rate of good non-tried areas, in bytes per second. If
the read rate falls below this value, ddrescue will skip ahead a
variable amount depending on rate and error history. The skipped
blocks are tried in additional passes (before trimming) where the
minimum read rate is divided by ten before each pass, until there
are no more non-tried blocks left. If BYTES is 0 (auto), the
minimum read rate is recalculated for each block read as
(average_rate / 10).
`-A'
`--try-again'
Mark all non-split and non-trimmed blocks inside the rescue domain
as non-tried before beginning the rescue. Try this if the drive
stops responding and ddrescue immediately starts splitting failed
blocks when restarted. If `--retrim' is also specified, mark all
failed blocks inside the rescue domain as non-tried.
`-b BYTES'
`--sector-size=BYTES'
Sector (hardware block) size of input device in bytes (usually 512
for hard discs and 3.5" floppies, 1024 for 5.25" floppies, and
2048 for cdroms). Defaults to 512.
`-B'
`--binary-prefixes'
Show units with binary prefixes (powers of 1024).
SI prefixes (powers of 1000) are used by default. (See table
below).
`-c SECTORS'
`--cluster-size=SECTORS'
Number of sectors to copy at a time. Defaults to
64 KiB / sector_size. Try smaller values for slow drives. The
number of sectors per track (18 or 9) is a good value for floppies.
`-C'
`--complete-only'
Limit rescue domain to the blocks listed in the LOGFILE. Do not
read new data beyond LOGFILE limits. This is useful when reading
from devices of undefined size (like raw devices), when the drive
returns an incorrect size, or when reading from a partial copy. It
can only be used after a first rescue attempt, possibly limited
with the `--size' option, has produced a complete LOGFILE.
`-d'
`--direct'
Use direct disc access to read from INFILE, bypassing the kernel
cache. (Open the file with the O_DIRECT flag). Use it only on
devices or partitions, not on regular files. Sector size must be
correctly set for this to work. Not all systems support this.
If your system does not support direct disc access, ddrescue will
warn you. If the sector size is not correctly set, all reads will
result in errors, and no data will be rescued.
`-D'
`--synchronous'
Use synchronous writes for OUTFILE. (Issue a fsync call after
every write). May be useful when forcing the drive to remap its bad
sectors.
`-e [+]N'
`--max-errors=[+]N'
Maximum number of error areas allowed before giving up. Defaults to
infinity. If N is preceded by `+' the number refers to new error
areas found in this run, not counting those already annotated in
the LOGFILE.
`-E BYTES'
`--max-error-rate=BYTES'
Maximum rate of errors allowed before giving up, in bytes per
second. Defaults to infinity. The rate being measured is that of
actually failed reads, so the rescue may finish because of this
rate being exceeded even if the total error size (errsize) does
not change because the areas being tried are already marked as
errors.
`-f'
`--force'
Force overwrite of OUTFILE. Needed when OUTFILE is not a regular
file, but a device or partition.
`-F TYPES'
`--fill-mode=TYPES'
Fill the blocks in OUTFILE specified as any of TYPES in LOGFILE,
with data read from INFILE. TYPES contains one or more of the
status characters defined in the chapter Logfile Structure (*note
Logfile structure::). See the chapter Fill mode (*note Fill
mode::) for a complete description of the fill mode.
`-g'
`--generate-mode'
Generate an approximate LOGFILE from the INFILE and OUTFILE of the
original rescue run. Note that you must keep the original offset
between `--input-position' and `--output-position' of the original
rescue run. See the chapter Generate mode (*note Generate mode::)
for a complete description of the generate mode.
`-i BYTES'
`--input-position=BYTES'
Starting position in INFILE, in bytes. Defaults to 0. In fill mode
it refers to a position in the INFILE of the original rescue run.
See the chapter Fill mode (*note Fill mode::) for details.
`-I'
`--verify-input-size'
Compare the size of INFILE with the size calculated from the list
of blocks contained in the LOGFILE, and exit with status 1 if they
differ. This is not enabled by default because the size of some
devices can't be known in advance and because the size derived
from the LOGFILE may be incomplete, for example after doing a
partial rescue.
`-K BYTES'
`--skip-size=BYTES'
Set the initial size to skip on the first read error or slow read.
The value given will be rounded to the next multiple of sector
size. For subsequent read errors or slow reads, ddrescue will
modify the skip size depending on error rate and error history.
Valid values range from 64 KiB to 1 GiB. Defaults to 64 KiB.
`-l ENTRIES'
`--logfile-size=ENTRIES'
During the splitting phase, do not grow logfile beyond this number
of entries. Logfile may be larger if it was larger at startup or
if it became larger during the copying or trimming phases.
Defaults to 1000. (Each entry is about 26-30 bytes in size).
`-m FILE'
`--domain-logfile=FILE'
Restrict the rescue domain to the blocks marked as finished in the
logfile FILE. This is useful if the destination drive fails during
the rescue.
`-M'
`--retrim'
Mark all failed blocks inside the rescue domain as non-trimmed
before beginning the rescue. The effect is similar to
`--retries=1', but the bad sectors are tried in a different order,
making perhaps possible to rescue some of them.
`-n'
`--no-split'
Skip the splitting phase. Avoids spending a lot of time trying to
rescue the most difficult parts of the file.
`-o BYTES'
`--output-position=BYTES'
Starting position in OUTFILE, in bytes. Defaults to
`--input-position'. The bytes below BYTES aren't touched if they
exist and truncation is not requested. Else they are set to 0.
`-p'
`--preallocate'
Preallocate space on disc for OUTFILE. Only space for regular
files can be preallocated. If preallocation succeeds, rescue will
not fail due to lack of free space on disc. If ddrescue can't
determine the size to preallocate, you may need to specify it with
some combination of the `--input-position', `--output-position',
`--size', and `--domain-logfile' options.
`-q'
`--quiet'
Quiet operation. Suppress all messages.
`-r N'
`--retries=N'
Exit after given number of retry passes. Defaults to 0. -1 means
infinity. Every bad sector is tried only one time per pass. To
retry bad sectors detected on a previous run, you must specify a
non-zero number of retries.
`-R'
`--reverse'
Reverse direction of copying, retrying, and the sequential part of
splitting, running them backwards from the end of the input file.
`-s BYTES'
`--size=BYTES'
Maximum size of the input data to be copied, in bytes. If ddrescue
can't determine the size of the input device, you may need to
specify it with this option. Note that this option specifies the
size of the input data to be copied, not the size of the resulting
OUTFILE. So, for example, the following command creates an OUTFILE
300 bytes long, but only writes data on the last 200 bytes:
ddrescue -i 100 -s 200 infile outfile logfile
`-S'
`--sparse'
Use sparse writes for OUTFILE. (The blocks of zeros are not
actually allocated on disc). May save a lot of disc space in some
cases. Not all systems support this. Only regular files can be
sparse.
`-t'
`--truncate'
Truncate OUTFILE to zero size before writing to it. Only works for
regular files, not for drives or partitions.
`-T INTERVAL'
`--timeout=INTERVAL'
Maximum time since last successful read allowed before giving up.
Defaults to infinity. INTERVAL is a rational number (like 1.5 or
1/2) optionally followed by one of `s', `m', `h' or `d', meaning
seconds, minutes, hours and days respectively. If no unit is
specified, it defaults to seconds.
`-v'
`--verbose'
Verbose mode. Further -v's (up to 4) increase the verbosity level.
`-w'
`--ignore-write-errors'
Make fill mode ignore write errors. This is useful to avoid
ddrescue exiting because of new errors developing while wiping the
good sectors of a failing drive. Fill mode normally writes to
OUTFILE one cluster at a time. With this option, after the first
write error is found in an area, the rest of that area is filled
sector by sector.
`-x BYTES'
`--extend-outfile=BYTES'
Extend the size of OUTFILE to make it at least BYTES long. If the
size of OUTFILE is already equal or longer than BYTES then this
option does nothing. Use this option to guarantee a minimum size
for OUTFILE. Only regular files can be extended.
Numbers given as arguments to options (positions, sizes, retries,
etc) may be followed by a multiplier and an optional `B' for "byte".
Table of SI and binary prefixes (unit multipliers):
Prefix Value | Prefix Value
| s sectors
k kilobyte (10^3 = 1000) | Ki kibibyte (2^10 = 1024)
M megabyte (10^6) | Mi mebibyte (2^20)
G gigabyte (10^9) | Gi gibibyte (2^30)
T terabyte (10^12) | Ti tebibyte (2^40)
P petabyte (10^15) | Pi pebibyte (2^50)
E exabyte (10^18) | Ei exbibyte (2^60)
Z zettabyte (10^21) | Zi zebibyte (2^70)
Y yottabyte (10^24) | Yi yobibyte (2^80)
Exit status: 0 for a normal exit, 1 for environmental problems (file
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused ddrescue to panic.
File: ddrescue.info, Node: Logfile structure, Next: Examples, Prev: Invoking ddrescue, Up: Top
6 Logfile structure
*******************
The logfile is a text file easy to read and edit. It is formed by three
parts, the heading comments, the status line, and the list of data
blocks. Any line beginning with `#' is a comment line.
NOTE: Logfiles generated by a version of ddrescue prior to 1.6 lack
the status line. If you want to use an old logfile with ddrescue 1.6 or
later, you will have to insert a line like `0 +' at the beginning of
the logfile.
The heading comments contain the version of ddrescue and the command
line used to create the logfile. They are intended as information for
the user.
The first non-comment line is the status line. It contains a
non-negative integer and a status character. The integer is the position
being tried in the input file. The status character is one of these:
Character Meaning
'?' copying non-tried blocks
'*' trimming non-trimmed blocks
'/' splitting non-split blocks
'-' retrying bad sectors
'F' filling specified blocks
'G' generating approximate logfile
'+' finished
The blocks in the list of data blocks must be contiguous and
non-overlapping.
Every line in the list of data blocks describes a block of data. It
contains 2 non-negative integers and a status character. The first
integer is the starting position of the block in the input file, the
second integer is the size (in bytes) of the block. The status character
is one of these:
Character Meaning
'?' non-tried block
'*' failed block non-trimmed
'/' failed block non-split
'-' failed block bad-sector(s)
'+' finished block
And here is an example logfile:
# Rescue Logfile. Created by GNU ddrescue version 1.17
# Command line: ddrescue /dev/fd0 fdimage logfile
# current_pos current_status
0x00120000 ?
# pos size status
0x00000000 0x00117000 +
0x00117000 0x00000200 -
0x00117200 0x00001000 /
0x00118200 0x00007E00 *
0x00120000 0x00048000 ?
If you edit the file, you may use decimal, hexadecimal or octal
values, using the same syntax that integer constants in C++.
File: ddrescue.info, Node: Examples, Next: Direct disc access, Prev: Logfile structure, Up: Top
7 A small tutorial with examples
********************************
This tutorial is for those already able to use the dd command. If you
don't know what dd is, better search the net for some introductory
material about dd and GNU ddrescue first.
A failing drive tends to develop more and more errors as time passes.
Because of this, you should rescue the data from a drive as soon as you
notice the first error. Be diligent because every time a physically
damaged drive powers up and is able to output some data, it may be the
very last time that it ever will.
You should make a copy of the failing drive with ddrescue, and then
try to repair the copy. If your data is really important, use the first
copy as a master for a second copy, and try to repair the second copy.
If something goes wrong, you have the master intact to try again.
If you are trying to rescue a whole partition, first repair the copy
with e2fsck or some other tool appropiate for the type of partition you
are trying to rescue, then mount the repaired copy somewhere and try to
recover the files in it.
If the drive is so damaged that the file system in the rescued
partition can't be repaired or mounted, you will have to browse the
rescued data with an hex editor and extract the desired parts by hand
or use a file recovery tool like photorec.
If the partition table is damaged, you may try to rescue the whole
disc, then try to repair the partition table and the partitions on the
copy.
If the damaged drive is not listed in /dev, then you cannot rescue
it. At least not with ddrescue.
Example 1: Rescue a whole disc with two ext2 partitions in /dev/hda to
/dev/hdb.
Note: you do not need to partition /dev/hdb beforehand, but if the
partition table on /dev/hda is damaged, you'll need to recreate it
somehow on /dev/hdb.
ddrescue -f -n /dev/hda /dev/hdb logfile
ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
fdisk /dev/hdb
e2fsck -v -f /dev/hdb1
e2fsck -v -f /dev/hdb2
Example 2: Rescue an ext2 partition in /dev/hda2 to /dev/hdb2.
Note: you need to create the hdb2 partition with fdisk first. hdb2
should be of appropiate type and size.
ddrescue -f -n /dev/hda2 /dev/hdb2 logfile
ddrescue -d -f -r3 /dev/hda2 /dev/hdb2 logfile
e2fsck -v -f /dev/hdb2
mount -t ext2 -o ro /dev/hdb2 /mnt
(read rescued files from /mnt)
Example 3: Rescue a CD-ROM in /dev/cdrom.
ddrescue -n -b2048 /dev/cdrom cdimage logfile
ddrescue -d -b2048 /dev/cdrom cdimage logfile
(write cdimage to a blank CD-ROM)
Example 4: Rescue a CD-ROM in /dev/cdrom from two copies.
ddrescue -n -b2048 /dev/cdrom cdimage logfile
ddrescue -d -b2048 /dev/cdrom cdimage logfile
(insert second copy in the CD drive)
ddrescue -d -r1 -b2048 /dev/cdrom cdimage logfile
(write cdimage to a blank CD-ROM)
Example 5: Rescue a lzip compressed backup from two copies on CD-ROM
with error-checked merging of copies (*Note lziprecover manual:
(lziprecover)Top, for details about lziprecover).
ddrescue -b2048 /dev/cdrom cdimage1 logfile1
mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage
cp /mnt/cdimage/backup.tar.lz rescued1.tar.lz
umount /mnt/cdimage
(insert second copy in the CD drive)
ddrescue -b2048 /dev/cdrom cdimage2 logfile2
mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage
cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz
umount /mnt/cdimage
lziprecover -m -v -o backup.tar.lz rescued1.tar.lz rescued2.tar.lz
Example 6: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
freezes up at position 12345678.
ddrescue -f /dev/hda /dev/hdb logfile <-- /dev/hda freezes here
(restart /dev/hda or reboot computer)
(restart copy at a safe distance from the troubled sector)
ddrescue -f -i 12350000 /dev/hda /dev/hdb logfile
(copy backwards down to the troubled sector)
ddrescue -f -R /dev/hda /dev/hdb logfile
Example 7: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hdb
fails and you have to rescue data to a third drive, /dev/hdc.
ddrescue -f -n /dev/hda /dev/hdb logfile1 <-- /dev/hdb fails here
ddrescue -f -m logfile1 /dev/hdb /dev/hdc logfile2
ddrescue -f -n /dev/hda /dev/hdc logfile2
ddrescue -d -f -r3 /dev/hda /dev/hdc logfile2
Example 8: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
stops responding and disappears from /dev.
ddrescue -f -n /dev/hda /dev/hdb logfile <-- /dev/hda fails here
(restart /dev/hda or reboot computer as many times as needed)
ddrescue -f -n -A /dev/hda /dev/hdb logfile
ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
File: ddrescue.info, Node: Direct disc access, Next: Fill mode, Prev: Examples, Up: Top
8 Direct disc access
********************
If you notice that the positions and sizes in the log file are ALWAYS
multiples of the sector size, maybe your kernel is caching the disc
accesses and grouping them. In this case you may want to use direct disc
access or a raw device to bypass the kernel cache and rescue more of
your data.
NOTE! Sector size must be correctly set with the `--sector-size'
option for this to work. Only whole sectors can be read; both
`--input-position' and `--size' must be a multiple of sector size.
Try the `--direct' option first. If direct disc access is not
available in your system, try raw devices. Read your system
documentation to find how to bind a raw device to a regular block
device. Some OSs provide raw access through special device names, like
/dev/rdisk.
Ddrescue aligns its I/O buffer to the sector size so that it can be
used for direct disc access or to read from raw devices. For efficiency
reasons, also aligns it to the memory page size if page size is a
multiple of sector size. On some systems, ddrescue can't determine the
size of a raw device, so an explicit `--size' or `--complete-only'
option may be needed.
Using direct disc access, or reading from a raw device, may be
slower or faster than normal cached reading depending on your OS and
hardware. In case it is slower you may want to make a first pass using
normal cached reads and use direct disc access, or a raw device, only
to recover the good sectors inside the failed blocks.
Example 1: using direct disc access.
ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
ddrescue -d -f -r3 /dev/hdb1 /dev/hdc1 logfile
e2fsck -v -f /dev/hdc1
mount -t ext2 -o ro /dev/hdc1 /mnt
Example 2: using a raw device.
raw /dev/raw/raw1 /dev/hdb1
ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
ddrescue -C -f -r3 /dev/raw/raw1 /dev/hdc1 logfile
raw /dev/raw/raw1 0 0
e2fsck -v -f /dev/hdc1
mount -t ext2 -o ro /dev/hdc1 /mnt
File: ddrescue.info, Node: Fill mode, Next: Generate mode, Prev: Direct disc access, Up: Top
9 Fill mode
***********
When ddrescue is invoked with the `--fill-mode' option it operates in
"fill mode", which is different from the default "rescue mode". That
is, if you use the `--fill-mode' option, ddrescue does not rescue
anything. It only fills with data read from the input file the blocks of
the output file whose status character from the logfile coincides with
one of the type characters specified as argument to the `--fill-mode'
option.
In fill mode the input file may have any size. If it is too small,
the data will be duplicated as many times as necessary to fill the input
buffer. If it is too big, only the data needed to fill the input buffer
will be read. Then the same data will be written to every cluster or
sector to be filled.
Note that in fill mode the input file is always read from position
0. If you specify a `--input-position', it refers to the original input
file from which the logfile was built, and is only used to calculate the
offset between input and output positions.
Note also that when filling the input file of the original rescue run
you should set `--input-position' and `--output-position' to identical
values, whereas when filling the output file of the original rescue run
you should keep the original offset between `--input-position' and
`--output-position'.
The `--fill-mode' option implies the `--complete-only' option.
In fill mode the logfile is updated to allow resumability when
interrupted or in case of a crash, but as nothing is being rescued the
logfile is not destroyed. The status line is the only part of the
logfile that is modified.
The fill mode has a number of uses. See the following examples:
Example 1: Mark parts of the rescued copy to allow finding them when
examined in an hex editor. For example, the following command line fills
all blocks marked as `-' (bad-sector) with copies of the string
`BAD SECTOR ':
printf "BAD SECTOR " > tmpfile
ddrescue --fill-mode=- tmpfile outfile logfile
Example 2: Wipe only the good sectors, leaving the bad sectors alone.
This way, the drive will still test bad (i.e., with unreadable sectors).
This is the fastest way of wiping a failing drive, and is specially
useful when sending the drive back to the manufacturer for warranty
replacement.
ddrescue --fill-mode=+ --force /dev/zero bad_drive logfile
Example 3: Force the drive to remap the bad sectors, making it usable
again. If the drive has only a few bad sectors, and they are not caused
by drive age, you can probably just rewrite those sectors, and the drive
will reallocate them automatically to new "spare" sectors that it keeps
for just this purpose. WARNING! This may not work on your drive.
ddrescue --fill-mode=- --force --synchronous /dev/zero bad_drive logfile
Fill mode can also help you to figure out, independently of the file
system used, what files are partially or entirely in the bad areas of
the disc. Just follow these steps:
1) Copy the damaged drive with ddrescue until finished. Do not use
sparse writes. This yields a logfile with only finished (`+') and
bad-sector (`-') blocks.
2) Fill the bad-sector blocks of the copied drive or image file with
a string not present in any file, for example "DEADBEEF".
3) Mount the copied drive (or the image file, via loopback device).
4) Grep for the fill string in all the files. Those files containing
the string reside (at least partially) in damaged disc areas.
5) Unmount the copied drive or image file.
6) Optionally fill the bad-sector blocks of the copied drive or image
file with zeros to restore the disc image.
Example 4: Figure out what files are in the bad areas of the disc.
ddrescue -b2048 /dev/cdrom cdimage logfile
printf "DEADBEEF" > tmpfile
ddrescue --fill-mode=- tmpfile cdimage logfile
rm tmpfile
mount -t iso9660 -o loop,ro cdimage /mnt/cdimage
find /mnt/cdimage -type f -exec grep "DEADBEEF" '{}' ';'
umount /mnt/cdimage
ddrescue --fill-mode=- /dev/zero cdimage logfile
File: ddrescue.info, Node: Generate mode, Next: Ddrescuelog, Prev: Fill mode, Up: Top
10 Generate mode
****************
NOTE: When ddrescue is invoked with the `--generate-mode' option it
operates in "generate mode", which is different from the default "rescue
mode". That is, if you use the `--generate-mode' option, ddrescue does
not rescue anything. It only tries to generate a logfile for later use.
So you didn't read the tutorial and started ddrescue without a
logfile. Now, two days later, your computer crashed and you can't know
how much data ddrescue managed to save. And even worse, you can't
resume the rescue; you have to restart it from the very beginning.
Or maybe you started copying a drive with `dd conv=noerror,sync' and
are now in the same situation described above. In this case, note that
you can't use a copy made by dd unless it was invoked with the `sync'
conversion argument.
Don't despair (yet). Ddrescue can in some cases generate an
approximate logfile, from the input file and the (partial) copy, that
is almost as good as an exact logfile. It makes this by simply assuming
that sectors containing all zeros were not rescued.
However, if the destination of the copy was a drive or a partition,
(or an existing regular file and truncation was not requested), most
probably you will need to restart ddrescue from the very beginning.
(This time with a logfile, of course). The reason is that old data may
be present in the drive that have not been overwritten yet, and may be
thus non-tried but non-zero.
For example, if you first tried one of these commands:
ddrescue infile outfile
or
dd if=infile of=outfile conv=noerror,sync
then you can generate an approximate logfile with this command:
ddrescue --generate-mode infile outfile logfile
Note that you must keep the original offset between `--input-position'
and `--output-position' of the original rescue run.
File: ddrescue.info, Node: Ddrescuelog, Next: Invoking ddrescuelog, Prev: Generate mode, Up: Top
11 Ddrescuelog
**************
Ddrescuelog is a tool that manipulates ddrescue logfiles, shows logfile
contents, converts logfiles to/from other formats, compares logfiles,
tests rescue status, and can delete a logfile if the rescue is done.
Ddrescuelog operations can be restricted to one or several parts of the
logfile if the domain setting options are used.
Here are some examples of how to use ddrescuelog, alone or in
combination with other tools.
Example 1: Delete the logfile if the rescue is finished (all data is
recovered without errors left).
ddrescue -f /dev/hda /dev/hdb logfile
ddrescuelog -d logfile
Example 2: Rescue two ext2 partitions in /dev/hda to /dev/hdb and
repair the file systems using badblock lists generated with
ddrescuelog. File system block size is 4096.
Note: you do need to partition /dev/hdb beforehand.
fdisk /dev/hdb <-- partition /deb/hdb
ddrescue -f /dev/hda1 /dev/hdb1 logfile1
ddrescue -f /dev/hda2 /dev/hdb2 logfile2
ddrescuelog -l- -b4096 logfile1 > badblocks1
ddrescuelog -l- -b4096 logfile2 > badblocks2
e2fsck -v -f -L badblocks1 /dev/hdb1
e2fsck -v -f -L badblocks2 /dev/hdb2
Example 3: Rescue a whole disc with two ext2 partitions in /dev/hda to
/dev/hdb and repair the file systems using badblock lists generated with
ddrescuelog. Disc sector size is 512, file system block size is 4096.
Arguments to options `-i' and `-s' are the starting positions and sizes
of the partitions being rescued.
Note: you do not need to partition /dev/hdb beforehand, but if the
partition table on /dev/hda is damaged, you'll need to recreate it
somehow on /dev/hdb.
ddrescue -f /dev/hda /dev/hdb logfile
fdisk /dev/hdb <-- get partition sizes
ddrescuelog -l- -b512 -i63b -o0 -s9767457b -b4096 logfile > badblocks1
ddrescuelog -l- -b512 -i9767520b -o0 -s128520b -b4096 logfile > badblocks2
e2fsck -v -f -L badblocks1 /dev/hdb1
e2fsck -v -f -L badblocks2 /dev/hdb2
File: ddrescue.info, Node: Invoking ddrescuelog, Next: Problems, Prev: Ddrescuelog, Up: Top
12 Invoking ddrescuelog
***********************
The format for running ddrescuelog is:
ddrescuelog [OPTIONS] LOGFILE
Ddrescuelog supports the following options:
`-h'
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of ddrescuelog on the standard output and
exit.
`-a OLD_TYPES,NEW_TYPES'
`--change-types=OLD_TYPES,NEW_TYPES'
Change the status of every block in the rescue domain from one
type in OLD_TYPES to the corresponding type in NEW_TYPES, much like
the `tr' command does, and write the resulting logfile to standard
output. OLD_TYPES and NEW_TYPES are strings of block status
characters as defined in the chapter Logfile structure (*note
Logfile structure::). Blocks whose status is not in OLD_TYPES are
left unchanged. If NEW_TYPES is shorter than OLD_TYPES the last
type of NEW_TYPES is repeated as many times as necessary.
`-b BYTES'
`--block-size=BYTES'
Block size used by ddrescuelog. Depending on the requested
operation it may be the sector size of the input device, the block
size of the rescued file system, etc. Defaults to 512.
`-c[TYPE1TYPE2]'
`--create-logfile[=TYPE1TYPE2]'
Create a logfile from a list of block numbers read from standard
input. Only blocks included in the rescue domain will be added to
LOGFILE.
TYPE1 and TYPE2 are block status characters as defined in the
chapter Logfile structure (*note Logfile structure::). TYPE1 sets
the type for blocks included in the list, while TYPE2 sets the
type for the rest of the logfile. If not specified, TYPE1 defaults
to `+' and TYPE2 defaults to `-'.
`-d'
`--delete-if-done'
Delete the given LOGFILE if all the blocks in the rescue domain
have been successfuly recovered. The exit status is 0 if LOGFILE
could be deleted, 1 otherwise.
`-D'
`--done-status'
Test if all the blocks in the rescue domain have been successfuly
recovered. The exit status is 0 if all tested blocks are finished,
1 otherwise.
`-f'
`--force'
Force overwrite of LOGFILE.
`-i BYTES'
`--input-position=BYTES'
Starting position of the rescue domain, in bytes. Defaults to 0. It
refers to a position in the original input file.
`-l TYPES'
`--list-blocks=TYPES'
Print on standard output the block numbers of the blocks specified
as any of TYPES in LOGFILE and included in the rescue domain.
TYPES contains one or more of the block status characters defined
in the chapter Logfile structure (*note Logfile structure::).
The list format is one block number per line in decimal, like the
output of the badblocks program, so that it can be used as input
for e2fsck or other similar filesystem repairing tool.
`-m FILE'
`--domain-logfile=FILE'
Restrict the rescue domain to the blocks marked as finished in the
logfile FILE.
`-n'
`--invert-logfile'
Invert the types of the blocks in LOGFILE which are included in
the rescue domain, and write the resulting logfile to standard
output. Finished blocks (`+') are changed to bad-sector (`-'), all
other types are changed to finished. `--invert-logfile' is
equivalent to `--change-types=?*/-+,++++-'
`-o BYTES'
`--output-position=BYTES'
Starting position in output file, in bytes. Is used by the
`--list-blocks' option. Defaults to `--input-position'.
`-p FILE'
`--compare-logfile=FILE'
Compare the types of the blocks included in the rescue domain. The
exit status is 0 if all tested blocks are the same in both files, 1
otherwise.
`-q'
`--quiet'
Quiet operation. Suppress all messages.
`-s BYTES'
`--size=BYTES'
Maximum size of the rescue domain, in bytes. It refers to a size
in the original input file.
`-t'
`--show-status'
Print a summary of LOGFILE contents on the standard output. The
summary can be restricted to one or several parts of LOGFILE if
the domain setting options are used.
`-v'
`--verbose'
Verbose mode. Further -v's (up to 4) increase the verbosity level.
`-x FILE'
`--xor-logfile=FILE'
Perform a logical XOR (exclusive OR) operation between the finished
blocks in FILE and those in LOGFILE, and write the resulting
logfile to standard output. In other words, in the resulting
logfile a block is only shown as finished if it was finished in
either of the two input logfiles but not in both.
`-y FILE'
`--and-logfile=FILE'
Perform a logical AND operation between the finished blocks in
FILE and those in LOGFILE, and write the resulting logfile to
standard output. In other words, in the resulting logfile a block
is only shown as finished if it was finished in both input
logfiles.
`-z FILE'
`--or-logfile=FILE'
Perform a logical OR operation between the finished blocks in FILE
and those in LOGFILE, and write the resulting logfile to standard
output. In other words, in the resulting logfile a block is shown
as finished if it was finished in either of the two input logfiles.
Exit status: 0 for a normal exit, 1 for environmental problems (file
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused ddrescuelog to panic.
File: ddrescue.info, Node: Problems, Next: Concept index, Prev: Invoking ddrescuelog, Up: Top
13 Reporting Bugs
*****************
There are probably bugs in ddrescue. There are certainly errors and
omissions in this manual. If you report them, they will get fixed. If
you don't, no one will ever know about them and they will remain unfixed
for all eternity, if not longer.
If you find a bug in GNU ddrescue, please send electronic mail to
. Include the version number, which you can find
by running `ddrescue --version'.
File: ddrescue.info, Node: Concept index, Prev: Problems, Up: Top
Concept index
*************
[index ]
* Menu:
* algorithm: Algorithm. (line 6)
* basic concepts: Basic concepts. (line 6)
* bugs: Problems. (line 6)
* ddrescuelog: Ddrescuelog. (line 6)
* direct disc access: Direct disc access. (line 6)
* examples: Examples. (line 6)
* fill Mode: Fill mode. (line 6)
* generate Mode: Generate mode. (line 6)
* getting help: Problems. (line 6)
* introduction: Introduction. (line 6)
* invoking ddrescue: Invoking ddrescue. (line 6)
* invoking ddrescuelog: Invoking ddrescuelog. (line 6)
* logfile structure: Logfile structure. (line 6)
* options: Invoking ddrescue. (line 6)
* raw devices: Direct disc access. (line 6)
* usage: Invoking ddrescue. (line 6)
* using ddrescue safely: Important advice. (line 6)
* version: Invoking ddrescue. (line 6)
Tag Table:
Node: Top203
Node: Introduction1368
Node: Basic concepts4081
Node: Important advice5561
Node: Algorithm6670
Node: Invoking ddrescue10549
Node: Logfile structure21284
Node: Examples23534
Ref: lziprecover-example26507
Node: Direct disc access28347
Node: Fill mode30425
Node: Generate mode34565
Node: Ddrescuelog36512
Node: Invoking ddrescuelog38661
Node: Problems44152
Node: Concept index44709
End Tag Table
Local Variables:
coding: iso-8859-15
End:
gddrescue-1.17/doc/ddrescue.texinfo 0000664 0000000 0000000 00000131507 12235656145 0017370 0 ustar 00root root 0000000 0000000 \input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename ddrescue.info
@documentencoding ISO-8859-15
@settitle GNU ddrescue Manual
@finalout
@c %**end of header
@set UPDATED 9 July 2013
@set VERSION 1.17
@dircategory GNU Packages
@direntry
* Ddrescue: (ddrescue). Data recovery tool
@end direntry
@ifnothtml
@titlepage
@title GNU ddrescue
@subtitle Data recovery tool
@subtitle for Ddrescue version @value{VERSION}, @value{UPDATED}
@author by Antonio Diaz Diaz
@page
@vskip 0pt plus 1filll
@end titlepage
@contents
@end ifnothtml
@node Top
@top
This manual is for GNU ddrescue (version @value{VERSION}, @value{UPDATED}).
@menu
* Introduction:: Purpose and features of GNU ddrescue
* Basic concepts:: Blocks, clusters, devices, files, sectors, etc
* Important advice:: Read this or risk losing your data
* Algorithm:: How ddrescue recovers the data
* Invoking ddrescue:: Command line interface
* Logfile structure:: Detailed format of the logfile
* Examples:: A small tutorial with examples
* Direct disc access:: Bypassing the kernel cache
* Fill mode:: Selectively overwriting the output file
* Generate mode:: Generating an approximate logfile
* Ddrescuelog:: Tool for ddrescue logfiles
* Invoking ddrescuelog:: Command line interface
* Problems:: Reporting bugs
* Concept index:: Index of concepts
@end menu
@sp 1
Copyright @copyright{} 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
2012, 2013 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission
to copy, distribute and modify it.
@node Introduction
@chapter Introduction
@cindex introduction
GNU ddrescue is a data recovery tool. It copies data from one file or
block device (hard disc, cdrom, etc) to another, trying hard to rescue
data in case of read errors.
The basic operation of ddrescue is fully automatic. That is, you don't
have to wait for an error, stop the program, read the log, restart it
from a new position, etc.
If you use the logfile feature of ddrescue, the data is rescued very
efficiently, (only the needed blocks are read). Also you can interrupt
the rescue at any time and resume it later at the same point.
Ddrescue does not write zeros to the output when it finds bad sectors in
the input, and does not truncate the output file if not asked to. So,
every time you run it on the same output file, it tries to fill in the
gaps without wiping out the data already rescued.
Automatic merging of backups: If you have two or more damaged copies of
a file, cdrom, etc, and run ddrescue on all of them, one at a time,
with the same output file, you will probably obtain a complete and
error-free file. This is so because the probability of having damaged
areas at the same places on different input files is very low. Using
the logfile, only the needed blocks are read from the second and
successive copies.
Ddrescue recommends lzip for compression of backups because of its
reliability and data recovery capabilities, including error-checked
merging of backup copies. Lziprecover makes lzip files resistant to
bit-flip, one of the most common forms of data corruption, and its
recovery capabilities contribute to make of the lzip format one of the
best formats for long-term data archiving. The combination ddrescue +
lziprecover is the best option for recovering data from multiple damaged
copies. @xref{lziprecover-example}, for an example.
Recordable CD and DVD media keep their data only for a finite time
(typically for many years). After that time, data loss develops slowly
with read errors growing from the outer media region towards the inside.
Just make two (or more) copies of every important CD/DVD you burn so
that you can later recover them with ddrescue.
Because ddrescue needs to read and write at random places, it only works
on seekable (random access) input and output files.
If your system supports it, ddrescue can use direct disc access to read
the input file, bypassing the kernel cache.
Ddrescue also features a "fill mode" able to selectively overwrite parts
of the output file, which has a number of interesting uses like wiping
data, marking bad areas or even, in some cases, "repair" damaged
sectors.
@node Basic concepts
@chapter Basic concepts
@cindex basic concepts
@table @asis
@item Block
Any amount of data. A block is described by its starting position and
its size.
@item Cluster
Group of consecutive sectors read or written in one go.
@item Device
Piece of hardware containing data. Hard disc drives, cdrom drives, USB
pendrives, are devices. /dev/hda, /dev/sdb, are device names.
@item File
Files are named units of data which are stored by the operating system
for you to retrieve later by name. Devices and partitions are accessed
by means of their associated file names.
@item Partition
Every part in which a device is divided. A partition normally contains a
file system. /dev/hda1, /dev/sdb3, are partition names.
@item Recoverable formats
As ddrescue uses standard library functions to read data from the device
being rescued, only mountable device formats can be rescued with
ddrescue. DVDs can be mounted and they can be rescued, "compact disc
digital audio" CDs can't, "video CDs"[1] maybe.@*
[1] http://en.wikipedia.org/wiki/Video_CD
@item Rescue domain
Block or set of blocks to be acted upon (rescued, listed, etc). You can
define it with the options @samp{--input-position}, @samp{--size} and
@samp{--domain-logfile}. The rescue domain defaults to the whole input
file or logfile.
@item Sector
Hardware block. Smallest accessible amount of data on a device.
@end table
@node Important advice
@chapter Using ddrescue safely
@cindex using ddrescue safely
Ddrescue is like any other power tool. You need to understand what it
does, and you need to understand some things about the machines it does
those things to, in order to use it safely.
Always use a logfile unless you know you won't need it. Without a
logfile, ddrescue can't resume a rescue, only reinitiate it.
Never try to rescue a r/w mounted partition. The resulting copy may be
useless.
Never try to repair a file system on a drive with I/O errors; you will
probably lose even more data.
If you use a device or a partition as destination, any data stored there
will be overwritten.
Some systems may change device names on reboot (eg. udev enabled
systems). If you reboot, check the device names before restarting
ddrescue.
If you interrupt the rescue and then reboot, any partially copied
partitions should be hidden before allowing them to be touched by any
operating system that tries to mount and "fix" the partitions it sees.
@node Algorithm
@chapter Algorithm
@cindex algorithm
GNU ddrescue manages efficiently the status of the rescue in progress
and tries to rescue the good parts first, scheduling reads inside bad
(or slow) areas for later. This maximizes the amount of data that can be
finally recovered from a failing drive.
The standard dd utility can be used to save data from a failing drive,
but it reads the data sequentially, which may wear out the drive without
rescuing anything if the errors are at the beginning of the drive.
Other programs switch to small size reads when they find errors, but
they still read the data sequentially. This is a bad idea because it
means spending more time at error areas, damaging the surface, the heads
and the drive mechanics, instead of getting out of them as fast as
possible. This behavior reduces the chances of rescuing the remaining
good data.
The algorithm of ddrescue is as follows (the user may interrupt the
process at any point, but be aware that a bad drive can block ddrescue
for a long time until the kernel gives up):
1) Optionally read a logfile describing the status of a multi-part or
previously interrupted rescue. If no logfile is specified or is empty or
does not exist, mark all the rescue domain as non-tried.
2) (First phase; Copying) Read the non-tried parts of the input file,
marking the failed blocks as non-trimmed and skipping beyond them, until
all the rescue domain is tried. Only non-tried areas are read in large
blocks. Trimming, splitting and retrying are done sector by sector. Each
sector is tried at most two times; the first in this step as part of a
large block read, the second in one of the steps below as a single
sector read.
3) (Second phase; Trimming) Read forwards one sector at a time from the
leading edge of the largest non-trimmed block, until a bad sector is
found. Then read backwards one sector at a time from the trailing edge
of the same block, until a bad sector is found. For each non-trimmed
block, mark the bad sectors found as bad-sector and mark the rest of
that block as non-split. Repeat until there are no more non-trimmed
blocks.
4) (Third phase; Splitting) Read forwards one sector at a time from the
center of the largest non-split block, until a bad sector is found. Then
read backwards one sector at a time from the center of the same block,
until a bad sector is found. If the logfile is larger than
@samp{--logfile-size}, read the smallest non-split blocks until the
number of entries in the logfile drops below @samp{--logfile-size}.
Repeat until all remaining non-split blocks have less than 5 sectors.
Then read the remaining non-split blocks sequentially.
5) (Fourth phase; Retrying) Optionally try to read again the bad sectors
until the specified number of retries is reached.
6) Optionally write a logfile for later use.
@sp 1
Note that as ddrescue splits the failed blocks, making them smaller, the
total error size may diminish while the number of errors increases.
The logfile is periodically saved to disc, as well as when ddrescue
finishes or is interrupted. So in case of a crash you can resume the
rescue with little recopying.
Also, the same logfile can be used for multiple commands that copy
different areas of the input file, and for multiple recovery attempts
over different subsets. See this example:
@noindent
Rescue the most important part of the disc first.
@example
ddrescue -i0 -s50MiB /dev/hdc hdimage logfile
ddrescue -i0 -s1MiB -d -r3 /dev/hdc hdimage logfile
@end example
@noindent
Then rescue some key disc areas.
@example
ddrescue -i30GiB -s10GiB /dev/hdc hdimage logfile
ddrescue -i230GiB -s5GiB /dev/hdc hdimage logfile
@end example
@noindent
Now rescue the rest (does not recopy what is already done).
@example
ddrescue /dev/hdc hdimage logfile
ddrescue -d -r3 /dev/hdc hdimage logfile
@end example
@node Invoking ddrescue
@chapter Invoking ddrescue
@cindex invoking ddrescue
@cindex options
@cindex usage
@cindex version
The format for running ddrescue is:
@example
ddrescue [@var{options}] @var{infile} @var{outfile} [@var{logfile}]
@end example
ddrescue supports the following options:
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of ddrescue on the standard output and exit.
@item -a @var{bytes}
@itemx --min-read-rate=@var{bytes}
Minimum read rate of good non-tried areas, in bytes per second. If the
read rate falls below this value, ddrescue will skip ahead a variable
amount depending on rate and error history. The skipped blocks are tried
in additional passes (before trimming) where the minimum read rate is
divided by ten before each pass, until there are no more non-tried
blocks left. If @var{bytes} is 0 (auto), the minimum read rate is
recalculated for each block read as @w{(average_rate / 10)}.
@item -A
@itemx --try-again
Mark all non-split and non-trimmed blocks inside the rescue domain as
non-tried before beginning the rescue. Try this if the drive stops
responding and ddrescue immediately starts splitting failed blocks when
restarted. If @samp{--retrim} is also specified, mark all failed blocks
inside the rescue domain as non-tried.
@item -b @var{bytes}
@itemx --sector-size=@var{bytes}
Sector (hardware block) size of input device in bytes (usually 512 for
hard discs and 3.5" floppies, 1024 for 5.25" floppies, and 2048 for
cdroms). Defaults to 512.
@item -B
@itemx --binary-prefixes
Show units with binary prefixes (powers of 1024).@*
SI prefixes (powers of 1000) are used by default. (See table below).
@item -c @var{sectors}
@itemx --cluster-size=@var{sectors}
Number of sectors to copy at a time. Defaults to @w{64 KiB / sector_size}.
Try smaller values for slow drives. The number of sectors per track (18
or 9) is a good value for floppies.
@item -C
@itemx --complete-only
Limit rescue domain to the blocks listed in the @var{logfile}. Do not
read new data beyond @var{logfile} limits. This is useful when reading
from devices of undefined size (like raw devices), when the drive
returns an incorrect size, or when reading from a partial copy. It can
only be used after a first rescue attempt, possibly limited with the
@samp{--size} option, has produced a complete @var{logfile}.
@item -d
@itemx --direct
Use direct disc access to read from @var{infile}, bypassing the kernel
cache. (Open the file with the O_DIRECT flag). Use it only on devices or
partitions, not on regular files. Sector size must be correctly set for
this to work. Not all systems support this.
If your system does not support direct disc access, ddrescue will warn
you. If the sector size is not correctly set, all reads will result in
errors, and no data will be rescued.
@item -D
@itemx --synchronous
Use synchronous writes for @var{outfile}. (Issue a fsync call after
every write). May be useful when forcing the drive to remap its bad
sectors.
@item -e [+]@var{n}
@itemx --max-errors=[+]@var{n}
Maximum number of error areas allowed before giving up. Defaults to
infinity. If @var{n} is preceded by @samp{+} the number refers to new
error areas found in this run, not counting those already annotated in
the @var{logfile}.
@item -E @var{bytes}
@itemx --max-error-rate=@var{bytes}
Maximum rate of errors allowed before giving up, in bytes per second.
Defaults to infinity. The rate being measured is that of actually failed
reads, so the rescue may finish because of this rate being exceeded even
if the total error size (errsize) does not change because the areas
being tried are already marked as errors.
@item -f
@itemx --force
Force overwrite of @var{outfile}. Needed when @var{outfile} is not a
regular file, but a device or partition.
@item -F @var{types}
@itemx --fill-mode=@var{types}
Fill the blocks in @var{outfile} specified as any of @var{types} in
@var{logfile}, with data read from @var{infile}. @var{types} contains
one or more of the status characters defined in the chapter Logfile
Structure (@pxref{Logfile structure}). See the chapter Fill mode
(@pxref{Fill mode}) for a complete description of the fill mode.
@item -g
@itemx --generate-mode
Generate an approximate @var{logfile} from the @var{infile} and
@var{outfile} of the original rescue run. Note that you must keep the
original offset between @samp{--input-position} and
@samp{--output-position} of the original rescue run. See the chapter
Generate mode (@pxref{Generate mode}) for a complete description of the
generate mode.
@item -i @var{bytes}
@itemx --input-position=@var{bytes}
Starting position in @var{infile}, in bytes. Defaults to 0. In fill mode
it refers to a position in the @var{infile} of the original rescue run.
See the chapter Fill mode (@pxref{Fill mode}) for details.
@item -I
@itemx --verify-input-size
Compare the size of @var{infile} with the size calculated from the list
of blocks contained in the @var{logfile}, and exit with status 1 if they
differ. This is not enabled by default because the size of some devices
can't be known in advance and because the size derived from the
@var{logfile} may be incomplete, for example after doing a partial
rescue.
@item -K @var{bytes}
@itemx --skip-size=@var{bytes}
Set the initial size to skip on the first read error or slow read. The
value given will be rounded to the next multiple of sector size. For
subsequent read errors or slow reads, ddrescue will modify the skip size
depending on error rate and error history. Valid values range from 64 KiB
to 1 GiB. Defaults to 64 KiB.
@item -l @var{entries}
@itemx --logfile-size=@var{entries}
During the splitting phase, do not grow logfile beyond this number of
entries. Logfile may be larger if it was larger at startup or if it
became larger during the copying or trimming phases. Defaults to 1000.
(Each entry is about 26-30 bytes in size).
@item -m @var{file}
@itemx --domain-logfile=@var{file}
Restrict the rescue domain to the blocks marked as finished in the
logfile @var{file}. This is useful if the destination drive fails during
the rescue.
@item -M
@itemx --retrim
Mark all failed blocks inside the rescue domain as non-trimmed before
beginning the rescue. The effect is similar to @samp{--retries=1}, but
the bad sectors are tried in a different order, making perhaps possible
to rescue some of them.
@item -n
@itemx --no-split
Skip the splitting phase. Avoids spending a lot of time trying to rescue
the most difficult parts of the file.
@item -o @var{bytes}
@itemx --output-position=@var{bytes}
Starting position in @var{outfile}, in bytes. Defaults to
@samp{--input-position}. The bytes below @var{bytes} aren't touched if
they exist and truncation is not requested. Else they are set to 0.
@item -p
@itemx --preallocate
Preallocate space on disc for @var{outfile}. Only space for regular
files can be preallocated. If preallocation succeeds, rescue will not
fail due to lack of free space on disc. If ddrescue can't determine the
size to preallocate, you may need to specify it with some combination of
the @samp{--input-position}, @samp{--output-position}, @samp{--size},
and @samp{--domain-logfile} options.
@item -q
@itemx --quiet
Quiet operation. Suppress all messages.
@item -r @var{n}
@itemx --retries=@var{n}
Exit after given number of retry passes. Defaults to 0. -1 means
infinity. Every bad sector is tried only one time per pass. To retry bad
sectors detected on a previous run, you must specify a non-zero number
of retries.
@item -R
@itemx --reverse
Reverse direction of copying, retrying, and the sequential part of
splitting, running them backwards from the end of the input file.
@item -s @var{bytes}
@itemx --size=@var{bytes}
Maximum size of the input data to be copied, in bytes. If ddrescue can't
determine the size of the input device, you may need to specify it with
this option. Note that this option specifies the size of the input data
to be copied, not the size of the resulting @var{outfile}. So, for
example, the following command creates an @var{outfile} 300 bytes long,
but only writes data on the last 200 bytes:
@example
ddrescue -i 100 -s 200 infile outfile logfile
@end example
@item -S
@itemx --sparse
Use sparse writes for @var{outfile}. (The blocks of zeros are not
actually allocated on disc). May save a lot of disc space in some cases.
Not all systems support this. Only regular files can be sparse.
@item -t
@itemx --truncate
Truncate @var{outfile} to zero size before writing to it. Only works for
regular files, not for drives or partitions.
@item -T @var{interval}
@itemx --timeout=@var{interval}
Maximum time since last successful read allowed before giving up.
Defaults to infinity. @var{interval} is a rational number (like 1.5 or
1/2) optionally followed by one of @samp{s}, @samp{m}, @samp{h} or
@samp{d}, meaning seconds, minutes, hours and days respectively. If no
unit is specified, it defaults to seconds.
@item -v
@itemx --verbose
Verbose mode. Further -v's (up to 4) increase the verbosity level.
@item -w
@itemx --ignore-write-errors
Make fill mode ignore write errors. This is useful to avoid ddrescue
exiting because of new errors developing while wiping the good sectors
of a failing drive. Fill mode normally writes to @var{outfile} one
cluster at a time. With this option, after the first write error is
found in an area, the rest of that area is filled sector by sector.
@item -x @var{bytes}
@itemx --extend-outfile=@var{bytes}
Extend the size of @var{outfile} to make it at least @var{bytes} long.
If the size of @var{outfile} is already equal or longer than @var{bytes}
then this option does nothing. Use this option to guarantee a minimum
size for @var{outfile}. Only regular files can be extended.
@end table
@sp 1
Numbers given as arguments to options (positions, sizes, retries, etc)
may be followed by a multiplier and an optional @samp{B} for "byte".
Table of SI and binary prefixes (unit multipliers):
@multitable {Prefix} {kilobyte (10^3 = 1000)} {|} {Prefix} {kibibyte (2^10 = 1024)}
@item Prefix @tab Value @tab | @tab Prefix @tab Value
@item @tab @tab | @tab s @tab sectors
@item k @tab kilobyte (10^3 = 1000) @tab | @tab Ki @tab kibibyte (2^10 = 1024)
@item M @tab megabyte (10^6) @tab | @tab Mi @tab mebibyte (2^20)
@item G @tab gigabyte (10^9) @tab | @tab Gi @tab gibibyte (2^30)
@item T @tab terabyte (10^12) @tab | @tab Ti @tab tebibyte (2^40)
@item P @tab petabyte (10^15) @tab | @tab Pi @tab pebibyte (2^50)
@item E @tab exabyte (10^18) @tab | @tab Ei @tab exbibyte (2^60)
@item Z @tab zettabyte (10^21) @tab | @tab Zi @tab zebibyte (2^70)
@item Y @tab yottabyte (10^24) @tab | @tab Yi @tab yobibyte (2^80)
@end multitable
@sp 1
Exit status: 0 for a normal exit, 1 for environmental problems (file not
found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused ddrescue to panic.
@node Logfile structure
@chapter Logfile structure
@cindex logfile structure
The logfile is a text file easy to read and edit. It is formed by three
parts, the heading comments, the status line, and the list of data
blocks. Any line beginning with @samp{#} is a comment line.
NOTE: Logfiles generated by a version of ddrescue prior to 1.6 lack the
status line. If you want to use an old logfile with ddrescue 1.6 or
later, you will have to insert a line like @samp{0 +} at the beginning
of the logfile.
The heading comments contain the version of ddrescue and the command
line used to create the logfile. They are intended as information for
the user.
The first non-comment line is the status line. It contains a
non-negative integer and a status character. The integer is the position
being tried in the input file. The status character is one of these:
@multitable {Character} {generating approximate logfile}
@item Character @tab Meaning
@item '?' @tab copying non-tried blocks
@item '*' @tab trimming non-trimmed blocks
@item '/' @tab splitting non-split blocks
@item '-' @tab retrying bad sectors
@item 'F' @tab filling specified blocks
@item 'G' @tab generating approximate logfile
@item '+' @tab finished
@end multitable
The blocks in the list of data blocks must be contiguous and
non-overlapping.
Every line in the list of data blocks describes a block of data. It
contains 2 non-negative integers and a status character. The first
integer is the starting position of the block in the input file, the
second integer is the size (in bytes) of the block. The status character
is one of these:
@multitable {Character} {failed block bad-sector(s)}
@item Character @tab Meaning
@item '?' @tab non-tried block
@item '*' @tab failed block non-trimmed
@item '/' @tab failed block non-split
@item '-' @tab failed block bad-sector(s)
@item '+' @tab finished block
@end multitable
@noindent
And here is an example logfile:
@noindent
# Rescue Logfile. Created by GNU ddrescue version @value{VERSION}@*
# Command line: ddrescue /dev/fd0 fdimage logfile@*
# current_pos current_status@*
0x00120000 ?@*
# pos size status@*
@multitable {0x00000000} {0x00000000} {status}
@item 0x00000000 @tab 0x00117000 @tab +
@item 0x00117000 @tab 0x00000200 @tab -
@item 0x00117200 @tab 0x00001000 @tab /
@item 0x00118200 @tab 0x00007E00 @tab *
@item 0x00120000 @tab 0x00048000 @tab ?
@end multitable
If you edit the file, you may use decimal, hexadecimal or octal values,
using the same syntax that integer constants in C++.
@node Examples
@chapter A small tutorial with examples
@cindex examples
This tutorial is for those already able to use the dd command. If you
don't know what dd is, better search the net for some introductory
material about dd and GNU ddrescue first.
A failing drive tends to develop more and more errors as time passes.
Because of this, you should rescue the data from a drive as soon as you
notice the first error. Be diligent because every time a physically
damaged drive powers up and is able to output some data, it may be the
very last time that it ever will.
You should make a copy of the failing drive with ddrescue, and then try
to repair the copy. If your data is really important, use the first copy
as a master for a second copy, and try to repair the second copy. If
something goes wrong, you have the master intact to try again.
If you are trying to rescue a whole partition, first repair the copy
with e2fsck or some other tool appropiate for the type of partition you
are trying to rescue, then mount the repaired copy somewhere and try to
recover the files in it.
If the drive is so damaged that the file system in the rescued partition
can't be repaired or mounted, you will have to browse the rescued data
with an hex editor and extract the desired parts by hand or use a file
recovery tool like photorec.
If the partition table is damaged, you may try to rescue the whole disc,
then try to repair the partition table and the partitions on the copy.
If the damaged drive is not listed in /dev, then you cannot rescue it.
At least not with ddrescue.
@sp 1
@noindent
Example 1: Rescue a whole disc with two ext2 partitions in /dev/hda to
/dev/hdb.@*
Note: you do not need to partition /dev/hdb beforehand, but if the
partition table on /dev/hda is damaged, you'll need to recreate it
somehow on /dev/hdb.
@example
ddrescue -f -n /dev/hda /dev/hdb logfile
ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
fdisk /dev/hdb
e2fsck -v -f /dev/hdb1
e2fsck -v -f /dev/hdb2
@end example
@sp 1
@noindent
Example 2: Rescue an ext2 partition in /dev/hda2 to /dev/hdb2.@*
Note: you need to create the hdb2 partition with fdisk first. hdb2
should be of appropiate type and size.
@example
ddrescue -f -n /dev/hda2 /dev/hdb2 logfile
ddrescue -d -f -r3 /dev/hda2 /dev/hdb2 logfile
e2fsck -v -f /dev/hdb2
mount -t ext2 -o ro /dev/hdb2 /mnt
(read rescued files from /mnt)
@end example
@sp 1
@noindent
Example 3: Rescue a CD-ROM in /dev/cdrom.
@example
ddrescue -n -b2048 /dev/cdrom cdimage logfile
ddrescue -d -b2048 /dev/cdrom cdimage logfile
(write cdimage to a blank CD-ROM)
@end example
@sp 1
@noindent
Example 4: Rescue a CD-ROM in /dev/cdrom from two copies.
@example
ddrescue -n -b2048 /dev/cdrom cdimage logfile
ddrescue -d -b2048 /dev/cdrom cdimage logfile
(insert second copy in the CD drive)
ddrescue -d -r1 -b2048 /dev/cdrom cdimage logfile
(write cdimage to a blank CD-ROM)
@end example
@sp 1
@anchor{lziprecover-example}
@noindent
Example 5: Rescue a lzip compressed backup from two copies on CD-ROM
with error-checked merging of copies
@ifnothtml
(@xref{Top,lziprecover manual,,lziprecover},
@end ifnothtml
@ifhtml
(See the
@uref{http://www.nongnu.org/lzip/manual/lziprecover_manual.html,,lziprecover manual}
@end ifhtml
for details about lziprecover).
@example
ddrescue -b2048 /dev/cdrom cdimage1 logfile1
mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage
cp /mnt/cdimage/backup.tar.lz rescued1.tar.lz
umount /mnt/cdimage
(insert second copy in the CD drive)
ddrescue -b2048 /dev/cdrom cdimage2 logfile2
mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage
cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz
umount /mnt/cdimage
lziprecover -m -v -o backup.tar.lz rescued1.tar.lz rescued2.tar.lz
@end example
@sp 1
@noindent
Example 6: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
freezes up at position 12345678.
@example
ddrescue -f /dev/hda /dev/hdb logfile <-- /dev/hda freezes here
(restart /dev/hda or reboot computer)
(restart copy at a safe distance from the troubled sector)
ddrescue -f -i 12350000 /dev/hda /dev/hdb logfile
(copy backwards down to the troubled sector)
ddrescue -f -R /dev/hda /dev/hdb logfile
@end example
@sp 1
@noindent
Example 7: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hdb
fails and you have to rescue data to a third drive, /dev/hdc.
@example
ddrescue -f -n /dev/hda /dev/hdb logfile1 <-- /dev/hdb fails here
ddrescue -f -m logfile1 /dev/hdb /dev/hdc logfile2
ddrescue -f -n /dev/hda /dev/hdc logfile2
ddrescue -d -f -r3 /dev/hda /dev/hdc logfile2
@end example
@sp 1
@noindent
Example 8: While rescuing the whole drive /dev/hda to /dev/hdb, /dev/hda
stops responding and disappears from /dev.
@example
ddrescue -f -n /dev/hda /dev/hdb logfile <-- /dev/hda fails here
(restart /dev/hda or reboot computer as many times as needed)
ddrescue -f -n -A /dev/hda /dev/hdb logfile
ddrescue -d -f -r3 /dev/hda /dev/hdb logfile
@end example
@node Direct disc access
@chapter Direct disc access
@cindex direct disc access
@cindex raw devices
If you notice that the positions and sizes in the log file are ALWAYS
multiples of the sector size, maybe your kernel is caching the disc
accesses and grouping them. In this case you may want to use direct disc
access or a raw device to bypass the kernel cache and rescue more of
your data.
NOTE! Sector size must be correctly set with the @samp{--sector-size}
option for this to work. Only whole sectors can be read; both
@samp{--input-position} and @samp{--size} must be a multiple of sector
size.
Try the @samp{--direct} option first. If direct disc access is not
available in your system, try raw devices. Read your system
documentation to find how to bind a raw device to a regular block
device. Some OSs provide raw access through special device names, like
/dev/rdisk.
Ddrescue aligns its I/O buffer to the sector size so that it can be used
for direct disc access or to read from raw devices. For efficiency
reasons, also aligns it to the memory page size if page size is a
multiple of sector size. On some systems, ddrescue can't determine the
size of a raw device, so an explicit @samp{--size} or
@samp{--complete-only} option may be needed.
Using direct disc access, or reading from a raw device, may be slower or
faster than normal cached reading depending on your OS and hardware. In
case it is slower you may want to make a first pass using normal cached
reads and use direct disc access, or a raw device, only to recover the
good sectors inside the failed blocks.
@sp 1
@noindent
Example 1: using direct disc access.
@example
ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
ddrescue -d -f -r3 /dev/hdb1 /dev/hdc1 logfile
e2fsck -v -f /dev/hdc1
mount -t ext2 -o ro /dev/hdc1 /mnt
@end example
@sp 1
@noindent
Example 2: using a raw device.
@example
raw /dev/raw/raw1 /dev/hdb1
ddrescue -f -n /dev/hdb1 /dev/hdc1 logfile
ddrescue -C -f -r3 /dev/raw/raw1 /dev/hdc1 logfile
raw /dev/raw/raw1 0 0
e2fsck -v -f /dev/hdc1
mount -t ext2 -o ro /dev/hdc1 /mnt
@end example
@node Fill mode
@chapter Fill mode
@cindex fill Mode
When ddrescue is invoked with the @samp{--fill-mode} option it operates
in "fill mode", which is different from the default "rescue mode". That
is, if you use the @samp{--fill-mode} option, ddrescue does not rescue
anything. It only fills with data read from the input file the blocks of
the output file whose status character from the logfile coincides with
one of the type characters specified as argument to the
@samp{--fill-mode} option.
In fill mode the input file may have any size. If it is too small, the
data will be duplicated as many times as necessary to fill the input
buffer. If it is too big, only the data needed to fill the input buffer
will be read. Then the same data will be written to every cluster or
sector to be filled.
Note that in fill mode the input file is always read from position 0. If
you specify a @samp{--input-position}, it refers to the original input
file from which the logfile was built, and is only used to calculate the
offset between input and output positions.
Note also that when filling the input file of the original rescue run
you should set @samp{--input-position} and @samp{--output-position} to
identical values, whereas when filling the output file of the original
rescue run you should keep the original offset between
@samp{--input-position} and @samp{--output-position}.
The @samp{--fill-mode} option implies the @samp{--complete-only} option.
In fill mode the logfile is updated to allow resumability when
interrupted or in case of a crash, but as nothing is being rescued the
logfile is not destroyed. The status line is the only part of the
logfile that is modified.
@sp 1
@noindent
The fill mode has a number of uses. See the following examples:
@noindent
Example 1: Mark parts of the rescued copy to allow finding them when
examined in an hex editor. For example, the following command line fills
all blocks marked as @samp{-} (bad-sector) with copies of the string
@w{@samp{BAD SECTOR }}:
@example
printf "BAD SECTOR " > tmpfile
ddrescue --fill-mode=- tmpfile outfile logfile
@end example
@noindent
Example 2: Wipe only the good sectors, leaving the bad sectors alone.
This way, the drive will still test bad (i.e., with unreadable sectors).
This is the fastest way of wiping a failing drive, and is specially
useful when sending the drive back to the manufacturer for warranty
replacement.
@example
ddrescue --fill-mode=+ --force /dev/zero bad_drive logfile
@end example
@noindent
Example 3: Force the drive to remap the bad sectors, making it usable
again. If the drive has only a few bad sectors, and they are not caused
by drive age, you can probably just rewrite those sectors, and the drive
will reallocate them automatically to new "spare" sectors that it keeps
for just this purpose. WARNING! This may not work on your drive.
@example
ddrescue --fill-mode=- --force --synchronous /dev/zero bad_drive logfile
@end example
@sp 1
@noindent
Fill mode can also help you to figure out, independently of the file
system used, what files are partially or entirely in the bad areas of
the disc. Just follow these steps:
1) Copy the damaged drive with ddrescue until finished. Do not use
sparse writes. This yields a logfile with only finished (@samp{+}) and
bad-sector (@samp{-}) blocks.
2) Fill the bad-sector blocks of the copied drive or image file with a
string not present in any file, for example "DEADBEEF".
3) Mount the copied drive (or the image file, via loopback device).
4) Grep for the fill string in all the files. Those files containing the
string reside (at least partially) in damaged disc areas.
5) Unmount the copied drive or image file.
6) Optionally fill the bad-sector blocks of the copied drive or image
file with zeros to restore the disc image.
@noindent
Example 4: Figure out what files are in the bad areas of the disc.
@example
ddrescue -b2048 /dev/cdrom cdimage logfile
printf "DEADBEEF" > tmpfile
ddrescue --fill-mode=- tmpfile cdimage logfile
rm tmpfile
mount -t iso9660 -o loop,ro cdimage /mnt/cdimage
find /mnt/cdimage -type f -exec grep "DEADBEEF" '@{@}' ';'
umount /mnt/cdimage
ddrescue --fill-mode=- /dev/zero cdimage logfile
@end example
@node Generate mode
@chapter Generate mode
@cindex generate Mode
NOTE: When ddrescue is invoked with the @samp{--generate-mode} option it
operates in "generate mode", which is different from the default "rescue
mode". That is, if you use the @samp{--generate-mode} option, ddrescue
does not rescue anything. It only tries to generate a logfile for later
use.
So you didn't read the tutorial and started ddrescue without a logfile.
Now, two days later, your computer crashed and you can't know how much
data ddrescue managed to save. And even worse, you can't resume the
rescue; you have to restart it from the very beginning.
Or maybe you started copying a drive with @w{@code{dd
conv=noerror,sync}} and are now in the same situation described above.
In this case, note that you can't use a copy made by dd unless it was
invoked with the @samp{sync} conversion argument.
Don't despair (yet). Ddrescue can in some cases generate an approximate
logfile, from the input file and the (partial) copy, that is almost as
good as an exact logfile. It makes this by simply assuming that sectors
containing all zeros were not rescued.
However, if the destination of the copy was a drive or a partition, (or
an existing regular file and truncation was not requested), most
probably you will need to restart ddrescue from the very beginning.
(This time with a logfile, of course). The reason is that old data may
be present in the drive that have not been overwritten yet, and may be
thus non-tried but non-zero.
For example, if you first tried one of these commands:
@example
ddrescue infile outfile
or
dd if=infile of=outfile conv=noerror,sync
@end example
then you can generate an approximate logfile with this command:
@example
ddrescue --generate-mode infile outfile logfile
@end example
@noindent
Note that you must keep the original offset between
@samp{--input-position} and @samp{--output-position} of the original
rescue run.
@node Ddrescuelog
@chapter Ddrescuelog
@cindex ddrescuelog
Ddrescuelog is a tool that manipulates ddrescue logfiles, shows logfile
contents, converts logfiles to/from other formats, compares logfiles,
tests rescue status, and can delete a logfile if the rescue is done.
Ddrescuelog operations can be restricted to one or several parts of the
logfile if the domain setting options are used.
Here are some examples of how to use ddrescuelog, alone or in
combination with other tools.
@sp 1
@noindent
Example 1: Delete the logfile if the rescue is finished (all data is
recovered without errors left).
@example
ddrescue -f /dev/hda /dev/hdb logfile
ddrescuelog -d logfile
@end example
@sp 1
@noindent
Example 2: Rescue two ext2 partitions in /dev/hda to
/dev/hdb and repair the file systems using badblock lists generated with
ddrescuelog. File system block size is 4096.@*
Note: you do need to partition /dev/hdb beforehand.
@example
fdisk /dev/hdb <-- partition /deb/hdb
ddrescue -f /dev/hda1 /dev/hdb1 logfile1
ddrescue -f /dev/hda2 /dev/hdb2 logfile2
ddrescuelog -l- -b4096 logfile1 > badblocks1
ddrescuelog -l- -b4096 logfile2 > badblocks2
e2fsck -v -f -L badblocks1 /dev/hdb1
e2fsck -v -f -L badblocks2 /dev/hdb2
@end example
@sp 1
@noindent
Example 3: Rescue a whole disc with two ext2 partitions in /dev/hda to
/dev/hdb and repair the file systems using badblock lists generated with
ddrescuelog. Disc sector size is 512, file system block size is 4096.
Arguments to options @samp{-i} and @samp{-s} are the starting positions
and sizes of the partitions being rescued.@*
Note: you do not need to partition /dev/hdb beforehand, but if the
partition table on /dev/hda is damaged, you'll need to recreate it
somehow on /dev/hdb.
@example
ddrescue -f /dev/hda /dev/hdb logfile
fdisk /dev/hdb <-- get partition sizes
ddrescuelog -l- -b512 -i63b -o0 -s9767457b -b4096 logfile > badblocks1
ddrescuelog -l- -b512 -i9767520b -o0 -s128520b -b4096 logfile > badblocks2
e2fsck -v -f -L badblocks1 /dev/hdb1
e2fsck -v -f -L badblocks2 /dev/hdb2
@end example
@node Invoking ddrescuelog
@chapter Invoking ddrescuelog
@cindex invoking ddrescuelog
The format for running ddrescuelog is:
@example
ddrescuelog [@var{options}] @var{logfile}
@end example
Ddrescuelog supports the following options:
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of ddrescuelog on the standard output and exit.
@item -a @var{old_types},@var{new_types}
@itemx --change-types=@var{old_types},@var{new_types}
Change the status of every block in the rescue domain from one type in
@var{old_types} to the corresponding type in @var{new_types}, much like
the @samp{tr} command does, and write the resulting logfile to standard
output. @var{old_types} and @var{new_types} are strings of block status
characters as defined in the chapter Logfile structure (@pxref{Logfile
structure}). Blocks whose status is not in @var{old_types} are left
unchanged. If @var{new_types} is shorter than @var{old_types} the last
type of @var{new_types} is repeated as many times as necessary.
@item -b @var{bytes}
@itemx --block-size=@var{bytes}
Block size used by ddrescuelog. Depending on the requested operation it
may be the sector size of the input device, the block size of the
rescued file system, etc. Defaults to 512.
@item -c[@var{type1}@var{type2}]
@itemx --create-logfile[=@var{type1}@var{type2}]
Create a logfile from a list of block numbers read from standard input.
Only blocks included in the rescue domain will be added to @var{logfile}.
@var{type1} and @var{type2} are block status characters as defined in
the chapter Logfile structure (@pxref{Logfile structure}). @var{type1}
sets the type for blocks included in the list, while @var{type2} sets
the type for the rest of the logfile. If not specified, @var{type1}
defaults to @samp{+} and @var{type2} defaults to @samp{-}.
@item -d
@itemx --delete-if-done
Delete the given @var{logfile} if all the blocks in the rescue domain
have been successfuly recovered. The exit status is 0 if @var{logfile}
could be deleted, 1 otherwise.
@item -D
@itemx --done-status
Test if all the blocks in the rescue domain have been successfuly
recovered. The exit status is 0 if all tested blocks are finished, 1
otherwise.
@item -f
@itemx --force
Force overwrite of @var{logfile}.
@item -i @var{bytes}
@itemx --input-position=@var{bytes}
Starting position of the rescue domain, in bytes. Defaults to 0. It
refers to a position in the original input file.
@item -l @var{types}
@itemx --list-blocks=@var{types}
Print on standard output the block numbers of the blocks specified as
any of @var{types} in @var{logfile} and included in the rescue domain.
@var{types} contains one or more of the block status characters defined
in the chapter Logfile structure (@pxref{Logfile structure}).
The list format is one block number per line in decimal, like the output
of the badblocks program, so that it can be used as input for e2fsck or
other similar filesystem repairing tool.
@item -m @var{file}
@itemx --domain-logfile=@var{file}
Restrict the rescue domain to the blocks marked as finished in the
logfile @var{file}.
@item -n
@itemx --invert-logfile
Invert the types of the blocks in @var{logfile} which are included in
the rescue domain, and write the resulting logfile to standard output.
Finished blocks (@samp{+}) are changed to bad-sector (@samp{-}), all
other types are changed to finished. @samp{--invert-logfile} is
equivalent to @samp{--change-types=?*/-+,++++-}
@item -o @var{bytes}
@itemx --output-position=@var{bytes}
Starting position in output file, in bytes. Is used by the
@samp{--list-blocks} option. Defaults to @samp{--input-position}.
@item -p @var{file}
@itemx --compare-logfile=@var{file}
Compare the types of the blocks included in the rescue domain. The exit
status is 0 if all tested blocks are the same in both files, 1
otherwise.
@item -q
@itemx --quiet
Quiet operation. Suppress all messages.
@item -s @var{bytes}
@itemx --size=@var{bytes}
Maximum size of the rescue domain, in bytes. It refers to a size in the
original input file.
@item -t
@itemx --show-status
Print a summary of @var{logfile} contents on the standard output. The
summary can be restricted to one or several parts of @var{logfile} if
the domain setting options are used.
@item -v
@itemx --verbose
Verbose mode. Further -v's (up to 4) increase the verbosity level.
@item -x @var{file}
@itemx --xor-logfile=@var{file}
Perform a logical XOR (exclusive OR) operation between the finished
blocks in @var{file} and those in @var{logfile}, and write the resulting
logfile to standard output. In other words, in the resulting logfile a
block is only shown as finished if it was finished in either of the two
input logfiles but not in both.
@item -y @var{file}
@itemx --and-logfile=@var{file}
Perform a logical AND operation between the finished blocks in
@var{file} and those in @var{logfile}, and write the resulting logfile
to standard output. In other words, in the resulting logfile a block is
only shown as finished if it was finished in both input logfiles.
@item -z @var{file}
@itemx --or-logfile=@var{file}
Perform a logical OR operation between the finished blocks in @var{file}
and those in @var{logfile}, and write the resulting logfile to standard
output. In other words, in the resulting logfile a block is shown as
finished if it was finished in either of the two input logfiles.
@end table
Exit status: 0 for a normal exit, 1 for environmental problems (file not
found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused ddrescuelog to panic.
@node Problems
@chapter Reporting Bugs
@cindex bugs
@cindex getting help
There are probably bugs in ddrescue. There are certainly errors and
omissions in this manual. If you report them, they will get fixed. If
you don't, no one will ever know about them and they will remain unfixed
for all eternity, if not longer.
If you find a bug in GNU ddrescue, please send electronic mail to
@email{bug-ddrescue@@gnu.org}. Include the version number, which you can
find by running @w{@samp{ddrescue --version}}.
@node Concept index
@unnumbered Concept index
@printindex cp
@bye
gddrescue-1.17/doc/ddrescuelog.1 0000664 0000000 0000000 00000005643 12235656145 0016557 0 ustar 00root root 0000000 0000000 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH DDRESCUELOG "1" "July 2013" "ddrescuelog 1.17" "User Commands"
.SH NAME
ddrescuelog \- tool for ddrescue logfiles
.SH SYNOPSIS
.B ddrescuelog
[\fIoptions\fR] \fIlogfile\fR
.SH DESCRIPTION
GNU ddrescuelog \- Tool for ddrescue logfiles.
Manipulates ddrescue logfiles, shows their contents, converts them to/from
other formats, compares them, and tests rescue status.
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
display this help and exit
.TP
\fB\-V\fR, \fB\-\-version\fR
output version information and exit
.TP
\fB\-a\fR, \fB\-\-change\-types=\fR,
change the block types of a logfile
.TP
\fB\-b\fR, \fB\-\-block\-size=\fR
block size in bytes [default 512]
.TP
\fB\-c\fR, \fB\-\-create\-logfile[=\fR]
create logfile from list of blocks [+\-]
.TP
\fB\-d\fR, \fB\-\-delete\-if\-done\fR
delete the logfile if rescue is finished
.TP
\fB\-D\fR, \fB\-\-done\-status\fR
return 0 if rescue is finished
.TP
\fB\-f\fR, \fB\-\-force\fR
overwrite existing output files
.TP
\fB\-i\fR, \fB\-\-input\-position=\fR
starting position of rescue domain [0]
.TP
\fB\-l\fR, \fB\-\-list\-blocks=\fR
print block numbers of given types (?*/\-+)
.TP
\fB\-m\fR, \fB\-\-domain\-logfile=\fR
restrict domain to finished blocks in file
.TP
\fB\-n\fR, \fB\-\-invert\-logfile\fR
invert block types (finished <\-> others)
.TP
\fB\-o\fR, \fB\-\-output\-position=\fR
starting position in output file [ipos]
.TP
\fB\-p\fR, \fB\-\-compare\-logfile=\fR
compare block types in domain of both files
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
\fB\-s\fR, \fB\-\-size=\fR
maximum size of rescue domain to be processed
.TP
\fB\-t\fR, \fB\-\-show\-status\fR
show a summary of logfile contents
.TP
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-x\fR, \fB\-\-xor\-logfile=\fR
XOR the finished blocks in file with logfile
.TP
\fB\-y\fR, \fB\-\-and\-logfile=\fR
AND the finished blocks in file with logfile
.TP
\fB\-z\fR, \fB\-\-or\-logfile=\fR
OR the finished blocks in file with logfile
.PP
Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,
Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
.PP
Exit status: 0 for a normal exit, 1 for environmental problems (file
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused ddrescuelog to panic.
.SH "REPORTING BUGS"
Report bugs to bug\-ddrescue@gnu.org
.br
Ddrescue home page: http://www.gnu.org/software/ddrescue/ddrescue.html
.br
General help using GNU software: http://www.gnu.org/gethelp
.SH COPYRIGHT
Copyright \(co 2013 Antonio Diaz Diaz.
License GPLv3+: GNU GPL version 3 or later
.br
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gddrescue-1.17/fillbook.cc 0000664 0000000 0000000 00000010365 12235656145 0015535 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include "block.h"
#include "ddrescue.h"
// Return values: 1 write error, 0 OK, -1 interrupted, -2 logfile error.
//
int Fillbook::fill_areas( const std::string & filltypes )
{
bool first_post = true;
for( int index = 0; index < sblocks(); ++index )
{
const Sblock & sb = sblock( index );
if( !domain().includes( sb ) ) { if( domain() < sb ) break; else continue; }
if( sb.end() <= current_pos() ||
filltypes.find( sb.status() ) >= filltypes.size() ) continue;
Block b( sb.pos(), softbs() ); // fill the area a softbs at a time
if( sb.includes( current_pos() ) ) b.pos( current_pos() );
if( b.end() > sb.end() ) b.crop( sb );
current_status( filling );
while( b.size() > 0 )
{
current_pos( b.pos() );
if( verbosity >= 0 )
{ show_status( b.pos(), first_post ); first_post = false; }
if( interrupted() ) return -1;
const int retval = fill_block( b );
if( retval ) // write error
{
if( !ignore_write_errors_ ) return retval;
if( b.size() > hardbs() ) // fill the area a hardbs at a time
{ b.size( hardbs() ); continue; }
}
if( !update_logfile( odes_ ) ) return -2;
b.pos( b.end() );
if( b.end() > sb.end() ) b.crop( sb );
}
++filled_areas; --remaining_areas;
}
return 0;
}
// Return values: 1 write error, 0 OK.
//
int Fillbook::do_fill( const int odes, const std::string & filltypes )
{
filled_size = 0, remaining_size = 0;
filled_areas = 0, remaining_areas = 0;
odes_ = odes;
if( current_status() != filling || !domain().includes( current_pos() ) )
current_pos( 0 );
for( int i = 0; i < sblocks(); ++i )
{
const Sblock & sb = sblock( i );
if( !domain().includes( sb ) ) { if( domain() < sb ) break; else continue; }
if( filltypes.find( sb.status() ) >= filltypes.size() ) continue;
if( sb.end() <= current_pos() ) { ++filled_areas; filled_size += sb.size(); }
else if( sb.includes( current_pos() ) )
{
filled_size += current_pos() - sb.pos();
++remaining_areas; remaining_size += sb.end() - current_pos();
}
else { ++remaining_areas; remaining_size += sb.size(); }
}
set_signals();
if( verbosity >= 0 )
{
std::printf( "Press Ctrl-C to interrupt\n" );
if( logfile_exists() )
{
std::printf( "Initial status (read from logfile)\n" );
std::printf( "filled size: %10sB,", format_num( filled_size ) );
std::printf( " filled areas: %7u\n", filled_areas );
std::printf( "remaining size: %10sB,", format_num( remaining_size ) );
std::printf( " remaining areas: %7u\n", remaining_areas );
std::printf( "Current status\n" );
}
}
int retval = fill_areas( filltypes );
if( verbosity >= 0 )
{
show_status( -1, true );
if( retval == 0 ) std::printf( "Finished" );
else if( retval == -2 ) std::printf( "\nLogfile error" );
else if( retval < 0 ) std::printf( "\nInterrupted by user" );
std::fputc( '\n', stdout );
}
if( retval == -2 ) retval = 1; // logfile error
else
{
if( retval == 0 ) current_status( finished );
else if( retval < 0 ) retval = 0; // interrupted by user
compact_sblock_vector();
if( !update_logfile( odes_, true ) && retval == 0 ) retval = 1;
}
if( final_msg() ) show_error( final_msg(), final_errno() );
return retval;
}
gddrescue-1.17/genbook.cc 0000664 0000000 0000000 00000006762 12235656145 0015366 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include
#include
#include "block.h"
#include "ddrescue.h"
// Return values: 1 unexpected EOF, 0 OK, -1 interrupted, -2 logfile error.
//
int Genbook::check_all()
{
long long pos = ( ( offset() >= 0 ) ? 0 : -offset() );
if( current_status() == generating && domain().includes( current_pos() ) &&
( offset() >= 0 || current_pos() >= -offset() ) )
pos = current_pos();
bool first_post = true;
while( pos >= 0 )
{
Block b( pos, softbs() );
find_chunk( b, Sblock::non_tried );
if( b.size() <= 0 ) break;
pos = b.end();
current_status( generating );
current_pos( b.pos() );
if( verbosity >= 0 )
{ show_status( b.pos(), "Generating logfile...", first_post );
first_post = false; }
if( interrupted() ) return -1;
int copied_size = 0, error_size = 0;
check_block( b, copied_size, error_size );
if( copied_size + error_size < b.size() && // EOF
!truncate_vector( b.pos() + copied_size + error_size ) )
{
final_msg( "EOF found before end of logfile" );
return 1;
}
if( !update_logfile() ) return -2;
}
return 0;
}
// Return values: 1 write error, 0 OK.
//
int Genbook::do_generate( const int odes )
{
recsize = 0; gensize = 0;
odes_ = odes;
for( int i = 0; i < sblocks(); ++i )
{
const Sblock & sb = sblock( i );
if( !domain().includes( sb ) )
{ if( domain() < sb ) break; else continue; }
if( sb.status() == Sblock::finished ) recsize += sb.size();
if( sb.status() != Sblock::non_tried || i + 1 < sblocks() )
gensize += sb.size();
}
set_signals();
if( verbosity >= 0 )
{
std::printf( "Press Ctrl-C to interrupt\n" );
if( logfile_exists() )
{
std::printf( "Initial status (read from logfile)\n" );
std::printf( "rescued: %10sB,", format_num( recsize ) );
std::printf( " generated:%10sB\n", format_num( gensize ) );
std::printf( "Current status\n" );
}
}
int retval = check_all();
if( verbosity >= 0 )
{
show_status( -1, (retval ? 0 : "Finished"), true );
if( retval == -2 ) std::printf( "\nLogfile error" );
else if( retval < 0 ) std::printf( "\nInterrupted by user" );
std::fputc( '\n', stdout );
}
if( retval == -2 ) retval = 1; // logfile error
else
{
if( retval == 0 ) current_status( finished );
else if( retval < 0 ) retval = 0; // interrupted by user
compact_sblock_vector();
if( !update_logfile( -1, true ) && retval == 0 ) retval = 1;
}
if( final_msg() ) show_error( final_msg(), final_errno() );
return retval;
}
gddrescue-1.17/io.cc 0000664 0000000 0000000 00000025427 12235656145 0014350 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "block.h"
#include "ddrescue.h"
namespace {
bool volatile interrupted_ = false; // user pressed Ctrl-C
extern "C" void sighandler( int ) { interrupted_ = true; }
bool block_is_zero( const uint8_t * const buf, const int size )
{
for( int i = 0; i < size; ++i ) if( buf[i] != 0 ) return false;
return true;
}
// Returns the number of bytes really read.
// If (returned value < size) and (errno == 0), means EOF was reached.
//
int readblock( const int fd, uint8_t * const buf, const int size,
const long long pos )
{
int rest = size;
errno = 0;
if( lseek( fd, pos, SEEK_SET ) >= 0 )
while( rest > 0 )
{
errno = 0;
const int n = read( fd, buf + size - rest, rest );
if( n > 0 ) rest -= n;
else if( n == 0 ) break; // EOF
else if( errno != EINTR && errno != EAGAIN ) break;
}
return size - rest;
}
// Returns the number of bytes really written.
// If (returned value < size), it is always an error.
//
int writeblock( const int fd, const uint8_t * const buf, const int size,
const long long pos )
{
int rest = size;
errno = 0;
if( lseek( fd, pos, SEEK_SET ) >= 0 )
while( rest > 0 )
{
errno = 0;
const int n = write( fd, buf + size - rest, rest );
if( n > 0 ) rest -= n;
else if( n < 0 && errno != EINTR && errno != EAGAIN ) break;
}
return size - rest;
}
} // end namespace
// Return values: 1 write error, 0 OK.
//
int Fillbook::fill_block( const Block & b )
{
if( b.size() <= 0 ) internal_error( "bad size filling a Block" );
const int size = b.size();
if( writeblock( odes_, iobuf(), size, b.pos() + offset() ) != size ||
( synchronous_ && fsync( odes_ ) < 0 && errno != EINVAL ) )
{
if( !ignore_write_errors_ )
{ final_msg( "write error" ); final_errno( errno ); }
return 1;
}
filled_size += size; remaining_size -= size;
return 0;
}
void Fillbook::show_status( const long long ipos, bool force )
{
const char * const up = "\x1b[A";
if( t0 == 0 )
{
t0 = t1 = std::time( 0 );
first_size = last_size = filled_size;
force = true;
std::printf( "\n\n\n" );
}
if( ipos >= 0 ) last_ipos = ipos;
const long t2 = std::time( 0 );
if( t2 > t1 || force )
{
if( t2 > t1 )
{
a_rate = ( filled_size - first_size ) / ( t2 - t0 );
c_rate = ( filled_size - last_size ) / ( t2 - t1 );
t1 = t2;
last_size = filled_size;
}
std::printf( "\r%s%s%s", up, up, up );
std::printf( "filled size: %10sB,", format_num( filled_size ) );
std::printf( " filled areas: %6u,", filled_areas );
std::printf( " current rate: %9sB/s\n", format_num( c_rate, 99999 ) );
std::printf( "remain size: %10sB,", format_num( remaining_size ) );
std::printf( " remain areas: %6u,", remaining_areas );
std::printf( " average rate: %9sB/s\n", format_num( a_rate, 99999 ) );
std::printf( "current pos: %10sB\n", format_num( last_ipos + offset() ) );
std::fflush( stdout );
}
else if( t2 < t1 ) // clock jumped back
{
t0 -= std::min( t0, t1 - t2 );
t1 = t2;
}
}
bool Fillbook::read_buffer( const int ides )
{
const int rd = readblock( ides, iobuf(), softbs(), 0 );
if( rd <= 0 ) return false;
for( int i = rd; i < softbs(); i *= 2 )
{
const int size = std::min( i, softbs() - i );
std::memcpy( iobuf() + i, iobuf(), size );
}
return true;
}
// If copied_size + error_size < b.size(), it means EOF has been reached.
//
void Genbook::check_block( const Block & b, int & copied_size, int & error_size )
{
if( b.size() <= 0 ) internal_error( "bad size checking a Block" );
copied_size = readblock( odes_, iobuf(), b.size(), b.pos() + offset() );
if( errno ) error_size = b.size() - copied_size;
for( int pos = 0; pos < copied_size; )
{
const int size = std::min( hardbs(), copied_size - pos );
if( !block_is_zero( iobuf() + pos, size ) )
{
change_chunk_status( Block( b.pos() + pos, size ), Sblock::finished );
recsize += size;
}
gensize += size;
pos += size;
}
}
void Genbook::show_status( const long long ipos, const char * const msg,
bool force )
{
const char * const up = "\x1b[A";
if( t0 == 0 )
{
t0 = t1 = std::time( 0 );
first_size = last_size = gensize;
force = true;
std::printf( "\n\n" );
}
if( ipos >= 0 ) last_ipos = ipos;
const long t2 = std::time( 0 );
if( t2 > t1 || force )
{
if( t2 > t1 )
{
a_rate = ( gensize - first_size ) / ( t2 - t0 );
c_rate = ( gensize - last_size ) / ( t2 - t1 );
t1 = t2;
last_size = gensize;
}
std::printf( "\r%s%s", up, up );
std::printf( "rescued: %10sB,", format_num( recsize ) );
std::printf( " generated:%10sB,", format_num( gensize ) );
std::printf( " current rate: %9sB/s\n", format_num( c_rate, 99999 ) );
std::printf( " opos: %10sB, ",
format_num( last_ipos + offset() ) );
std::printf( " average rate: %9sB/s\n", format_num( a_rate, 99999 ) );
if( msg && msg[0] )
{
const int len = std::strlen( msg ); std::printf( "\r%s", msg );
for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
oldlen = len;
}
std::fflush( stdout );
}
else if( t2 < t1 ) // clock jumped back
{
t0 -= std::min( t0, t1 - t2 );
t1 = t2;
}
}
bool Rescuebook::extend_outfile_size()
{
if( min_outfile_size > 0 || sparse_size > 0 )
{
const long long min_size = std::max( min_outfile_size, sparse_size );
const long long size = lseek( odes_, 0, SEEK_END );
if( size < 0 ) return false;
if( min_size > size )
{
const uint8_t zero = 0;
if( writeblock( odes_, &zero, 1, min_size - 1 ) != 1 ) return false;
fsync( odes_ );
}
}
return true;
}
// Return values: 1 write error, 0 OK.
// If !OK, copied_size and error_size are set to 0.
// If OK && copied_size + error_size < b.size(), it means EOF has been reached.
//
int Rescuebook::copy_block( const Block & b, int & copied_size, int & error_size )
{
if( b.size() <= 0 ) internal_error( "bad size copying a Block" );
copied_size = readblock( ides_, iobuf(), b.size(), b.pos() );
if( errno ) error_size = b.size() - copied_size;
if( copied_size > 0 )
{
const long long pos = b.pos() + offset();
if( sparse_size >= 0 && block_is_zero( iobuf(), copied_size ) )
{
const long long end = pos + copied_size;
if( end > sparse_size ) sparse_size = end;
}
else if( writeblock( odes_, iobuf(), copied_size, pos ) != copied_size ||
( synchronous_ && fsync( odes_ ) < 0 && errno != EINVAL ) )
{
copied_size = 0; error_size = 0;
final_msg( "write error" ); final_errno( errno );
return 1;
}
}
return 0;
}
void Rescuebook::update_rates( const bool force )
{
if( t0 == 0 )
{
t0 = t1 = ts = std::time( 0 );
first_size = last_size = recsize;
rates_updated = true;
if( verbosity >= 0 ) std::printf( "\n\n\n" );
}
long t2 = std::time( 0 );
if( force && t2 <= t1 ) t2 = t1 + 1; // force update of e_code
if( t2 > t1 )
{
a_rate = ( recsize - first_size ) / ( t2 - t0 );
c_rate = ( recsize - last_size ) / ( t2 - t1 );
if( !( e_code & 4 ) )
{
if( recsize != last_size ) { last_size = recsize; ts = t2; }
else if( timeout >= 0 && t2 - ts > timeout ) e_code |= 4;
}
if( max_error_rate >= 0 && !( e_code & 1 ) )
{
error_rate /= ( t2 - t1 );
if( error_rate > max_error_rate ) e_code |= 1;
else error_rate = 0;
}
t1 = t2;
rates_updated = true;
}
else if( t2 < t1 ) // clock jumped back
{
const long delta = std::min( t0, t1 - t2 );
t0 -= delta;
ts -= delta;
t1 = t2;
}
}
void Rescuebook::show_status( const long long ipos, const char * const msg,
const bool force )
{
const char * const up = "\x1b[A";
if( ipos >= 0 ) last_ipos = ipos;
if( rates_updated || force )
{
if( verbosity >= 0 )
{
std::printf( "\r%s%s%s", up, up, up );
std::printf( "rescued: %10sB,", format_num( recsize ) );
std::printf( " errsize:%9sB,", format_num( errsize, 99999 ) );
std::printf( " current rate: %9sB/s\n", format_num( c_rate, 99999 ) );
std::printf( " ipos: %10sB, errors: %7u, ",
format_num( last_ipos ), errors );
std::printf( " average rate: %9sB/s\n", format_num( a_rate, 99999 ) );
std::printf( " opos: %10sB,", format_num( last_ipos + offset() ) );
std::printf( " time since last successful read: %9s\n",
format_time( t1 - ts ) );
if( msg && msg[0] && !errors_or_timeout() )
{
const int len = std::strlen( msg ); std::printf( "\r%s", msg );
for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout );
oldlen = len;
}
std::fflush( stdout );
}
rates_updated = false;
}
}
const char * format_time( long t )
{
static char buf[16];
int fraction = 0;
char unit = 's';
if( t >= 86400 ) { fraction = ( t % 86400 ) / 8640; t /= 86400; unit = 'd'; }
else if( t >= 3600 ) { fraction = ( t % 3600 ) / 360; t /= 3600; unit = 'h'; }
else if( t >= 60 ) { fraction = ( t % 60 ) / 6; t /= 60; unit = 'm'; }
if( fraction == 0 )
snprintf( buf, sizeof buf, "%ld %c", t, unit );
else
snprintf( buf, sizeof buf, "%ld.%d %c", t, fraction, unit );
return buf;
}
bool interrupted() { return interrupted_; }
void set_signals()
{
interrupted_ = false;
std::signal( SIGINT, sighandler );
std::signal( SIGHUP, sighandler );
std::signal( SIGTERM, sighandler );
std::signal( SIGUSR1, SIG_IGN );
std::signal( SIGUSR2, SIG_IGN );
}
gddrescue-1.17/logbook.cc 0000664 0000000 0000000 00000043562 12235656145 0015375 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "block.h"
#include "ddrescue.h"
namespace {
void input_pos_error( const long long pos, const long long isize )
{
char buf[128];
snprintf( buf, sizeof buf,
"Can't start reading at pos %lld.\n"
" Input file is only %lld bytes long.", pos, isize );
show_error( buf );
}
int my_fgetc( FILE * const f )
{
int ch;
bool comment = false;
do {
ch = std::fgetc( f );
if( ch == '#' ) comment = true;
else if( ch == '\n' || ch == EOF ) comment = false;
}
while( comment );
return ch;
}
// Read a line discarding comments, leading whitespace and blank lines.
// Returns 0 if at EOF.
//
const char * my_fgets( FILE * const f, int & linenum )
{
const int maxlen = 127;
static char buf[maxlen+1];
int ch, len = 1;
while( len == 1 ) // while line is blank
{
do { ch = my_fgetc( f ); if( ch == '\n' ) ++linenum; }
while( std::isspace( ch ) );
len = 0;
while( true )
{
if( ch == EOF ) { if( len > 0 ) ch = '\n'; else break; }
if( len < maxlen ) buf[len++] = ch;
if( ch == '\n' ) { ++linenum; break; }
ch = my_fgetc( f );
}
}
if( len > 0 ) { buf[len] = 0; return buf; }
else return 0;
}
void extend_sblock_vector( std::vector< Sblock > & sblock_vector,
const long long isize )
{
if( sblock_vector.size() == 0 )
{
Sblock sb( 0, ( isize > 0 ) ? isize : -1, Sblock::non_tried );
sb.fix_size();
sblock_vector.push_back( sb );
return;
}
Sblock & front = sblock_vector.front();
if( front.pos() > 0 )
sblock_vector.insert( sblock_vector.begin(), Sblock( 0, front.pos(), Sblock::non_tried ) );
Sblock & back = sblock_vector.back();
const long long end = back.end();
if( isize > 0 )
{
if( back.pos() >= isize )
{
if( back.pos() == isize && back.status() != Sblock::finished )
{ sblock_vector.pop_back(); return; }
show_error( "Last block in logfile begins past end of input file.\n"
" Use '-C' if you are reading from a partial copy.",
0, true );
std::exit( 1 );
}
if( end > isize )
{
if( back.status() != Sblock::finished )
{ back.size( isize - back.pos() ); return; }
show_error( "Rescued data in logfile goes past end of input file.\n"
" Use '-C' if you are reading from a partial copy.",
0, true );
std::exit( 1 );
}
else if( end < isize )
sblock_vector.push_back( Sblock( end, isize - end, Sblock::non_tried ) );
}
else if( end >= 0 )
{
Sblock sb( end, -1, Sblock::non_tried );
sb.fix_size();
if( sb.size() > 0 ) sblock_vector.push_back( sb );
}
}
void show_logfile_error( const char * const filename, const int linenum )
{
char buf[80];
snprintf( buf, sizeof buf, "error in logfile %s, line %d.", filename, linenum );
show_error( buf );
}
// Returns true if logfile exists and is readable.
//
bool read_logfile( const char * const logname,
std::vector< Sblock > & sblock_vector,
long long & current_pos, Logbook::Status & current_status )
{
FILE * const f = std::fopen( logname, "r" );
if( !f ) return false;
int linenum = 0;
sblock_vector.clear();
const char * line = my_fgets( f, linenum );
if( line ) // status line
{
char ch;
int n = std::sscanf( line, "%lli %c\n", ¤t_pos, &ch );
if( n == 2 && current_pos >= 0 && Logbook::isstatus( ch ) )
current_status = Logbook::Status( ch );
else
{
show_logfile_error( logname, linenum );
show_error( "Are you using a logfile from ddrescue 1.5 or older?" );
std::exit( 2 );
}
while( true )
{
line = my_fgets( f, linenum );
if( !line ) break;
long long pos, size;
n = std::sscanf( line, "%lli %lli %c\n", &pos, &size, &ch );
if( n == 3 && pos >= 0 && Sblock::isstatus( ch ) &&
( size > 0 || size == -1 || ( size == 0 && pos == 0 ) ) )
{
const Sblock::Status st = Sblock::Status( ch );
Sblock sb( pos, size, st ); sb.fix_size();
if( sblock_vector.size() > 0 && !sb.follows( sblock_vector.back() ) )
{ show_logfile_error( logname, linenum ); std::exit( 2 ); }
sblock_vector.push_back( sb );
}
else
{ show_logfile_error( logname, linenum ); std::exit( 2 ); }
}
}
std::fclose( f );
return true;
}
} // end namespace
Domain::Domain( const long long p, const long long s,
const char * const logname )
{
Block b( p, s ); b.fix_size();
if( !logname || !logname[0] ) { block_vector.push_back( b ); return; }
std::vector< Sblock > sblock_vector;
long long current_pos; // not used
Logbook::Status current_status; // not used
if( !read_logfile( logname, sblock_vector, current_pos, current_status ) )
{
char buf[80];
snprintf( buf, sizeof buf,
"Logfile '%s' does not exist or is not readable.", logname );
show_error( buf );
std::exit( 1 );
}
for( unsigned i = 0; i < sblock_vector.size(); ++i )
{
const Sblock & sb = sblock_vector[i];
if( sb.status() == Sblock::finished ) block_vector.push_back( sb );
}
if( block_vector.size() == 0 ) block_vector.push_back( Block( 0, 0 ) );
else this->crop( b );
}
void Logbook::split_domain_border_sblocks()
{
for( unsigned i = 0; i < sblock_vector.size(); ++i )
{
Sblock & sb = sblock_vector[i];
const long long pos = domain_.breaks_block_by( sb );
if( pos > 0 )
{
const Sblock head( sb.split( pos ) );
if( head.size() > 0 ) insert_sblock( i, head );
else internal_error( "empty block created by split_domain_border_sblocks" );
}
}
}
Logbook::Logbook( const long long offset, const long long isize,
Domain & dom, const char * const logname,
const int cluster, const int hardbs,
const bool complete_only, const bool do_not_read )
: offset_( offset ), current_pos_( 0 ), logfile_isize_( 0 ),
current_status_( copying ), domain_( dom ), filename_( logname ),
hardbs_( hardbs ), softbs_( cluster * hardbs ),
final_msg_( 0 ), final_errno_( 0 ), index_( 0 ),
ul_t1( std::time( 0 ) ), logfile_exists_( false )
{
int alignment = sysconf( _SC_PAGESIZE );
if( alignment < hardbs_ || alignment % hardbs_ ) alignment = hardbs_;
if( alignment < 2 || alignment > 65536 ) alignment = 0;
iobuf_ = iobuf_base = new uint8_t[ softbs_ + alignment ];
if( alignment > 1 ) // align iobuf for use with raw devices
{
const int disp = alignment - ( reinterpret_cast (iobuf_) % alignment );
if( disp > 0 && disp < alignment ) iobuf_ += disp;
}
if( isize > 0 )
{
if( domain_.pos() >= isize )
{ input_pos_error( domain_.pos(), isize ); std::exit( 1 ); }
domain_.crop_by_file_size( isize );
}
if( filename_ && !do_not_read )
{
logfile_exists_ =
read_logfile( filename_, sblock_vector, current_pos_, current_status_ );
if( logfile_exists_ && sblock_vector.size() )
logfile_isize_ = sblock_vector.back().end();
}
if( !complete_only ) extend_sblock_vector( sblock_vector, isize );
else if( sblock_vector.size() ) // limit domain to blocks read from logfile
{
const Block b( sblock_vector.front().pos(),
sblock_vector.back().end() - sblock_vector.front().pos() );
domain_.crop( b );
}
compact_sblock_vector();
split_domain_border_sblocks();
if( sblock_vector.size() == 0 ) domain_.clear();
}
bool Logbook::blank() const
{
for( unsigned i = 0; i < sblock_vector.size(); ++i )
if( sblock_vector[i].status() != Sblock::non_tried )
return false;
return true;
}
void Logbook::compact_sblock_vector()
{
for( unsigned i = sblock_vector.size(); i >= 2; )
{
--i;
if( sblock_vector[i-1].join( sblock_vector[i] ) )
sblock_vector.erase( sblock_vector.begin() + i );
}
}
// Writes periodically the logfile to disc.
// Returns false only if update is attempted and fails.
//
bool Logbook::update_logfile( const int odes, const bool force,
const bool retry )
{
if( !filename_ ) return true;
const int interval = 30 + std::min( 270, sblocks() / 38 ); // 30s to 5m
const long t2 = std::time( 0 );
if( !force && t2 - ul_t1 < interval ) return true;
ul_t1 = t2;
if( odes >= 0 ) fsync( odes );
errno = 0;
FILE * const f = std::fopen( filename_, "w" );
if( f )
{
write_logfile( f );
if( std::fclose( f ) == 0 ) return true;
}
if( verbosity >= 0 )
{
char buf[80];
snprintf( buf, sizeof buf, f ? "Error writing logfile '%s'." :
"Error opening logfile '%s' for writing.",
filename_ );
if( retry ) std::fprintf( stderr, "\n" );
show_error( buf, errno );
if( retry )
{
std::fprintf( stderr, "Fix the problem and press ENTER to retry, or Q+ENTER to abort. " );
std::fflush( stderr );
while( true )
{
const char c = std::tolower( std::fgetc( stdin ) );
if( c == '\r' || c == '\n' )
{
std::fprintf( stderr, "\n\n\n\n" );
return update_logfile( -1, true );
}
if( c == 'q' ) break;
}
}
}
return false;
}
void Logbook::write_logfile( FILE * const f ) const
{
write_logfile_header( f );
std::fprintf( f, "# current_pos current_status\n" );
std::fprintf( f, "0x%08llX %c\n", current_pos_, current_status_ );
std::fprintf( f, "# pos size status\n" );
for( unsigned i = 0; i < sblock_vector.size(); ++i )
{
const Sblock & sb = sblock_vector[i];
std::fprintf( f, "0x%08llX 0x%08llX %c\n", sb.pos(), sb.size(), sb.status() );
}
}
// Returns false only if truncation would remove finished blocks and
// force is false.
//
bool Logbook::truncate_vector( const long long end, const bool force )
{
int i = sblocks() - 1;
while( i >= 0 && sblock_vector[i].pos() >= end ) --i;
if( i < 0 )
{
sblock_vector.clear();
sblock_vector.push_back( Sblock( 0, 0, Sblock::non_tried ) );
}
else
{
if( !force )
for( unsigned j = i + 1; j < sblock_vector.size(); ++j )
if( sblock_vector[j].status() == Sblock::finished ) return false;
Sblock & sb = sblock_vector[i];
if( sb.includes( end ) )
{
if( !force && sb.status() == Sblock::finished ) return false;
sb.size( end - sb.pos() );
}
sblock_vector.erase( sblock_vector.begin() + i + 1, sblock_vector.end() );
}
return true;
}
int Logbook::find_index( const long long pos ) const
{
if( index_ < 0 || index_ >= sblocks() ) index_ = sblocks() / 2;
while( index_ + 1 < sblocks() && pos >= sblock_vector[index_].end() )
++index_;
while( index_ > 0 && pos < sblock_vector[index_].pos() )
--index_;
if( !sblock_vector[index_].includes( pos ) ) index_ = -1;
return index_;
}
int Logbook::find_largest_sblock( const Sblock::Status st ) const
{
long long size = 0;
int index = -1;
for( int i = 0; i < sblocks(); ++i )
{
const Sblock & sb = sblock_vector[i];
if( sb.status() == st && sb.size() > size && domain_.includes( sb ) )
{ size = sb.size(); index = i; }
}
return index;
}
int Logbook::find_smallest_sblock( const Sblock::Status st ) const
{
long long size = LLONG_MAX;
int index = -1;
for( int i = 0; i < sblocks(); ++i )
{
const Sblock & sb = sblock_vector[i];
if( sb.status() == st &&
( sb.size() < size || ( sb.size() == size && index < 0 ) ) &&
domain_.includes( sb ) )
{ size = sb.size(); index = i; if( size <= hardbs_ ) break; }
}
return index;
}
// Find chunk from b.pos of size <= b.size and status st.
// if not found, puts b.size to 0.
//
void Logbook::find_chunk( Block & b, const Sblock::Status st,
const int alignment ) const
{
if( b.size() <= 0 ) return;
if( b.pos() < sblock_vector.front().pos() )
b.pos( sblock_vector.front().pos() );
if( find_index( b.pos() ) < 0 ) { b.size( 0 ); return; }
int i;
for( i = index_; i < sblocks(); ++i )
if( sblock_vector[i].status() == st &&
domain_.includes( sblock_vector[i] ) )
{ index_ = i; break; }
if( i >= sblocks() ) { b.size( 0 ); return; }
if( b.pos() < sblock_vector[index_].pos() )
b.pos( sblock_vector[index_].pos() );
b.fix_size();
if( !sblock_vector[index_].includes( b ) )
b.crop( sblock_vector[index_] );
if( b.end() != sblock_vector[index_].end() )
b.align_end( alignment ? alignment : hardbs_ );
}
// Find chunk from b.end backwards of size <= b.size and status st.
// if not found, puts b.size to 0.
//
void Logbook::rfind_chunk( Block & b, const Sblock::Status st,
const int alignment ) const
{
if( b.size() <= 0 ) return;
b.fix_size();
if( sblock_vector.back().end() < b.end() )
b.end( sblock_vector.back().end() );
find_index( b.end() - 1 );
for( ; index_ >= 0; --index_ )
if( sblock_vector[index_].status() == st &&
domain_.includes( sblock_vector[index_] ) )
break;
if( index_ < 0 ) { b.size( 0 ); return; }
if( b.end() > sblock_vector[index_].end() )
b.end( sblock_vector[index_].end() );
if( !sblock_vector[index_].includes( b ) )
b.crop( sblock_vector[index_] );
if( b.pos() != sblock_vector[index_].pos() )
b.align_pos( alignment ? alignment : hardbs_ );
}
// Returns an adjust value (-1, 0, +1) to keep "errors" updated without
// having to call count_errors every time.
// - - - --> - + - return +1
// - - + --> - + + return 0
// - + - --> - - - return -1
// - + + --> - - + return 0
// + - - --> + + - return 0
// + - + --> + + + return -1
// + + - --> + - - return 0
// + + + --> + - + return +1
//
int Logbook::change_chunk_status( const Block & b, const Sblock::Status st )
{
if( b.size() <= 0 ) return 0;
if( !domain_.includes( b ) || find_index( b.pos() ) < 0 ||
!domain_.includes( sblock_vector[index_] ) )
internal_error( "can't change status of chunk not in rescue domain" );
if( !sblock_vector[index_].includes( b ) )
internal_error( "can't change status of chunk spread over more than 1 block" );
if( sblock_vector[index_].status() == st ) return 0;
const bool old_st_good = Sblock::is_good_status( sblock_vector[index_].status() );
const bool new_st_good = Sblock::is_good_status( st );
bool bl_st_good = ( index_ <= 0 ||
!domain_.includes( sblock_vector[index_-1] ) ||
Sblock::is_good_status( sblock_vector[index_-1].status() ) );
bool br_st_good = ( index_ + 1 >= sblocks() ||
!domain_.includes( sblock_vector[index_+1] ) ||
Sblock::is_good_status( sblock_vector[index_+1].status() ) );
if( sblock_vector[index_].pos() < b.pos() )
{
if( sblock_vector[index_].end() == b.end() &&
index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st &&
domain_.includes( sblock_vector[index_+1] ) )
{
sblock_vector[index_].inc_size( -b.size() );
sblock_vector[index_+1].pos( b.pos() );
sblock_vector[index_+1].inc_size( b.size() );
return 0;
}
insert_sblock( index_, sblock_vector[index_].split( b.pos() ) );
++index_;
bl_st_good = old_st_good;
}
if( sblock_vector[index_].size() > b.size() )
{
sblock_vector[index_].pos( b.end() );
sblock_vector[index_].inc_size( -b.size() );
br_st_good = Sblock::is_good_status( sblock_vector[index_].status() );
if( index_ > 0 && sblock_vector[index_-1].status() == st &&
domain_.includes( sblock_vector[index_-1] ) )
sblock_vector[index_-1].inc_size( b.size() );
else
insert_sblock( index_, Sblock( b, st ) );
}
else
{
sblock_vector[index_].status( st );
if( index_ > 0 && sblock_vector[index_-1].status() == st &&
domain_.includes( sblock_vector[index_-1] ) )
{
sblock_vector[index_-1].inc_size( sblock_vector[index_].size() );
erase_sblock( index_ ); --index_;
}
if( index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st &&
domain_.includes( sblock_vector[index_+1] ) )
{
sblock_vector[index_].inc_size( sblock_vector[index_+1].size() );
erase_sblock( index_ + 1 );
}
}
int retval = 0;
if( new_st_good != old_st_good && bl_st_good == br_st_good )
{ if( old_st_good == bl_st_good ) retval = +1; else retval = -1; }
return retval;
}
const char * Logbook::status_name( const Logbook::Status st )
{
switch( st )
{
case copying: return "copying";
case trimming: return "trimming";
case splitting: return "splitting";
case retrying: return "retrying";
case filling: return "filling";
case generating: return "generating";
case finished: return "finished";
}
return "unknown"; // should not be reached
}
gddrescue-1.17/main.cc 0000664 0000000 0000000 00000063267 12235656145 0014671 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
Exit status: 0 for a normal exit, 1 for environmental problems
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
corrupt or invalid input file, 3 for an internal consistency error
(eg, bug) which caused ddrescue to panic.
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "arg_parser.h"
#include "rational.h"
#include "block.h"
#include "ddrescue.h"
#ifndef O_DIRECT
#define O_DIRECT 0
#endif
namespace {
const char * const Program_name = "GNU ddrescue";
const char * const program_name = "ddrescue";
const char * invocation_name = 0;
enum Mode { m_none, m_fill, m_generate };
const mode_t outmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
#ifdef O_BINARY
const int o_binary = O_BINARY;
#else
const int o_binary = 0;
#endif
void show_help( const int cluster, const int hardbs, const int skipbs )
{
std::printf( "%s - Data recovery tool.\n", Program_name );
std::printf( "Copies data from one file or block device to another,\n"
"trying hard to rescue data in case of read errors.\n"
"\nUsage: %s [options] infile outfile [logfile]\n", invocation_name );
std::printf( "You should use a logfile unless you know what you are doing.\n"
"If you reboot, check the device names before restarting ddrescue.\n"
"Do not use options '-F' or '-g' without reading the manual first.\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" -a, --min-read-rate= minimum read rate of good areas in bytes/s\n"
" -A, --try-again mark non-split, non-trimmed blocks as non-tried\n"
" -b, --sector-size= sector size of input device [default %d]\n", hardbs );
std::printf( " -B, --binary-prefixes show binary multipliers in numbers [SI]\n"
" -c, --cluster-size= sectors to copy at a time [%d]\n", cluster );
std::printf( " -C, --complete-only do not read new data beyond logfile limits\n"
" -d, --direct use direct disc access for input file\n"
" -D, --synchronous use synchronous writes for output file\n"
" -e, --max-errors=[+] maximum number of [new] error areas allowed\n"
" -E, --max-error-rate= maximum allowed rate of read errors per second\n"
" -f, --force overwrite output device or partition\n"
" -F, --fill-mode= fill given type blocks with infile data (?*/-+)\n"
" -g, --generate-mode generate approximate logfile from partial copy\n"
" -i, --input-position= starting position in input file [0]\n"
" -I, --verify-input-size verify input file size with size in logfile\n"
" -K, --skip-size= initial size to skip on read error [%sB]\n",
format_num( skipbs, 9999, -1 ) );
std::printf( " -l, --logfile-size= do not grow logfile beyond this size [1000]\n"
" -m, --domain-logfile= restrict domain to finished blocks in file\n"
" -M, --retrim mark all failed blocks as non-trimmed\n"
" -n, --no-split do not try to split or retry failed blocks\n"
" -o, --output-position= starting position in output file [ipos]\n"
" -p, --preallocate preallocate space on disc for output file\n"
" -q, --quiet suppress all messages\n"
" -r, --retries= exit after given retries (-1=infinity) [0]\n"
" -R, --reverse reverse direction of copy operations\n"
" -s, --size= maximum size of input data to be copied\n"
" -S, --sparse use sparse writes for output file\n"
" -t, --truncate truncate output file to zero size\n"
" -T, --timeout= maximum time since last successful read\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" -w, --ignore-write-errors make fill mode ignore write errors\n"
" -x, --extend-outfile= extend outfile size to be at least this long\n"
"Numbers may be followed by a multiplier: s = sectors, k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
"Time intervals have the format 1[.5][smhd] or 1/2[smhd].\n"
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
"invalid input file, 3 for an internal consistency error (eg, bug) which\n"
"caused ddrescue to panic.\n"
"\nReport bugs to bug-ddrescue@gnu.org\n"
"Ddrescue home page: http://www.gnu.org/software/ddrescue/ddrescue.html\n"
"General help using GNU software: http://www.gnu.org/gethelp\n" );
}
// Recognized formats: [unit]
// Where the optional "unit" is one of 's', 'm', 'h' or 'd'.
// Returns the number of seconds, or exits with 1 status if error.
//
long parse_time_interval( const char * const s )
{
Rational r;
int c = r.parse( s );
if( c > 0 )
{
switch( s[c] )
{
case 'd': r *= 86400; break; // 24 * 60 * 60
case 'h': r *= 3600; break; // 60 * 60
case 'm': r *= 60; break;
case 's':
case 0 : break;
default : show_error( "Bad unit in time interval", 0, true );
std::exit( 1 );
}
const long interval = r.round();
if( !r.error() && interval >= 0 ) return interval;
}
show_error( "Bad value for time interval.", 0, true );
std::exit( 1 );
}
bool check_identical( const char * const iname, const char * const oname,
const char * const logname )
{
struct stat istat, ostat, logstat;
bool iexists = false, oexists = false, logexists = false;
bool same = ( std::strcmp( iname, oname ) == 0 );
if( !same )
{
iexists = ( stat( iname, &istat ) == 0 );
oexists = ( stat( oname, &ostat ) == 0 );
if( iexists && oexists && istat.st_ino == ostat.st_ino &&
istat.st_dev == ostat.st_dev ) same = true;
}
if( same )
{ show_error( "Infile and outfile are the same." ); return true; }
if( logname )
{
same = ( std::strcmp( iname, logname ) == 0 );
if( !same )
{
logexists = ( stat( logname, &logstat ) == 0 );
if( iexists && logexists && istat.st_ino == logstat.st_ino &&
istat.st_dev == logstat.st_dev ) same = true;
}
if( same )
{ show_error( "Infile and logfile are the same." ); return true; }
if( std::strcmp( oname, logname ) == 0 ||
( oexists && logexists && ostat.st_ino == logstat.st_ino &&
ostat.st_dev == logstat.st_dev ) )
{ show_error( "Outfile and logfile are the same." ); return true; }
}
return false;
}
bool check_files( const char * const iname, const char * const oname,
const char * const logname,
const long long min_outfile_size, const bool force,
const bool generate, const bool preallocate,
const bool sparse )
{
if( !iname || !oname )
{
show_error( "Both input and output files must be specified.", 0, true );
return false;
}
if( check_identical( iname, oname, logname ) ) return false;
if( !generate && ( min_outfile_size > 0 || !force || preallocate || sparse ) )
{
struct stat st;
if( stat( oname, &st ) == 0 && !S_ISREG( st.st_mode ) )
{
show_error( "Output file exists and is not a regular file." );
if( !force )
show_error( "Use '--force' if you really want to overwrite it, but be\n"
" aware that all existing data in the output file will be lost.",
0, true );
else if( min_outfile_size > 0 )
show_error( "Only regular files can be extended.", 0, true );
else if( preallocate )
show_error( "Only regular files can be preallocated.", 0, true );
else if( sparse )
show_error( "Only regular files can be sparse.", 0, true );
return false;
}
}
return true;
}
int do_fill( const long long offset, Domain & domain,
const char * const iname, const char * const oname,
const char * const logname,
const int cluster, const int hardbs,
const std::string & filltypes, const bool ignore_write_errors,
const bool synchronous )
{
if( !logname )
{
show_error( "Logfile required in fill mode.", 0, true );
return 1;
}
Fillbook fillbook( offset, domain, logname, cluster, hardbs,
ignore_write_errors, synchronous );
if( fillbook.domain().size() == 0 )
{ show_error( "Nothing to do." ); return 0; }
const int ides = open( iname, O_RDONLY | o_binary );
if( ides < 0 )
{ show_error( "Can't open input file", errno ); return 1; }
if( !fillbook.read_buffer( ides ) )
{ show_error( "Error reading fill data from input file." ); return 1; }
const int odes = open( oname, O_CREAT | O_WRONLY | o_binary, outmode );
if( odes < 0 )
{ show_error( "Can't open output file", errno ); return 1; }
if( lseek( odes, 0, SEEK_SET ) )
{ show_error( "Output file is not seekable." ); return 1; }
if( verbosity >= 0 )
std::printf( "\n\n%s %s\n", Program_name, PROGVERSION );
if( verbosity >= 1 )
{
std::printf( "About to fill with data from %s blocks of %s marked %s\n",
iname, oname, filltypes.c_str() );
std::printf( " Maximum size to fill: %sBytes\n",
format_num( fillbook.domain().in_size() ) );
std::printf( " Starting positions: infile = %sB",
format_num( fillbook.domain().pos() ) );
std::printf( ", outfile = %sB\n",
format_num( fillbook.domain().pos() + fillbook.offset() ) );
std::printf( " Copy block size: %3d sectors\n", cluster );
std::printf( "Sector size: %sBytes\n\n", format_num( hardbs, 99999 ) );
}
return fillbook.do_fill( odes, filltypes );
}
int do_generate( const long long offset, Domain & domain,
const char * const iname, const char * const oname,
const char * const logname,
const int cluster, const int hardbs )
{
if( !logname )
{
show_error( "Logfile must be specified in generate mode.", 0, true );
return 1;
}
const int ides = open( iname, O_RDONLY | o_binary );
if( ides < 0 )
{ show_error( "Can't open input file", errno ); return 1; }
const long long isize = lseek( ides, 0, SEEK_END );
if( isize < 0 )
{ show_error( "Input file is not seekable." ); return 1; }
Genbook genbook( offset, isize, domain, logname, cluster, hardbs );
if( genbook.domain().size() == 0 )
{ show_error( "Nothing to do." ); return 0; }
if( !genbook.blank() && genbook.current_status() != Logbook::generating )
{
show_error( "Logfile alredy exists and is non-empty.", 0, true );
return 1;
}
const int odes = open( oname, O_RDONLY | o_binary );
if( odes < 0 )
{ show_error( "Can't open output file", errno ); return 1; }
if( lseek( odes, 0, SEEK_SET ) )
{ show_error( "Output file is not seekable." ); return 1; }
if( verbosity >= 0 )
std::printf( "\n\n%s %s\n", Program_name, PROGVERSION );
if( verbosity >= 1 )
{
std::printf( "About to generate an approximate logfile for %s and %s\n",
iname, oname );
std::printf( " Starting positions: infile = %sB",
format_num( genbook.domain().pos() ) );
std::printf( ", outfile = %sB\n",
format_num( genbook.domain().pos() + genbook.offset() ) );
std::printf( " Copy block size: %3d sectors\n", cluster );
std::printf( "Sector size: %sBytes\n\n", format_num( hardbs, 99999 ) );
}
return genbook.do_generate( odes );
}
int do_rescue( const long long offset, Domain & domain,
const Rb_options & rb_opts,
const char * const iname, const char * const oname,
const char * const logname, const int cluster,
const int hardbs, const int o_direct, const int o_trunc,
const bool preallocate, const bool reverse,
const bool synchronous, const bool verify_input_size )
{
const int ides = open( iname, O_RDONLY | o_direct | o_binary );
if( ides < 0 )
{ show_error( "Can't open input file", errno ); return 1; }
const long long isize = lseek( ides, 0, SEEK_END );
if( isize < 0 )
{ show_error( "Input file is not seekable." ); return 1; }
Rescuebook rescuebook( offset, isize, domain, rb_opts, iname, logname,
cluster, hardbs, synchronous );
if( verify_input_size )
{
if( !rescuebook.logfile_exists() || isize <= 0 ||
rescuebook.logfile_isize() <= 0 ||
rescuebook.logfile_isize() >= LLONG_MAX )
{
show_error( "Can't verify input file size.\n"
" Logfile is unfinished or missing or size is invalid." );
return 1;
}
if( rescuebook.logfile_isize() != isize )
{
show_error( "Input file size differs from size calculated from logfile." );
return 1;
}
}
if( rescuebook.domain().size() == 0 )
{
if( rb_opts.complete_only )
{ show_error( "Nothing to complete; logfile is missing or empty.", 0, true );
return 1; }
show_error( "Nothing to do." ); return 0;
}
if( o_trunc && !rescuebook.blank() )
{
show_error( "Outfile truncation and logfile input are incompatible.", 0, true );
return 1;
}
const int odes = open( oname, O_CREAT | O_WRONLY | o_trunc | o_binary,
outmode );
if( odes < 0 )
{ show_error( "Can't open output file", errno ); return 1; }
if( lseek( odes, 0, SEEK_SET ) )
{ show_error( "Output file is not seekable." ); return 1; }
while( preallocate )
{
#if defined _POSIX_ADVISORY_INFO && _POSIX_ADVISORY_INFO > 0
if( posix_fallocate( odes, rescuebook.domain().pos() + rescuebook.offset(),
rescuebook.domain().size() ) == 0 ) break;
if( errno != EINTR )
{ show_error( "Can't preallocate output file", errno ); return 1; }
#else
show_error( "warning: Preallocation not available." ); break;
#endif
}
if( !rescuebook.update_logfile( -1, true ) ) return 1;
if( verbosity >= 0 )
std::printf( "\n\n%s %s\n", Program_name, PROGVERSION );
if( verbosity >= 1 )
{
std::printf( "About to copy %sBytes from %s to %s\n",
format_num( rescuebook.domain().in_size() ), iname, oname );
std::printf( " Starting positions: infile = %sB",
format_num( rescuebook.domain().pos() ) );
std::printf( ", outfile = %sB\n",
format_num( rescuebook.domain().pos() + rescuebook.offset() ) );
std::printf( " Copy block size: %3d sectors", cluster );
std::printf( " Initial skip size: %d sectors\n",
rb_opts.skipbs / hardbs );
std::printf( "Sector size: %sBytes\n", format_num( hardbs, 99999 ) );
if( verbosity >= 2 )
{
bool nl = false;
if( rb_opts.max_error_rate >= 0 )
{ nl = true; std::printf( "Max error rate: %8sB/s ",
format_num( rb_opts.max_error_rate, 99999 ) ); }
if( rb_opts.max_errors >= 0 )
{
nl = true;
std::printf( "Max %serrors: %d ",
rb_opts.new_errors_only ? "new " : "", rb_opts.max_errors );
}
if( rb_opts.max_retries >= 0 )
{ nl = true; std::printf( "Max retries: %d ", rb_opts.max_retries ); }
if( nl ) { nl = false; std::printf( "\n" ); }
if( rb_opts.min_read_rate >= 0 )
{ nl = true; std::printf( "Min read rate: %8sB/s ",
format_num( rb_opts.min_read_rate, 99999 ) ); }
if( rb_opts.timeout >= 0 )
{ nl = true; std::printf( "Max time since last successful read: %s",
format_time( rb_opts.timeout ) ); }
if( nl ) { nl = false; std::printf( "\n" ); }
std::printf( "Direct: %s ", o_direct ? "yes" : "no" );
std::printf( "Sparse: %s ", rb_opts.sparse ? "yes" : "no" );
std::printf( "Split: %s ", !rb_opts.nosplit ? "yes" : "no" );
std::printf( "Truncate: %s ", o_trunc ? "yes" : "no" );
if( rb_opts.complete_only ) std::printf( "Complete only" );
std::printf( "\n" );
if( reverse ) std::printf( "Reverse mode\n" );
}
std::printf( "\n" );
}
return rescuebook.do_rescue( ides, odes, reverse );
}
} // end namespace
#include "main_common.cc"
int main( const int argc, const char * const argv[] )
{
long long ipos = 0;
long long opos = -1;
long long max_size = -1;
const char * domain_logfile_name = 0;
const int cluster_bytes = 65536;
const int default_hardbs = 512;
const int max_hardbs = Rb_options::max_skipbs;
int cluster = 0;
int hardbs = default_hardbs;
int o_direct = 0;
int o_trunc = 0;
Mode program_mode = m_none;
struct Rb_options rb_opts;
bool force = false;
bool ignore_write_errors = false;
bool preallocate = false;
bool reverse = false;
bool synchronous = false;
bool verify_input_size = false;
std::string filltypes;
invocation_name = argv[0];
command_line = argv[0];
for( int i = 1; i < argc; ++i )
{ command_line += ' '; command_line += argv[i]; }
const Arg_parser::Option options[] =
{
{ 'a', "min-read-rate", Arg_parser::yes },
{ 'A', "try-again", Arg_parser::no },
{ 'b', "block-size", Arg_parser::yes },
{ 'b', "sector-size", Arg_parser::yes },
{ 'B', "binary-prefixes", Arg_parser::no },
{ 'c', "cluster-size", Arg_parser::yes },
{ 'C', "complete-only", Arg_parser::no },
{ 'd', "direct", Arg_parser::no },
{ 'D', "synchronous", Arg_parser::no },
{ 'e', "max-errors", Arg_parser::yes },
{ 'E', "max-error-rate", Arg_parser::yes },
{ 'f', "force", Arg_parser::no },
{ 'F', "fill-mode", Arg_parser::yes },
{ 'g', "generate-mode", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
{ 'i', "input-position", Arg_parser::yes },
{ 'I', "verify-input-size", Arg_parser::no },
{ 'K', "skip-size", Arg_parser::yes },
{ 'l', "logfile-size", Arg_parser::yes },
{ 'm', "domain-logfile", Arg_parser::yes },
{ 'M', "retrim", Arg_parser::no },
{ 'n', "no-split", Arg_parser::no },
{ 'o', "output-position", Arg_parser::yes },
{ 'p', "preallocate", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 'r', "retries", Arg_parser::yes },
{ 'r', "max-retries", Arg_parser::yes },
{ 'R', "reverse", Arg_parser::no },
{ 's', "size", Arg_parser::yes },
{ 's', "max-size", Arg_parser::yes },
{ 'S', "sparse", Arg_parser::no },
{ 't', "truncate", Arg_parser::no },
{ 'T', "timeout", Arg_parser::yes },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ 'w', "ignore-write-errors", Arg_parser::no },
{ 'x', "extend-outfile", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 1; }
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
switch( code )
{
case 'a': rb_opts.min_read_rate = getnum( arg, hardbs, 0 ); break;
case 'A': rb_opts.try_again = true; break;
case 'b': hardbs = getnum( arg, 0, 1, max_hardbs ); break;
case 'B': format_num( 0, 0, -1 ); break; // set binary prefixes
case 'c': cluster = getnum( arg, 0, 1, INT_MAX ); break;
case 'C': rb_opts.complete_only = true; break;
case 'd': o_direct = O_DIRECT;
if( !o_direct )
{ show_error( "Direct disc access not available." ); return 1; }
break;
case 'D': synchronous = true; break;
case 'e': rb_opts.new_errors_only = ( *arg == '+' );
rb_opts.max_errors = getnum( arg, 0, 0, INT_MAX ); break;
case 'E': rb_opts.max_error_rate = getnum( arg, hardbs, 0 ); break;
case 'f': force = true; break;
case 'F': set_mode( program_mode, m_fill ); filltypes = arg;
check_types( filltypes, "fill-mode" ); break;
case 'g': set_mode( program_mode, m_generate ); break;
case 'h': show_help( cluster_bytes / default_hardbs, default_hardbs,
Rb_options::default_skipbs );
return 0;
case 'i': ipos = getnum( arg, hardbs, 0 ); break;
case 'I': verify_input_size = true; break;
case 'K': rb_opts.skipbs = getnum( arg, hardbs, Rb_options::default_skipbs,
Rb_options::max_skipbs ); break;
case 'l': rb_opts.max_logfile_size = getnum( arg, 0, 1, INT_MAX ); break;
case 'm': set_name( &domain_logfile_name, arg ); break;
case 'M': rb_opts.retrim = true; break;
case 'n': rb_opts.nosplit = true; break;
case 'o': opos = getnum( arg, hardbs, 0 ); break;
case 'p': preallocate = true; break;
case 'q': verbosity = -1; break;
case 'r': rb_opts.max_retries = getnum( arg, 0, -1, INT_MAX ); break;
case 'R': reverse = true; break;
case 's': max_size = getnum( arg, hardbs, -1 ); break;
case 'S': rb_opts.sparse = true; break;
case 't': o_trunc = O_TRUNC; break;
case 'T': rb_opts.timeout = parse_time_interval( arg ); break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
case 'w': ignore_write_errors = true; break;
case 'x': rb_opts.min_outfile_size = getnum( arg, hardbs, 1 ); break;
default : internal_error( "uncaught option" );
}
} // end process options
if( opos < 0 ) opos = ipos;
if( hardbs < 1 ) hardbs = default_hardbs;
if( cluster >= INT_MAX / hardbs ) cluster = ( INT_MAX / hardbs ) - 1;
if( cluster < 1 ) cluster = cluster_bytes / hardbs;
if( cluster < 1 ) cluster = 1;
if( rb_opts.skipbs < hardbs )
rb_opts.skipbs = hardbs;
else // make multiple of hardbs
rb_opts.skipbs = round_up( rb_opts.skipbs, hardbs );
const char *iname = 0, *oname = 0, *logname = 0;
if( argind < parser.arguments() ) iname = parser.argument( argind++ ).c_str();
if( argind < parser.arguments() ) oname = parser.argument( argind++ ).c_str();
if( argind < parser.arguments() ) logname = parser.argument( argind++ ).c_str();
if( argind < parser.arguments() )
{ show_error( "Too many files.", 0, true ); return 1; }
// end scan arguments
if( !check_files( iname, oname, logname, rb_opts.min_outfile_size, force,
program_mode == m_generate, preallocate, rb_opts.sparse ) )
return 1;
Domain domain( ipos, max_size, domain_logfile_name );
switch( program_mode )
{
case m_fill:
if( rb_opts != Rb_options() || o_direct ||
verify_input_size || preallocate || reverse || o_trunc )
show_error( "warning: Options -aCdeEIMnOprRStTx are ignored in fill mode." );
return do_fill( opos - ipos, domain, iname, oname, logname, cluster,
hardbs, filltypes, ignore_write_errors, synchronous );
case m_generate:
if( rb_opts != Rb_options() || o_direct || synchronous ||
verify_input_size || preallocate || reverse || o_trunc ||
ignore_write_errors )
show_error( "warning: Options -aCdDeEIMnOprRStTwx are ignored in generate mode." );
return do_generate( opos - ipos, domain, iname, oname, logname,
cluster, hardbs );
case m_none:
if( ignore_write_errors )
{ show_error( "Option '-w' is incompatible with rescue mode.", 0, true );
return 1; }
return do_rescue( opos - ipos, domain, rb_opts, iname, oname, logname,
cluster, hardbs, o_direct, o_trunc, preallocate,
reverse, synchronous, verify_input_size );
}
}
gddrescue-1.17/main_common.cc 0000664 0000000 0000000 00000012707 12235656145 0016232 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
namespace {
const char * const program_year = "2013";
std::string command_line;
void show_version()
{
std::printf( "%s %s\n", Program_name, PROGVERSION );
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
std::printf( "License GPLv3+: GNU GPL version 3 or later \n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n" );
}
long long getnum( const char * const ptr, const int hardbs,
const long long min = LLONG_MIN + 1,
const long long max = LLONG_MAX )
{
errno = 0;
char *tail;
long long result = strtoll( ptr, &tail, 0 );
if( tail == ptr )
{
show_error( "Bad or missing numerical argument.", 0, true );
std::exit( 1 );
}
if( !errno && tail[0] )
{
int factor = ( tail[1] == 'i' ) ? 1024 : 1000;
int exponent = 0;
bool bad_multiplier = false;
switch( tail[0] )
{
case ' ': break;
case 'b':
case 's': if( hardbs > 0 ) { factor = hardbs; exponent = 1; }
else bad_multiplier = true;
break;
case 'Y': exponent = 8; break;
case 'Z': exponent = 7; break;
case 'E': exponent = 6; break;
case 'P': exponent = 5; break;
case 'T': exponent = 4; break;
case 'G': exponent = 3; break;
case 'M': exponent = 2; break;
case 'K': if( factor == 1024 ) exponent = 1; else bad_multiplier = true;
break;
case 'k': if( factor == 1000 ) exponent = 1; else bad_multiplier = true;
break;
default: bad_multiplier = true;
}
if( bad_multiplier )
{
show_error( "Bad multiplier in numerical argument.", 0, true );
std::exit( 1 );
}
for( int i = 0; i < exponent; ++i )
{
if( LLONG_MAX / factor >= llabs( result ) ) result *= factor;
else { errno = ERANGE; break; }
}
}
if( !errno && ( result < min || result > max ) ) errno = ERANGE;
if( errno )
{
show_error( "Numerical argument out of limits." );
std::exit( 1 );
}
return result;
}
void check_types( const std::string & types, const char * const opt_name )
{
bool error = false;
for( unsigned i = 0; i < types.size(); ++i )
if( !Sblock::isstatus( types[i] ) )
{ error = true; break; }
if( !types.size() || error )
{
char buf[80];
snprintf( buf, sizeof buf, "Invalid type for '%s' option.", opt_name );
show_error( buf, 0, true );
std::exit( 1 );
}
}
void set_mode( Mode & program_mode, const Mode new_mode )
{
if( program_mode != m_none && program_mode != new_mode )
{
show_error( "Only one operation can be specified.", 0, true );
std::exit( 1 );
}
program_mode = new_mode;
}
void set_name( const char ** domain_logfile_name, const char * new_name )
{
if( *domain_logfile_name )
{
show_error( "Only one domain logfile can be specified.", 0, true );
std::exit( 1 );
}
*domain_logfile_name = new_name;
}
} // end namespace
int verbosity = 0;
void show_error( const char * const msg, const int errcode, const bool help )
{
if( verbosity >= 0 )
{
if( msg && msg[0] )
{
std::fprintf( stderr, "%s: %s", program_name, msg );
if( errcode > 0 )
std::fprintf( stderr, ": %s", std::strerror( errcode ) );
std::fprintf( stderr, "\n" );
}
if( help )
std::fprintf( stderr, "Try '%s --help' for more information.\n",
invocation_name );
}
}
void internal_error( const char * const msg )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
std::exit( 3 );
}
void write_logfile_header( FILE * const f )
{
std::fprintf( f, "# Rescue Logfile. Created by %s version %s\n",
Program_name, PROGVERSION );
std::fprintf( f, "# Command line: %s\n", command_line.c_str() );
}
const char * format_num( long long num, long long limit,
const int set_prefix )
{
const char * const si_prefix[8] =
{ "k", "M", "G", "T", "P", "E", "Z", "Y" };
const char * const binary_prefix[8] =
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
static bool si = true;
static char buf[16];
if( set_prefix ) si = ( set_prefix > 0 );
const int factor = ( si ? 1000 : 1024 );
const char * const * prefix = ( si ? si_prefix : binary_prefix );
const char * p = "";
limit = std::max( 999LL, std::min( 999999LL, limit ) );
for( int i = 0; i < 8 && llabs( num ) > limit; ++i )
{ num /= factor; p = prefix[i]; }
snprintf( buf, sizeof buf, "%lld %s", num, p );
return buf;
}
gddrescue-1.17/rational.cc 0000664 0000000 0000000 00000015507 12235656145 0015550 0 ustar 00root root 0000000 0000000 /* Rational - Rational number class with overflow detection.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This library is free software: you have unlimited permission to
copy, distribute and modify it.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include
#include
#include
#include
#include
#include "rational.h"
#ifndef LLONG_MAX
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
#endif
namespace {
int gcd( int n, int m ) // Greatest Common Divisor
{
if( n < 0 ) n = -n;
if( m < 0 ) m = -m;
while( true )
{
if( m ) n %= m; else return n;
if( n ) m %= n; else return m;
}
}
long long llgcd( long long n, long long m ) // Greatest Common Divisor
{
if( n < 0 ) n = -n;
if( m < 0 ) m = -m;
while( true )
{
if( m ) n %= m; else return n;
if( n ) m %= n; else return m;
}
}
const std::string overflow_string( const int n )
{ if( n > 0 ) return "+INF"; if( n < 0 ) return "-INF"; return "NAN"; }
int overflow_value( const int n )
{ if( n > 0 ) return INT_MAX; if( n < 0 ) return -INT_MAX; return 0; }
int lloverflow_value( const long long n )
{ if( n > 0 ) return INT_MAX; if( n < 0 ) return -INT_MAX; return 0; }
} // end namespace
void Rational::normalize( long long n, long long d )
{
if( d == 0 ) { num = lloverflow_value( n ); den = 0; return; } // set error
if( n == 0 ) { num = 0; den = 1; return; }
if( d != 1 )
{
const long long tmp = llgcd( n, d );
n /= tmp; d /= tmp;
}
if( n <= INT_MAX && n >= -INT_MAX && d <= INT_MAX && d >= -INT_MAX )
{ if( d >= 0 ) { num = n; den = d; } else { num = -n; den = -d; } }
else
{ num = lloverflow_value( (d >= 0) ? n : -n ); den = 0; }
}
void Rational::normalize()
{
if( den == 0 ) return; // no op on error
if( num == 0 ) { den = 1; return; }
if( num < -INT_MAX )
{
if( den < -INT_MAX ) den = -INT_MAX;
num = overflow_value( -den ); den = 0; return;
}
if( den < 0 )
{
if( den < -INT_MAX ) { num = overflow_value( -num ); den = 0; return; }
num = -num; den = -den;
}
if( den != 1 )
{
const int tmp = gcd( num, den );
num /= tmp; den /= tmp;
}
}
Rational Rational::inverse() const
{
if( den <= 0 ) return *this; // no op on error
Rational tmp;
if( num > 0 ) { tmp.num = den; tmp.den = num; }
else if( num < 0 ) { tmp.num = -den; tmp.den = -num; }
else { tmp.num = overflow_value( den ); tmp.den = 0; } // set error
return tmp;
}
Rational & Rational::operator+=( const Rational & r )
{
if( den <= 0 ) return *this; // no op on error
if( r.den <= 0 ) { num = r.num; den = 0; return *this; } // set error
const long long new_den = (long long)den * r.den;
const long long new_num = ( (long long)num * r.den ) +
( (long long)r.num * den );
normalize( new_num, new_den );
return *this;
}
Rational & Rational::operator*=( const Rational & r )
{
if( den <= 0 ) return *this; // no op on error
if( r.den <= 0 ) { num = r.num; den = 0; return *this; } // set error
const long long new_num = (long long)num * r.num;
const long long new_den = (long long)den * r.den;
normalize( new_num, new_den );
return *this;
}
int Rational::round() const
{
if( den <= 0 ) return num;
int result = num / den;
const int rest = std::abs( num ) % den;
if( rest > 0 && rest >= den - rest )
{ if( num >= 0 ) ++result; else --result; }
return result;
}
// Recognized formats: 123 123/456 123.456 .123 12% 12/3% 12.3% .12%
// Values may be preceded by an optional '+' or '-' sign.
// Returns the number of chars read from 's', or 0 if input is invalid.
// In case of invalid input, the Rational is not changed.
//
int Rational::parse( const char * const s )
{
if( !s || !s[0] ) return 0;
long long n = 0, d = 1; // restrain intermediate overflow
int c = 0;
bool minus = false;
while( std::isspace( s[c] ) ) ++c;
if( s[c] == '+' ) ++c;
else if( s[c] == '-' ) { ++c; minus = true; }
if( !std::isdigit( s[c] ) && s[c] != '.' ) return 0;
while( std::isdigit( s[c] ) )
{
if( ( LLONG_MAX - (s[c] - '0') ) / 10 < n ) return 0;
n = (n * 10) + (s[c] - '0'); ++c;
}
if( s[c] == '.' )
{
++c; if( !std::isdigit( s[c] ) ) return 0;
while( std::isdigit( s[c] ) )
{
if( ( LLONG_MAX - (s[c] - '0') ) / 10 < n || LLONG_MAX / 10 < d )
return 0;
n = (n * 10) + (s[c] - '0'); d *= 10; ++c;
}
}
else if( s[c] == '/' )
{
++c; d = 0;
while( std::isdigit( s[c] ) )
{
if( ( LLONG_MAX - (s[c] - '0') ) / 10 < d ) return 0;
d = (d * 10) + (s[c] - '0'); ++c;
}
if( d == 0 ) return 0;
}
if( s[c] == '%' )
{
++c;
if( n % 100 == 0 ) n /= 100;
else if( n % 10 == 0 && LLONG_MAX / 10 >= d ) { n /= 10; d *= 10; }
else if( LLONG_MAX / 100 >= d ) d *= 100;
else return 0;
}
if( minus ) n = -n;
Rational tmp; tmp.normalize( n, d );
if( !tmp.error() ) { *this = tmp; return c; }
return 0;
}
// Returns a string representing the value 'num/den' in decimal point
// format with 'prec' decimals.
// 'iwidth' is the minimum width of the integer part, prefixed with
// spaces if needed.
// If 'prec' is negative, only the needed decimals are produced.
//
const std::string Rational::to_decimal( const unsigned iwidth, int prec ) const
{
if( den <= 0 ) return overflow_string( num );
std::string s;
int ipart = std::abs( num / den );
const bool truncate = ( prec < 0 );
if( prec < 0 ) prec = -prec;
do { s += '0' + ( ipart % 10 ); ipart /= 10; } while( ipart > 0 );
if( num < 0 ) s += '-';
if( iwidth > s.size() ) s.append( iwidth - s.size(), ' ' );
std::reverse( s.begin(), s.end() );
long long rest = std::abs( num ) % den;
if( prec > 0 && ( rest > 0 || !truncate ) )
{
s += '.';
while( prec > 0 && ( rest > 0 || !truncate ) )
{ rest *= 10; s += '0' + ( rest / den ); rest %= den; --prec; }
}
return s;
}
// Returns a string representing the value 'num/den' in fractional form.
// 'width' is the minimum width to be produced, prefixed with spaces if
// needed.
//
const std::string Rational::to_fraction( const unsigned width ) const
{
if( den <= 0 ) return overflow_string( num );
std::string s;
int n = std::abs( num ), d = den;
do { s += '0' + ( d % 10 ); d /= 10; } while( d > 0 );
s += '/';
do { s += '0' + ( n % 10 ); n /= 10; } while( n > 0 );
if( num < 0 ) s += '-';
if( width > s.size() ) s.append( width - s.size(), ' ' );
std::reverse( s.begin(), s.end() );
return s;
}
gddrescue-1.17/rational.h 0000664 0000000 0000000 00000014227 12235656145 0015410 0 ustar 00root root 0000000 0000000 /* Rational - Rational number class with overflow detection.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
This library is free software: you have unlimited permission to
copy, distribute and modify it.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
// Rationals are kept normalized at all times.
// Invariant = ( gcd( num, den ) == 1 && den > 0 ).
// Range extends from INT_MAX to -INT_MAX.
// Maximum resolution is 1 / INT_MAX.
// In case of domain error or overflow, den is set to 0 and num is set
// to >0, <0 or 0, meaning +INF, -INF and NAN respectively. This error
// condition can be tested with the 'error' function, and can only be
// cleared assigning a new value to the Rational.
// While in error state, arithmetic operators become no ops and
// relational operators return false, except !=, which returns true.
//
class Rational
{
int num, den;
void normalize( long long n, long long d );
void normalize();
public:
Rational( const int n, const int d ) : num( n ), den( d ) // n / d
{ normalize(); }
explicit Rational( const int n ) : num( n ), den( 1 ) // n / 1
{ if( num < -INT_MAX ) { num = -INT_MAX; den = 0; } }
Rational() : num( 0 ), den( 1 ) {} // zero
Rational & assign( const int n, const int d )
{ num = n; den = d; normalize(); return *this; }
Rational & operator=( const int n )
{ num = n; den = 1; if( num < -INT_MAX ) { num = -INT_MAX; den = 0; }
return *this; }
int numerator() const { return num; }
int denominator() const { return den; }
int sign() const
{ if( num > 0 ) return 1; if( num < 0 ) return -1; return 0; }
bool error() const { return ( den <= 0 ); } // true if in error state
const Rational & operator+() const { return *this; } // unary plus const
Rational & operator+() { return *this; } // unary plus
Rational operator-() const // unary minus
{ Rational tmp( *this ); tmp.num = -tmp.num; return tmp; }
Rational abs() const { if( num >= 0 ) return *this; else return -*this; }
Rational inverse() const;
Rational & operator+=( const Rational & r );
Rational & operator-=( const Rational & r ) { return operator+=( -r ); }
Rational & operator*=( const Rational & r );
Rational & operator/=( const Rational & r )
{ return operator*=( r.inverse() ); }
Rational & operator+=( const int n ) { return operator+=( Rational( n ) ); }
Rational & operator-=( const int n ) { return operator-=( Rational( n ) ); }
Rational & operator*=( const int n ) { return operator*=( Rational( n ) ); }
Rational & operator/=( const int n ) { return operator/=( Rational( n ) ); }
Rational operator+( const Rational & r ) const
{ Rational tmp( *this ); return tmp += r; }
Rational operator-( const Rational & r ) const
{ Rational tmp( *this ); return tmp -= r; }
Rational operator*( const Rational & r ) const
{ Rational tmp( *this ); return tmp *= r; }
Rational operator/( const Rational & r ) const
{ Rational tmp( *this ); return tmp /= r; }
Rational operator+( const int n ) const
{ Rational tmp( *this ); return tmp += n; }
Rational operator-( const int n ) const
{ Rational tmp( *this ); return tmp -= n; }
Rational operator*( const int n ) const
{ Rational tmp( *this ); return tmp *= n; }
Rational operator/( const int n ) const
{ Rational tmp( *this ); return tmp /= n; }
Rational & operator++() { return operator+=( 1 ); } // prefix
Rational operator++( int ) // suffix
{ Rational tmp( *this ); operator+=( 1 ); return tmp; }
Rational & operator--() { return operator-=( 1 ); } // prefix
Rational operator--( int ) // suffix
{ Rational tmp( *this ); operator-=( 1 ); return tmp; }
bool operator==( const Rational & r ) const
{ return ( den > 0 && num == r.num && den == r.den ); }
bool operator==( const int n ) const
{ return ( num == n && den == 1 ); }
bool operator!=( const Rational & r ) const
{ return ( den <= 0 || r.den <= 0 || num != r.num || den != r.den ); }
bool operator!=( const int n ) const
{ return ( num != n || den != 1 ); }
bool operator< ( const Rational & r ) const
{ return ( den > 0 && r.den > 0 &&
(long long)num * r.den < (long long)r.num * den ); }
bool operator<=( const Rational & r ) const
{ return ( *this < r || *this == r ); }
bool operator> ( const Rational & r ) const
{ return ( den > 0 && r.den > 0 &&
(long long)num * r.den > (long long)r.num * den ); }
bool operator>=( const Rational & r ) const
{ return ( *this > r || *this == r ); }
bool operator< ( const int n ) const { return operator< ( Rational( n ) ); }
bool operator<=( const int n ) const { return operator<=( Rational( n ) ); }
bool operator> ( const int n ) const { return operator> ( Rational( n ) ); }
bool operator>=( const int n ) const { return operator>=( Rational( n ) ); }
int round() const; // nearest integer; -1.5 ==> -2, 1.5 ==> 2
int trunc() const // integer part; -x.y ==> -x, x.y ==> x
{ if( den > 0 ) return ( num / den ); else return num; }
int parse( const char * const s ); // returns parsed size
const std::string to_decimal( const unsigned iwidth = 1, int prec = -2 ) const;
const std::string to_fraction( const unsigned width = 1 ) const;
};
inline Rational operator+( const int n, const Rational & r ) { return r + n; }
inline Rational operator-( const int n, const Rational & r ) { return -r + n; }
inline Rational operator*( const int n, const Rational & r ) { return r * n; }
inline Rational operator/( const int n, const Rational & r )
{ return Rational( n ) / r; }
inline bool operator==( const int n, const Rational & r ) { return r == n; }
inline bool operator!=( const int n, const Rational & r ) { return r != n; }
inline bool operator< ( const int n, const Rational & r ) { return r > n; }
inline bool operator<=( const int n, const Rational & r ) { return r >= n; }
inline bool operator> ( const int n, const Rational & r ) { return r < n; }
inline bool operator>=( const int n, const Rational & r ) { return r <= n; }
gddrescue-1.17/rescuebook.cc 0000664 0000000 0000000 00000055303 12235656145 0016076 0 ustar 00root root 0000000 0000000 /* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include
#include
#include "block.h"
#include "ddrescue.h"
namespace {
int calculate_max_skip_size( const long long isize,
const int hardbs, const int skipbs )
{
int skip;
if( isize > 0 && isize / 100 < Rb_options::max_skipbs ) skip = isize / 100;
else skip = Rb_options::max_skipbs;
if( skip < hardbs || skip < skipbs ) skip = skipbs;
return round_up( skip, hardbs );
}
} // end namespace
void Rescuebook::count_errors()
{
bool good = true;
errors = 0;
for( int i = 0; i < sblocks(); ++i )
{
const Sblock & sb = sblock( i );
if( !domain().includes( sb ) )
{ if( domain() < sb ) break; else { good = true; continue; } }
switch( sb.status() )
{
case Sblock::non_tried:
case Sblock::finished: good = true; break;
case Sblock::non_trimmed:
case Sblock::non_split:
case Sblock::bad_sector: if( good ) { good = false; ++errors; } break;
}
}
}
// Return values: 1 I/O error, 0 OK, -1 interrupted.
//
int Rescuebook::copy_and_update( const Block & b, const Sblock::Status st,
int & copied_size, int & error_size,
const char * const msg, bool & first_post,
const bool forward )
{
current_pos( forward ? b.pos() : b.end() );
show_status( current_pos(), msg, first_post );
first_post = false;
if( errors_or_timeout() ) return 1;
if( interrupted() ) return -1;
int retval = copy_block( b, copied_size, error_size );
if( !retval )
{
if( copied_size + error_size < b.size() ) // EOF
{
if( complete_only ) truncate_domain( b.pos() + copied_size + error_size );
else if( !truncate_vector( b.pos() + copied_size + error_size ) )
{
final_msg( "EOF found before end of logfile" );
retval = 1;
}
}
if( copied_size > 0 )
{
errors += change_chunk_status( Block( b.pos(), copied_size ), Sblock::finished );
recsize += copied_size;
}
if( error_size > 0 )
{
errors += change_chunk_status( Block( b.pos() + copied_size, error_size ),
( error_size > hardbs() ) ? st : Sblock::bad_sector );
if( iname_ && access( iname_, F_OK ) != 0 )
{
final_msg( "input file disappeared" ); final_errno( errno );
retval = 1;
}
}
}
return retval;
}
// Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
// Read the non-damaged part of the domain, skipping over the damaged areas.
//
int Rescuebook::copy_non_tried()
{
bool first_post = true;
for( bool first_pass = true; ; first_pass = false )
{
long long pos = 0;
int skip_size = 0; // size to skip on error
bool block_found = false;
if( first_pass && current_status() == copying &&
domain().includes( current_pos() ) )
{
Block b( current_pos(), 1 );
find_chunk( b, Sblock::non_tried );
if( b.size() > 0 ) pos = b.pos(); // resume
}
while( pos >= 0 )
{
const int alignment = ( skip_size ? hardbs() : softbs() );
Block b( pos, alignment );
find_chunk( b, Sblock::non_tried, alignment );
if( b.size() <= 0 ) break;
if( pos != b.pos() ) skip_size = 0; // reset size on block change
pos = b.end();
current_status( copying );
block_found = true;
const Sblock::Status st =
( ( b.size() > hardbs() ) ? Sblock::non_trimmed : Sblock::bad_sector );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, st, copied_size, error_size,
"Copying non-tried blocks...",
first_post, true );
if( error_size > 0 ) errsize += error_size;
else if( skip_size > 0 && copied_size > 0 )
{ skip_size -= copied_size; if( skip_size < 0 ) skip_size = 0; }
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( error_size > 0 || slow_read() )
{
if( pos >= 0 && skip_size > 0 )
{
b.assign( pos, skip_size ); b.fix_size();
find_chunk( b, Sblock::non_tried );
if( pos == b.pos() && b.size() > 0 )
{
if( error_size > 0 )
{ errors += change_chunk_status( b, Sblock::non_trimmed );
errsize += b.size(); }
pos = b.end();
}
}
if( skip_size < skipbs ) skip_size = skipbs;
else if( skip_size <= max_skip_size / 2 ) skip_size *= 2;
else skip_size = max_skip_size;
}
if( !update_logfile( odes_ ) ) return -2;
}
if( !block_found ) break;
reduce_min_read_rate();
}
return 0;
}
// Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
// Read the non-damaged part of the domain in reverse mode, skipping
// over the damaged areas.
//
int Rescuebook::rcopy_non_tried()
{
bool first_post = true;
for( bool first_pass = true; ; first_pass = false )
{
long long end = LLONG_MAX;
int skip_size = 0; // size to skip on error
bool block_found = false;
if( first_pass && current_status() == copying &&
domain().includes( current_pos() - 1 ) )
{
Block b( current_pos() - 1, 1 );
rfind_chunk( b, Sblock::non_tried );
if( b.size() > 0 ) end = b.end(); // resume
}
while( end > 0 )
{
const int alignment = ( skip_size ? hardbs() : softbs() );
long long pos = end - alignment;
if( pos < 0 ) pos = 0;
Block b( pos, end - pos );
rfind_chunk( b, Sblock::non_tried, alignment );
if( b.size() <= 0 ) break;
if( pos != b.pos() ) skip_size = 0; // reset size on block change
end = b.pos();
current_status( copying );
block_found = true;
const Sblock::Status st =
( ( b.size() > hardbs() ) ? Sblock::non_trimmed : Sblock::bad_sector );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, st, copied_size, error_size,
"Copying non-tried blocks...",
first_post, false );
if( error_size > 0 ) errsize += error_size;
else if( skip_size > 0 && copied_size > 0 )
{ skip_size -= copied_size; if( skip_size < 0 ) skip_size = 0; }
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( error_size > 0 || slow_read() )
{
if( end > 0 && skip_size > 0 )
{
b.size( skip_size ); b.end( end ); pos = b.pos();
rfind_chunk( b, Sblock::non_tried );
if( pos == b.pos() && b.size() > 0 )
{
if( error_size > 0 )
{ errors += change_chunk_status( b, Sblock::non_trimmed );
errsize += b.size(); }
end = b.pos();
}
}
if( skip_size < skipbs ) skip_size = skipbs;
else if( skip_size <= max_skip_size / 2 ) skip_size *= 2;
else skip_size = max_skip_size;
}
if( !update_logfile( odes_ ) ) return -2;
}
if( !block_found ) break;
reduce_min_read_rate();
}
return 0;
}
// Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
// Trim the damaged areas (largest first) from both edges.
//
int Rescuebook::trim_errors()
{
const char * const msg = "Trimming failed blocks...";
bool first_post = true;
while( true )
{
const int index = find_largest_sblock( Sblock::non_trimmed );
if( index < 0 ) break; // no more blocks
const Block block = sblock( index );
long long pos = block.pos();
while( pos >= 0 )
{
Block b( pos, hardbs() );
find_chunk( b, Sblock::non_trimmed );
if( pos != b.pos() || b.size() <= 0 ) break; // block change
pos = b.end();
current_status( trimming );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) { error_rate += error_size; pos = -1; }
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
long long end = block.end();
while( end > 0 )
{
pos = end - hardbs();
if( pos < 0 ) pos = 0;
Block b( pos, end - pos );
rfind_chunk( b, Sblock::non_trimmed );
if( pos != b.pos() || b.size() <= 0 ) break; // block change
end = b.pos();
current_status( trimming );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, false );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
if( error_size > 0 && end > 0 )
{
const int index = find_index( end - 1 );
if( index >= 0 && domain().includes( sblock( index ) ) &&
sblock( index ).status() == Sblock::non_trimmed )
errors += change_chunk_status( sblock( index ), Sblock::non_split );
end = -1;
}
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
}
return 0;
}
// Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
// Split the damaged areas (largest first).
// Then read the remaining small areas sequentially.
//
int Rescuebook::split_errors( const bool reverse )
{
const char * const msg = "Splitting failed blocks...";
bool first_post = true;
while( true )
{
if( sblocks() < max_logfile_size ) // split largest block
{
const int index = find_largest_sblock( Sblock::non_split );
if( index < 0 ) break; // no more blocks
const Block block = sblock( index );
if( block.size() / hardbs() < 5 ) break; // no more large blocks
const long long midpos =
block.pos() + ( ( block.size() / ( 2 * hardbs() ) ) * hardbs() );
long long pos = midpos;
while( pos >= 0 )
{
Block b( pos, hardbs() );
find_chunk( b, Sblock::non_split );
if( pos != b.pos() || b.size() <= 0 ) break; // block change
pos = b.end();
current_status( splitting );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) { error_rate += error_size; pos = -1; }
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
long long end = midpos;
while( end > 0 )
{
pos = end - hardbs();
if( pos < 0 ) pos = 0;
Block b( pos, end - pos );
rfind_chunk( b, Sblock::non_split );
if( pos != b.pos() || b.size() <= 0 ) break; // block change
end = b.pos();
current_status( splitting );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) { error_rate += error_size; end = -1; }
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
}
else // logfile is full; read smallest block
{
const int index = find_smallest_sblock( Sblock::non_split );
if( index < 0 ) break; // no more blocks
const Block block = sblock( index );
long long pos = block.pos();
while( pos >= 0 )
{
Block b( pos, hardbs() );
find_chunk( b, Sblock::non_split );
if( pos != b.pos() || b.size() <= 0 ) break; // block change
pos = b.end();
current_status( splitting );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
}
}
if( !reverse ) // read the remaining small areas forwards
{
long long pos = 0;
while( pos >= 0 )
{
Block b( pos, hardbs() );
find_chunk( b, Sblock::non_split );
if( b.size() <= 0 ) break; // no more blocks
pos = b.end();
current_status( splitting );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
}
else // read the remaining small areas backwards
{
long long end = LLONG_MAX;
while( end > 0 )
{
long long pos = end - hardbs();
if( pos < 0 ) pos = 0;
Block b( pos, end - pos );
rfind_chunk( b, Sblock::non_split );
if( b.size() <= 0 ) break; // no more blocks
end = b.pos();
current_status( splitting );
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msg, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
}
return 0;
}
// Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
// Try to read the damaged areas, one sector at a time.
//
int Rescuebook::copy_errors()
{
char msgbuf[80] = "Retrying bad sectors... Retry ";
const int msglen = std::strlen( msgbuf );
for( int retry = 1; max_retries < 0 || retry <= max_retries; ++retry )
{
long long pos = 0;
bool first_post = true, block_found = false;
snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%d", retry );
if( retry == 1 && current_status() == retrying &&
domain().includes( current_pos() ) )
{
Block b( current_pos(), 1 );
find_chunk( b, Sblock::bad_sector );
if( b.size() > 0 ) pos = b.pos(); // resume
}
while( pos >= 0 )
{
Block b( pos, hardbs() );
find_chunk( b, Sblock::bad_sector );
if( b.size() <= 0 ) break;
pos = b.end();
current_status( retrying );
block_found = true;
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msgbuf, first_post, true );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
if( !block_found || retry >= INT_MAX ) break;
}
return 0;
}
// Return values: 1 I/O error, 0 OK, -1 interrupted, -2 logfile error.
// Try to read the damaged areas in reverse mode, one sector at a time.
//
int Rescuebook::rcopy_errors()
{
char msgbuf[80] = "Retrying bad sectors... Retry ";
const int msglen = std::strlen( msgbuf );
for( int retry = 1; max_retries < 0 || retry <= max_retries; ++retry )
{
long long end = LLONG_MAX;
bool first_post = true, block_found = false;
snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%d", retry );
if( retry == 1 && current_status() == retrying &&
domain().includes( current_pos() - 1 ) )
{
Block b( current_pos() - 1, 1 );
rfind_chunk( b, Sblock::bad_sector );
if( b.size() > 0 ) end = b.end(); // resume
}
while( end > 0 )
{
long long pos = end - hardbs();
if( pos < 0 ) pos = 0;
Block b( pos, end - pos );
rfind_chunk( b, Sblock::bad_sector );
if( b.size() <= 0 ) break;
end = b.pos();
current_status( retrying );
block_found = true;
int copied_size = 0, error_size = 0;
const int retval = copy_and_update( b, Sblock::bad_sector, copied_size,
error_size, msgbuf, first_post, false );
if( copied_size > 0 ) errsize -= copied_size;
if( retval ) return retval;
if( error_size > 0 ) error_rate += error_size;
update_rates();
if( !update_logfile( odes_ ) ) return -2;
}
if( !block_found || retry >= INT_MAX ) break;
}
return 0;
}
Rescuebook::Rescuebook( const long long offset, const long long isize,
Domain & dom, const Rb_options & rb_opts,
const char * const iname, const char * const logname,
const int cluster, const int hardbs,
const bool synchronous )
: Logbook( offset, isize, dom, logname, cluster, hardbs, rb_opts.complete_only ),
Rb_options( rb_opts ),
error_rate( 0 ),
sparse_size( sparse ? 0 : -1 ),
recsize( 0 ),
errsize( 0 ),
iname_( ( access( iname, F_OK ) == 0 ) ? iname : 0 ),
max_skip_size( calculate_max_skip_size( isize, hardbs, skipbs ) ),
e_code( 0 ),
synchronous_( synchronous ),
a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ),
last_ipos( 0 ), t0( 0 ), t1( 0 ), ts( 0 ), oldlen( 0 ),
rates_updated( false )
{
if( retrim )
for( int index = 0; index < sblocks(); ++index )
{
const Sblock & sb = sblock( index );
if( !domain().includes( sb ) )
{ if( domain() < sb ) break; else continue; }
if( sb.status() == Sblock::non_split ||
sb.status() == Sblock::bad_sector )
change_sblock_status( index, Sblock::non_trimmed );
}
if( try_again )
for( int index = 0; index < sblocks(); ++index )
{
const Sblock & sb = sblock( index );
if( !domain().includes( sb ) )
{ if( domain() < sb ) break; else continue; }
if( sb.status() == Sblock::non_split ||
sb.status() == Sblock::non_trimmed )
change_sblock_status( index, Sblock::non_tried );
}
count_errors();
if( new_errors_only ) max_errors += errors;
}
// Return values: 1 I/O error, 0 OK.
//
int Rescuebook::do_rescue( const int ides, const int odes, const bool reverse )
{
bool copy_pending = false, trim_pending = false, split_pending = false;
ides_ = ides; odes_ = odes;
for( int i = 0; i < sblocks(); ++i )
{
const Sblock & sb = sblock( i );
if( !domain().includes( sb ) ) { if( domain() < sb ) break; else continue; }
switch( sb.status() )
{
case Sblock::non_tried: copy_pending = trim_pending = split_pending = true;
break;
case Sblock::non_trimmed: trim_pending = true; // fall through
case Sblock::non_split: split_pending = true; // fall through
case Sblock::bad_sector: errsize += sb.size(); break;
case Sblock::finished: recsize += sb.size(); break;
}
}
set_signals();
if( verbosity >= 0 )
{
std::printf( "Press Ctrl-C to interrupt\n" );
if( logfile_exists() )
{
std::printf( "Initial status (read from logfile)\n" );
std::printf( "rescued: %10sB,", format_num( recsize ) );
std::printf( " errsize:%9sB,", format_num( errsize, 99999 ) );
std::printf( " errors: %7u\n", errors );
if( verbosity >= 2 )
{
std::printf( "current position: %10sB,", format_num( current_pos() ) );
std::printf( " current sector: %7lld\n", current_pos() / hardbs() );
if( sblocks() )
std::printf( "last block size: %10sB\n",
format_num( sblock( sblocks() - 1 ).size() ) );
std::printf( "\n" );
}
std::printf( "Current status\n" );
}
}
int retval = 0;
update_rates(); // first call
if( copy_pending && !errors_or_timeout() )
retval = ( reverse ? rcopy_non_tried() : copy_non_tried() );
if( !retval && trim_pending && !errors_or_timeout() )
retval = trim_errors();
if( !retval && split_pending && !nosplit && !errors_or_timeout() )
retval = split_errors( reverse );
if( !retval && max_retries != 0 && !errors_or_timeout() )
retval = ( reverse ? rcopy_errors() : copy_errors() );
if( !rates_updated ) update_rates( true ); // force update of e_code
show_status( -1, (retval ? 0 : "Finished"), true );
if( !retval && errors_or_timeout() ) retval = 1;
if( verbosity >= 0 )
{
if( retval == -2 ) std::printf( "\nLogfile error" );
else if( retval < 0 ) std::printf( "\nInterrupted by user" );
else
{
if( e_code & 1 )
std::printf( "\nToo high error rate reading input file (%sB/s)",
format_num( error_rate ) );
if( e_code & 2 ) std::printf( "\nToo many errors in input file" );
if( e_code & 4 ) std::printf( "\nTimeout expired" );
}
std::fputc( '\n', stdout );
}
if( retval == -2 ) retval = 1; // logfile error
else
{
if( retval == 0 ) current_status( finished );
else if( retval < 0 ) retval = 0; // interrupted by user
if( !extend_outfile_size() ) // sparse or -x option
{
show_error( "Error extending output file size." );
if( retval == 0 ) retval = 1;
}
compact_sblock_vector();
if( !update_logfile( odes_, true ) && retval == 0 ) retval = 1;
}
if( final_msg() ) show_error( final_msg(), final_errno() );
return retval;
}
gddrescue-1.17/testsuite/ 0000775 0000000 0000000 00000000000 12235656145 0015451 5 ustar 00root root 0000000 0000000 gddrescue-1.17/testsuite/check.sh 0000775 0000000 0000000 00000015777 12235656145 0017106 0 ustar 00root root 0000000 0000000 #! /bin/sh
# check script for GNU ddrescue - Data recovery tool
# Copyright (C) 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
#
# This script is free software: you have unlimited permission
# to copy, distribute and modify it.
LC_ALL=C
export LC_ALL
objdir=`pwd`
testdir=`cd "$1" ; pwd`
DDRESCUE="${objdir}"/ddrescue
DDRESCUELOG="${objdir}"/ddrescuelog
framework_failure() { echo "failure in testing framework" ; exit 1 ; }
if [ ! -x "${DDRESCUE}" ] ; then
echo "${DDRESCUE}: cannot execute"
exit 1
fi
if [ -d tmp ] ; then rm -rf tmp ; fi
mkdir tmp
cd "${objdir}"/tmp
in="${testdir}"/test.txt
in1="${testdir}"/test1.txt
in2="${testdir}"/test2.txt
logfile1="${testdir}"/logfile1
logfile2="${testdir}"/logfile2
fail=0
printf "testing ddrescue-%s..." "$2"
"${DDRESCUE}" -q ${in}
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q ${in} out logfile extra
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q ${in} ${in} logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q ${in} out ${in}
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q ${in} out out
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q -g ${in} out
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q -F- ${in} out
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q -F ${in} out logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q -F- -g ${in} out logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q -m ${logfile1} -m ${logfile1} ${in} out logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUE}" -q -w ${in} out logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
if [ -r logfile ] ; then rm logfile || framework_failure ; fi
"${DDRESCUE}" -t -pq -i15000 ${in} out logfile || fail=1
"${DDRESCUE}" -D -fnq -s15000 ${in} out logfile || fail=1
cmp ${in} out || fail=1
printf .
rm out || framework_failure
rm logfile || framework_failure
"${DDRESCUE}" -qR -i15000 ${in} out logfile || fail=1
"${DDRESCUE}" -qR -s15000 ${in} out logfile || fail=1
cmp ${in} out || fail=1
printf .
rm out || framework_failure
"${DDRESCUE}" -qF+ -o15000 ${in} out2 logfile || fail=1
"${DDRESCUE}" -qRS -i15000 -o0 out2 out || fail=1
cmp ${in} out || fail=1
printf .
printf "garbage" >> out || framework_failure
"${DDRESCUE}" -qRt -i15000 -o0 out2 out || fail=1
cmp ${in} out || fail=1
printf .
rm out || framework_failure
"${DDRESCUE}" -q -m ${logfile1} ${in} out || fail=1
cmp ${in1} out || fail=1
printf .
"${DDRESCUE}" -q -m ${logfile2} ${in} out || fail=1
cmp ${in} out || fail=1
printf .
rm out || framework_failure
"${DDRESCUE}" -qRm ${logfile2} ${in} out || fail=1
cmp ${in2} out || fail=1
printf .
"${DDRESCUE}" -qRm ${logfile1} ${in} out || fail=1
cmp ${in} out || fail=1
printf .
rm out || framework_failure
cat ${logfile1} > logfile || framework_failure
"${DDRESCUE}" -qI ${in} out logfile || fail=1
cat ${logfile2} > logfile || framework_failure
"${DDRESCUE}" -qI ${in} out logfile || fail=1
cmp ${in} out || fail=1
printf .
rm out || framework_failure
cat ${logfile1} > logfile || framework_failure
"${DDRESCUE}" -qR ${in} out logfile || fail=1
cat ${logfile2} > logfile || framework_failure
"${DDRESCUE}" -qR ${in} out logfile || fail=1
cmp ${in} out || fail=1
printf .
cat ${in1} > out || framework_failure
rm logfile || framework_failure
"${DDRESCUE}" -qg ${in} out logfile || fail=1
"${DDRESCUE}" -q ${in2} out logfile || fail=1
cmp ${in} out || fail=1
printf .
cat ${in} > copy || framework_failure
printf "garbage" >> copy || framework_failure
cat ${in2} > out || framework_failure
rm logfile || framework_failure
"${DDRESCUE}" -qt -x 35744 ${in1} copy || fail=1
"${DDRESCUE}" -qg ${in} out logfile || fail=1
"${DDRESCUE}" -qR -T1.5d copy out logfile || fail=1
cmp ${in} out || fail=1
printf .
printf "\ntesting ddrescuelog-%s..." "$2"
"${DDRESCUELOG}" -q logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUELOG}" -q -d
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUELOG}" -q -t -d logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail=1
cat out | "${DDRESCUELOG}" -b2048 -fc logfile || fail=1
"${DDRESCUELOG}" -b2048 -l+ logfile > copy || fail=1
cmp out copy || fail=1
printf .
cat out | "${DDRESCUELOG}" -b2048 -s35744 -fc?+ logfile || fail=1
"${DDRESCUELOG}" -p ${logfile2} logfile || fail=1
printf .
cat out | "${DDRESCUELOG}" -b2048 -fc?+ logfile || fail=1
"${DDRESCUELOG}" -s35744 -p ${logfile2} logfile || fail=1
printf .
"${DDRESCUELOG}" -s35745 -q -p ${logfile2} logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
cat ${logfile1} > logfile || framework_failure
"${DDRESCUELOG}" -i1024 -s2048 -d logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUELOG}" -i1024 -s1024 -d logfile || fail=1
printf .
"${DDRESCUELOG}" -i1024 -s1024 -d -q logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
cat ${logfile2} > logfile || framework_failure
"${DDRESCUELOG}" -m ${logfile1} -D logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUELOG}" -m ${logfile2} -D logfile || fail=1
printf .
"${DDRESCUELOG}" -i1024 -s2048 -d logfile
if [ $? = 0 ] ; then fail=1 ; printf - ; else printf . ; fi
"${DDRESCUELOG}" -i2048 -s2048 -d logfile || fail=1
printf .
cat ${logfile1} > logfile || framework_failure
"${DDRESCUELOG}" -b2048 -l+ logfile > out || fail=1
printf "0\n2\n4\n6\n8\n10\n12\n14\n16\n" > copy || framework_failure
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -b2048 -l?- logfile > out || fail=1
printf "1\n3\n5\n7\n9\n11\n13\n15\n17\n" > copy || framework_failure
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -b2048 -l+ -i6KiB -o0 -s16KiB logfile > out || fail=1
printf "1\n3\n5\n7\n" > copy || framework_failure
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -n ${logfile2} > logfile || framework_failure
"${DDRESCUELOG}" -b2048 -l+ logfile > out || fail=1
printf "0\n2\n4\n6\n8\n10\n12\n14\n16\n" > copy || framework_failure
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -b2048 -l?- logfile > out || fail=1
printf "1\n3\n5\n7\n9\n11\n13\n15\n17\n" > copy || framework_failure
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -b2048 -l+ -i2048 -o0 -s16KiB logfile > out || fail=1
printf "1\n3\n5\n7\n" > copy || framework_failure
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -b2048 -l+ ${logfile1} > out || fail=1
"${DDRESCUELOG}" -x ${logfile1} ${logfile1} > logfile || fail=1
"${DDRESCUELOG}" -b2048 -l- logfile > copy || fail=1
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -y ${logfile2} ${logfile1} > logfile || fail=1
"${DDRESCUELOG}" -b2048 -l- logfile > copy || fail=1
cmp out copy || fail=1
printf .
"${DDRESCUELOG}" -z ${logfile1} ${logfile2} > logfile || fail=1
"${DDRESCUELOG}" -d logfile || fail=1
printf .
echo
if [ ${fail} = 0 ] ; then
echo "tests completed successfully."
cd "${objdir}" && rm -r tmp
else
echo "tests failed."
fi
exit ${fail}
gddrescue-1.17/testsuite/logfile1 0000664 0000000 0000000 00000001131 12235656145 0017072 0 ustar 00root root 0000000 0000000 # Rescue Logfile. Created by GNU ddrescue version 1.11
# current_pos current_status
0x00000000 +
# pos size status
0x00000000 0x00000800 +
0x00000800 0x00000800 ?
0x00001000 0x00000800 +
0x00001800 0x00000800 ?
0x00002000 0x00000800 +
0x00002800 0x00000800 ?
0x00003000 0x00000800 +
0x00003800 0x00000800 ?
0x00004000 0x00000800 +
0x00004800 0x00000800 ?
0x00005000 0x00000800 +
0x00005800 0x00000800 ?
0x00006000 0x00000800 +
0x00006800 0x00000800 ?
0x00007000 0x00000800 +
0x00007800 0x00000800 ?
0x00008000 0x00000800 +
0x00008800 0x000003A0 ?
gddrescue-1.17/testsuite/logfile2 0000664 0000000 0000000 00000001131 12235656145 0017073 0 ustar 00root root 0000000 0000000 # Rescue Logfile. Created by GNU ddrescue version 1.11
# current_pos current_status
0x00000000 +
# pos size status
0x00000000 0x00000800 ?
0x00000800 0x00000800 +
0x00001000 0x00000800 ?
0x00001800 0x00000800 +
0x00002000 0x00000800 ?
0x00002800 0x00000800 +
0x00003000 0x00000800 ?
0x00003800 0x00000800 +
0x00004000 0x00000800 ?
0x00004800 0x00000800 +
0x00005000 0x00000800 ?
0x00005800 0x00000800 +
0x00006000 0x00000800 ?
0x00006800 0x00000800 +
0x00007000 0x00000800 ?
0x00007800 0x00000800 +
0x00008000 0x00000800 ?
0x00008800 0x000003A0 +
gddrescue-1.17/testsuite/test.txt 0000664 0000000 0000000 00000105640 12235656145 0017177 0 ustar 00root root 0000000 0000000
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
gddrescue-1.17/testsuite/test1.txt 0000664 0000000 0000000 00000104000 12235656145 0017245 0 ustar 00root root 0000000 0000000
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer yo work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work a This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corre modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If addit he Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate u may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange nt that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version numbe l law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `showgddrescue-1.17/testsuite/test2.txt 0000664 0000000 0000000 00000105640 12235656145 0017261 0 ustar 00root root 0000000 0000000 u this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a s a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit sponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a ional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If t the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and yo to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringeme r of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply loca c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.