pax_global_header00006660000000000000000000000064122356561450014523gustar00rootroot0000000000000052 comment=4503d76cd899bd9aa39183a863ef7a676fb94ee8 gddrescue-1.17/000077500000000000000000000000001223565614500134205ustar00rootroot00000000000000gddrescue-1.17/AUTHORS000066400000000000000000000003251223565614500144700ustar00rootroot00000000000000GNU 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/COPYING000066400000000000000000001043741223565614500144640ustar00rootroot00000000000000 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/ChangeLog000066400000000000000000000253641223565614500152040ustar00rootroot000000000000002013-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/INSTALL000066400000000000000000000033671223565614500144620ustar00rootroot00000000000000Requirements ------------ 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.in000066400000000000000000000101221223565614500154610ustar00rootroot00000000000000 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/NEWS000066400000000000000000000036331223565614500141240ustar00rootroot00000000000000Changes 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/README000066400000000000000000000073301223565614500143030ustar00rootroot00000000000000Description 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.cc000066400000000000000000000144141223565614500160600ustar00rootroot00000000000000/* 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.h000066400000000000000000000077041223565614500157260ustar00rootroot00000000000000/* 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.cc000066400000000000000000000056101223565614500150230ustar00rootroot00000000000000/* 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.h000066400000000000000000000124701223565614500146670ustar00rootroot00000000000000/* 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/configure000077500000000000000000000131471223565614500153350ustar00rootroot00000000000000#! /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.h000066400000000000000000000255721223565614500154020ustar00rootroot00000000000000/* 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.cc000066400000000000000000000563521223565614500162420ustar00rootroot00000000000000/* 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/000077500000000000000000000000001223565614500141655ustar00rootroot00000000000000gddrescue-1.17/doc/ddrescue.1000066400000000000000000000106471223565614500160550ustar00rootroot00000000000000.\" 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.info000066400000000000000000001330451223565614500166460ustar00rootroot00000000000000This 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.texinfo000066400000000000000000001315071223565614500173700ustar00rootroot00000000000000\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.1000066400000000000000000000056431223565614500165570ustar00rootroot00000000000000.\" 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.cc000066400000000000000000000103651223565614500155350ustar00rootroot00000000000000/* 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.cc000066400000000000000000000067621223565614500153660ustar00rootroot00000000000000/* 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.cc000066400000000000000000000254271223565614500143500ustar00rootroot00000000000000/* 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.cc000066400000000000000000000435621223565614500153750ustar00rootroot00000000000000/* 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.cc000066400000000000000000000632671223565614500146710ustar00rootroot00000000000000/* 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.cc000066400000000000000000000127071223565614500162320ustar00rootroot00000000000000/* 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.cc000066400000000000000000000155071223565614500155500ustar00rootroot00000000000000/* 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.h000066400000000000000000000142271223565614500154100ustar00rootroot00000000000000/* 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.cc000066400000000000000000000553031223565614500160760ustar00rootroot00000000000000/* 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/000077500000000000000000000000001223565614500154515ustar00rootroot00000000000000gddrescue-1.17/testsuite/check.sh000077500000000000000000000157771223565614500171060ustar00rootroot00000000000000#! /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/logfile1000066400000000000000000000011311223565614500170720ustar00rootroot00000000000000# 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/logfile2000066400000000000000000000011311223565614500170730ustar00rootroot00000000000000# 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.txt000066400000000000000000001056401223565614500171770ustar00rootroot00000000000000 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.txt000066400000000000000000001040001223565614500172450ustar00rootroot00000000000000 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 aThis 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 thisthe 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 Corremodified 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 addithe 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 terminateu 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 numbel 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.txt000066400000000000000000001056401223565614500172610ustar00rootroot00000000000000u 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" 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. 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 yoto 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 infringemer 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 .