pax_global_header00006660000000000000000000000064151271645450014524gustar00rootroot0000000000000052 comment=887800a75b299a4217f5e0dafdda6b4f491185d2 gddrescue-1.30/000077500000000000000000000000001512716454500134145ustar00rootroot00000000000000gddrescue-1.30/AUTHORS000066400000000000000000000003321512716454500144620ustar00rootroot00000000000000GNU ddrescue was written by Antonio Diaz Diaz. Thanks to Dave Burton for his ideas about the mapfile format, the raw devices, and more. Thanks also to the many people who have contributed useful ideas, testing, etc. gddrescue-1.30/COPYING000066400000000000000000000430761512716454500144610ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. gddrescue-1.30/ChangeLog000066400000000000000000000557161512716454500152040ustar00rootroot000000000000002026-01-01 Antonio Diaz Diaz * Version 1.30 released. * Replace pass 5 of copying with a sweeping phase after trimming. * New option '-N, --no-sweep' to disable reading of skipped areas. Reassign short name '-N' from option '--no-trim' to '--no-sweep'. * main.cc. Make '--size=output' use the size of outfile. (Suggested by Stefan Monnier). (do_rescue): Make '-x 0' extend outfile to size of infile. * main_common.cc (strtoll_): New function accepting underscores. * rescuebook.cc (fcopy_non_tried, rcopy_non_tried): Limit pass 2 to blocks adjacent to a finished block. (Delimit bad area as a whole). (trim_errors): Trim only edges adjacent to a finished block. Initial skip size now defaults to (infile_size / 32_768). Only retrim blocks adjacent to a non-tried or finished block. (update_rates): Don't force update of a_rate, c_rate, ts. (Rescuebook): Estimate remaining time from last 60 seconds. (Suggested by Stefan Monnier). * genbook.cc (format_time), loggers.cc (format_time_dhms): Add years. * loggers.cc (Event_logger): Add finished_size, a_rate, read errors. * ddrescuelog.cc: New option '-H, --make-test'. * ddrescue.texi: Document rescue with lziprecover's recovery record. 2025-03-21 Antonio Diaz Diaz * Version 1.29.1 released. * New option '--bad-sector-data'. (Suggested by Eliyahu Saks). * main_common.cc (format_num3): New function. * mapbook.cc (input_pos_error): Print pos and size aligned. * ddrescue.texi: Document use of -p and -x with --domain-mapfile. (Reported by Bret Quigley II). * block.h: Rename to mapfile.h. 2025-01-05 Antonio Diaz Diaz * Version 1.29 released. * New option '--continue-on-errno'. * main.cc: New function 'show_final_msg' showing the value of errno. (about_to_copy): Print rescue options before asking user. * loggers.cc (Read_logger): Record errno if different from EIO. (The four changes above suggested by Christian Franke). * rescuebook.cc: Extend '-O, --reopen-on-error' to all phases. * ddrescuelog.cc (test_offset): Use llabs instead of std::abs. (Reported by Jordi Sanfeliu). * ddrescue.texi: New chapter 'Syntax of command-line arguments'. Add two examples of combined use with lziprecover. Document that '--continue-on-errno' may need '--reopen-on-error'. Document that option -b of ddrescuelog is position dependent. (Reported by Winston B. E.). * check.sh: Use 'cp' instead of 'cat'. 2024-01-22 Antonio Diaz Diaz * Version 1.28 released. * main.cc: Rename option '--verify-on-error' to '--check-on-error'. Rename option '--verify-input-size' to '--check-input-size'. Remove synonym '--exit-on-error'. * fillbook.cc (fill_areas), rescuebook.cc (do_rescue): Issue a final fsync to prevent early exit if kernel caches writes. * ddrescuelog.cc (show_status): Show mapfile names at verbosity == 0. * ddrescue.texi: Document how to create a compressed image. (Suggested by Detlef Bieritz). * configure, Makefile.in: New variable 'MAKEINFO'. 2023-01-23 Antonio Diaz Diaz * Version 1.27 released. * command_mode.cc (do_commands): Fix flush stdout after each command. (Reported by Jeffrey Bosboom). * New option '-W, --compare-before-write'. (Suggested by Kajetan Harald Hinner and Petr Slansky). * main_common.cc (show_option_error): New function showing argument and option name. * main.cc: Remove synonym '--direct'. * Use 'long long' instead of 'long' for time variables. * loggers.cc: Missing '#include '. * Fix two compiler warnings reported by Christian Franke. 2022-01-21 Antonio Diaz Diaz * Version 1.26 released. * mapfile.cc (write_mapfile): Check all calls to fprintf. (Hole in mapfile reported by Radomír Tomis). (read_mapfile): Allow unordered, overlapping blocks in loose domain. (Suggested by Gábor Katona and Shaya Potter). * Show file name in all diagnostics with a file involved. (Reported by Radomír Tomis). * rescuebook.cc (copy_block): Exit with status 1 on fatal errors. (Suggested by Marco Marques). (do_rescue): Don't run empty phases. (show_status): Scroll forward after each pass. (Based on a suggestion by David Morrison). * main_common.cc (getnum): Show option name and valid range if error. * main.cc, ddrescuelog.cc: Remove synonyms '*-logfile', '--pause'. * ddrescuelog.cc: New option '-F, --format'. (Bitmap format proposed by Florian Sedivy). (test_if_done): Don't try to delete stdin. (do_show_status): Round percentages up. * command_mode.cc, io.cc, loggers.cc: Missing '#include '. (Reported by Richard Burkert). * ddrescue.texi: Improve description of algorithm. * check.sh: Require a POSIX shell. 2020-02-21 Antonio Diaz Diaz * Version 1.25 released. * block.h: Add default constructors to classes Block and Sblock. (Reported by Rosen Penev). * check.sh: Quote all file name variables to allow names with spaces. (Reported by David Morrison). * In rescue mode, join non-finished subsectors read from mapfile. (Reported by David Burton). * mapbook.cc (update_mapfile): Exclude writing time from intervals. (Reported by David Burton). * rescuebook.cc (extend_outfile_size): Use ftruncate if it works. * Print large numbers in groups of 3 digits separated by underscores. * main.cc: Set a valid invocation_name even if argc == 0. 2019-02-24 Antonio Diaz Diaz * Version 1.24 released. * New option '--command-mode'. * Implement mapfile backup. (Suggested by Joe Kickman). * ddrescue.texi: Document final contents of bad areas in outfile. * configure: Accept appending to CXXFLAGS; 'CXXFLAGS+=OPTIONS'. 2018-02-13 Antonio Diaz Diaz * Version 1.23 released. * rescuebook.cc (trim_errors): Fix wrong status change to non-scraped. * New option '--same-file'. * ddrescuelog.cc: New option '--shift'. * fillbook.cc (fill_block): Write location data as one line. * fillbook.cc (read_buffer): Don't require a seekable infile. * ddrescue.texi: New chapter 'Output'. * check.sh: Add test 'combined rescue'. * io.cc: Add missing '#include '. 2017-02-03 Antonio Diaz Diaz * Version 1.22 released. * Replace option '-X, --exit-on-error' with '-X, --max-read-errors'. * New option '--max-slow-reads'. * New option '--delay-slow'. * New option '--reset-slow'. * New option '--log-events'. * New option '--mapfile-interval'. * New option '--pause-on-error'. (Suggested by Dmitri Kostin). * Rename option '--pause' to '--pause-on-pass'. * Rename option '--max-errors' to '--max-bad-areas'. * Rename 'errsize' to 'bad_size' and 'errors' to 'bad_areas' * Rescuebook: Show read_errors, error_rate and slow_reads. * Add 'current_pass' field to mapfile. * Add two new passes (3 and 4) to the copying phase. * main.cc (parse_cpass): Accept ranges of passes. * Option '-K, --skip-size' now accepts sizes up to 1 EiB. * Initial skip size now defaults to (infile_size / 100_000). * rescuebook.cc (copy_non_tried): Don't reduce min_read_rate, enable it only for passes 1 and 2. * rescuebook.cc (trim_errors): Don't trim bad edges. * main_common.cc (getnum): Accept 's' after other multiplier. * '--ask', '-vv' now show size along with model and serial number. * non_posix.cc: Add 'device_id' for Cygwin. (Patch written by Christian Franke ). * rescuebook.cc (do_rescue): Show full sizes in domain warning. * ddrescuelog.cc: New option '-A, --annotate-mapfile'. 2016-03-17 Antonio Diaz Diaz * Version 1.21 released. * mapbook.cc (Mapbook): Fix iobuf alignment. (Reported by Heikki Tauriainen). * Remove short option names '-1' and '-2'. * Allow only regular files for '--log-rates' and '--log-reads'. * Option '-D, --odirect' now works also in fill mode. * rescuebook.cc (copy_block): Return 1 on unaligned read error. Set e_code on any error if verify_on_error. * Option '-X, --exit-on-error' has been extended to all phases. * Assign short name '-Z' to option '--max-read-rate'. * mapbook.cc (update_mapfile): 'fsync' the mapfile every 5 minutes. * Rescuebook: Show full range of sizes from non-tried to finished. * rescuebook.cc (show_status): Show percentage rescued. * configure: Avoid warning on some shells when testing for g++. * Makefile.in: Detect the existence of install-info. 2015-09-10 Antonio Diaz Diaz * Version 1.20 released. * Rename 'logfile' to 'mapfile' everywhere. * Change short name of option '--synchronous' to '-y'. * Change long name of option '-d' to '--idirect'. * New option '-D, --odirect'. * New option '-J, --verify-on-error'. * New option '--max-read-rate'. * rescuebook.cc (copy_block): Copy arbitrary blocks with '--idirect'. * Include only bad-sector blocks in 'errsize'. * rescuebook.cc (show_status): Show the estimated remaining time. * io.cc (format_time): Show time in days, hours, minutes and seconds. * Add per sector location data to fill mode. * mapbook.cc: Add emergency save of the mapfile. * non_posix.cc: Add 'device_id' for Haiku. * mapfile.cc (read_mapfile): Read read-only mapfiles from stdin. * ddrescuelog.cc: Allow multiple mapfiles for '-t, --show-status'. * ddrescuelog.cc (create_mapfile): '-' writes mapfile to stdout. * ddrescue.texi: New chapter 'Optical media'. * ddrescue.texi: Document maximum size of the rescue domain. * configure: Rename option '--enable-linux' to '--enable-non-posix'. * Makefile.in: New targets 'install*-compress'. * ddrescue.h: Rename to mapbook.h. * logbook.cc: Rename to mapbook.cc. * logfile.cc: Rename to mapfile.cc. * linux.{h,cc}: Rename to non_posix.{h,cc}. 2014-10-03 Antonio Diaz Diaz * Version 1.19 released. * Fix a race condition at start of run with '--timeout=0'. * New option '-P, --data-preview'. * New option '-u, --unidirectional'. * New option '-X, --exit-on-error'. * New option '--ask' to ask for user confirmation. * New option '--cpass' to select passes during copying phase. * New option '--pause' to insert a pause between passes. * Remove option '-l, --logfile-size'. * Skip on the first error during the copying phase. * rescuebook.cc: Trimming done in one pass, may be run in reverse. * The splitting phase has been replaced by a scraping phase. * Change long name of option '-n' to '--no-scrape'. * rescuebook.cc: Alternate direction of passes during retrying phase. * Show ATA model and serial number with '--ask' or '-vv' on Linux. * configure: New option '--enable-linux'. * New files linux.h and linux.cc. * Change license to GPL version 2 or later. 2014-06-10 Antonio Diaz Diaz * Version 1.18.1 released. * ddrescuelog.cc (do_logic_ops): Fix 'or' and 'xor'. * New option '-H, --test-mode' to simulate read errors. * New option '-L, --loose-domain' (both ddrescue and ddrescuelog). * New option '-N, --no-trim' to disable trimming of damaged areas. * New option '-O, --reopen-on-error'. (Suggested by Paul L Daniels). * New options '-1, --log-rates' and '-2, --log-reads'. (Suggested by Alexander Sashnov and Paul L Daniels). * Extend '-K, --skip-size' with maximum and disable values. * Change long name of option '-r' to '--retry-passes'. * Change short name of option '--generate-mode' to '-G'. * Default value of option '-l, --logfile-size' increased to 10000. * If interrupted, ddrescue terminates by raising the signal received. * rescuebook.cc (copy_non_tried): Don't mark skipped blocks as non-trimmed. Try them in additional passes (before trimming). * rescuebook.cc: Limit the copying phase to 3 passes. * rescuebook.cc: Alternate direction of passes during copying phase. * rescuebook.cc: Smallest blocks are trimmed first. * rescuebook.cc (split_errors): Read largest first if logfile full. * Improve speed when using option '-m, --domain-logfile'. * io.cc (show_status): Show the current total run time. * rescuebook.cc: Show pass number and direction during copying. * rescuebook.cc (show_status): Show block pos instead of current_pos. * main.cc: Show "an unknown number of bytes" for unknown insize. * ddrescuelog.cc: New options '-B, --binary-prefixes', -C, --complete-logfile', and '-P, --compare-as-domain'. * Improve speed of logic operations in ddrescuelog. * rescuebook.cc (do_rescue): Show warning when domain is smaller than logfile. * ddrescuelog.cc (do_show_status): Show logfile and domain extents when domain is smaller than logfile. * block.h: Class Block now forces the invariant by itself. * Code reorganization. New class 'Logfile'. * Add status message to rescue logfile. * Many improvements to documentation. * ddrescue.texinfo: Rename to ddrescue.texi. 2013-07-09 Antonio Diaz Diaz * Version 1.17 released. * New option '-l, --logfile-size'. * New option '-w, --ignore-write-errors'. * Rename option '--fill' to '--fill-mode'. * Rename option '--generate-logfile' to '--generate-mode'. * Add option '--sector-size' as a synonym of '--block-size'. * Add option '--retries' as a synonym of '--max-retries'. * Add 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 insize 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: Don't require '--force' for generate mode. * ddrescue.h (Logbook::logfile_exists): Don't return false if logfile exists but is empty. * ddrescue.texinfo: New chapter 'Using ddrescue safely'. * Document that 'direct disc access' only reads whole sectors. * configure: Options now accept a separate argument. * Makefile.in: New target 'install-bin'. 2012-06-11 Antonio Diaz Diaz * Version 1.16 released. * New option '-K, --skip-size'. * New option '-T, --timeout'. * Change 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 option '-E, --max-error-rate' now checks the rate of actually failed reads, not the growth of error size. * The option '-v, --verbose' now increases verbosity if repeated. * Change quote characters in messages as advised by GNU Standards. * configure: Rename 'datadir' to 'datarootdir'. * New files rational.h, rational.cc. 2012-01-01 Antonio Diaz Diaz * Version 1.15 released. * New option '-a, --min-read-rate'. * New option '-I, --verify-input-size'. * New option '-x, --extend-outfile'. * main.cc: Check that infile, outfile, and logfile are all different. (do_fill, do_generate, do_rescue): Show PROGVERSION. * Non-tried blocks are now read aligned to cluster-size sectors. * rescuebook.cc: Improve skip algorithm for the split pass. * main.cc: Remove spurious warning about '-D' ignored in fill mode. * ddrescue.texinfo: Improve 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: Rename to io.cc. * Add 'ddrescuelog', a program for logfile manipulation. 2011-01-10 Antonio Diaz Diaz * Version 1.14 released. * New option '-R, --reverse'. * New option '-E, --max-error-rate'. * Extend syntax of '--max-errors' (+N) to specify new errors. * Change short name of option '--retrim' to '-M'. * Remove 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 longer overwritten by default. * New option '-f, --force'. * New option '-p, --preallocate'. * main.cc (write_logfile_header): Write command line to logfile. * Revert to use 'long' instead of 'time_t' for time variables. Ddrescue only needs counting seconds, and 'time_t' causes warnings on some systems. * ddrescue.texinfo: Add info about logfile and recoverable formats. Add a couple more warnings to the tutorial. * testsuite: Rename 'test1' to 'test.txt' 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: Add quotes to directory names. * Makefile.in: Add option '--name' to help2man invocation. * 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): Modify the split threshold. * rescuebook.cc (copy_and_update): Check after every read error that the input file does still exist. * ddrescue.cc (Rescuebook::show_status): Show the time elapsed since the last successful read. * ddrescue.cc (set_signals): Ignore SIGUSR1 and SIGUSR2. * ddrescue.texinfo: Improve descriptions of '-d', '-D', and '-S'. Improve description of algorithm. * check.sh: Check that files are opened in binary mode. * Add logfile usage warning to the output of 'ddrescue --help'. 2009-02-19 Antonio Diaz Diaz * Version 1.10 released. * New option '-T, --try-again'. * rescuebook.cc: 'skip_size' has been made independent of 'softbs'. * 'change_chunk_status' is now faster for large logfiles. * Fix overflow when reading from devices of undefined size. * Block does no longer 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. * New option '-m, --domain-logfile'. * Verbosity control of messages has been simplified. * Change LONG_LONG_MAX to LLONG_MAX. 2008-02-24 Antonio Diaz Diaz * Version 1.8 released. * New option '-g, --generate-logfile'. * New option '-D, --synchronous'. * Fill mode now works when outfile offset differs from 0. * ddrescue.texinfo: Update chapter 'Fill Mode'. 2008-01-04 Antonio Diaz Diaz * Version 1.7 released. * Skips faster over damaged areas (small read, big jump). * Logfile is kept minimized at all times. * Rescuebook::errors now counts the error areas found. * Makefile.in: New target 'check'. * rescuebook.cc (split_errors): New variable 'error_counter'. * 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): New variable 'skip_counter'. * Add new pass that trims error areas backwards before splitting. * Add support for sparse output files. * Blocks longer than hardbs are now split at sector boundaries. * New option '-F, --fill'. * Add 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. * Option '--quiet' now also quiets error messages. * Print a more informative error message when reading an old logfile. * Add some consistency checks. * ddrescue.texinfo: New chapter 'Fill Mode'. Add note about old logfiles. 2007-06-29 Antonio Diaz Diaz * Version 1.5 released. * Update license to GPL version 3 or later. 2007-06-18 Antonio Diaz Diaz * Version 1.4 released. * New option '-d, --direct'. * Fix a bug showing bad initial error size. * Fix error counting. * Small changes to documentation. 2006-12-13 Antonio Diaz Diaz * Version 1.3 released. * configure: Some fixes. * Makefile.in: New target 'sddrescue'. 2006-04-03 Antonio Diaz Diaz * Version 1.2 released. * New option '-C, --complete-only'. * Replace 'getopt_long' with a new argument parser. * Logfile save interval is now dependent on logfile size. * Small changes to documentation. 2005-10-10 Antonio Diaz Diaz * Version 1.1 released. * Align 'iobuf' to the sector size for use with raw devices. * Add two missing #includes. * ddrescue.texinfo: Add a small tutorial. 2005-06-07 Antonio Diaz Diaz * Version 1.0 released. * A new logfile format makes multipart rescue possible. * Logfile is saved every 30 seconds. * Logfile is now also saved in case of write error on outfile. * Fix 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. * configure, ddrescue.texinfo: New files. * Two small bugs corrected. * 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. * Rename 'badblocks file' to 'logfile'. * Save logfile also if max_errors are exceeded. 2004-12-14 Antonio Diaz Diaz * Version 0.8 released. * 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. * Skip faster over damaged areas (try 1 block first). * Improve error messages. 2004-09-15 Antonio Diaz Diaz * Version 0.5 released. * Save badblocks file also if ddrescue is interrupted while splitting damaged areas. * ddrescue.1: New man page. 2004-09-03 Antonio Diaz Diaz * Version 0.4 released. * Change project name to 'ddrescue' to meet command name standards. * Add long option names. 2004-08-18 Antonio Diaz Diaz * Version 0.3 released. * Add badblocks file, making the rescue much more efficient. 2004-08-14 Antonio Diaz Diaz * Version 0.2 released. * Fix bug that sometimes ignored the last sectors of a damaged area. * Make the algorithm faster in presence of errors. 2004-08-12 Antonio Diaz Diaz * Version 0.1 released. Copyright (C) 2004-2026 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.30/INSTALL000066400000000000000000000041241512716454500144460ustar00rootroot00000000000000Requirements ------------ You will need a C++98 compiler with support for 'long long'. (gcc 3.3.6 or newer is recommended). I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards compliant compiler. Gcc is available at http://gcc.gnu.org Lzip is available at http://www.nongnu.org/lzip/lzip.html Procedure --------- 1. Unpack the archive if you have not done so already: tar -xf ddrescue[version].tar.lz or lzip -cd ddrescue[version].tar.lz | tar -xf - This creates the directory ./ddrescue[version] containing the source code extracted from the 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 programs and any data files and documentation. You need root privileges to install into a prefix owned by root. Or type 'make install-compress', which additionally compresses the info manual and the man pages after installation. (Installing compressed docs may become the default in the future). You can install only the programs, the info manual, or the man pages by 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 variable 'VPATH', 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 source code. Usually 'configure' can determine that directory automatically. After running 'configure', you can run 'make' and 'make install' as explained above. Copyright (C) 2004-2026 Antonio Diaz Diaz. This file is free documentation: you have unlimited permission to copy, distribute, and modify it. gddrescue-1.30/Makefile.in000066400000000000000000000130461512716454500154650ustar00rootroot00000000000000 DISTNAME = $(pkgname)-$(pkgversion) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -m 755 INSTALL_DIR = $(INSTALL) -d -m 755 INSTALL_DATA = $(INSTALL) -m 644 SHELL = /bin/sh CAN_RUN_INSTALLINFO = $(SHELL) -c "install-info --version" > /dev/null 2>&1 ddobjs = mapbook.o fillbook.o genbook.o io.o rescuebook.o command_mode.o main.o logobjs = make_test.o ddrescuelog.o objs = arg_parser.o rational.o non_posix.o loggers.o block.o mapfile.o $(ddobjs) lobjs = arg_parser.o block.o mapfile.o $(logobjs) .PHONY : all install install-bin install-info install-man \ install-strip install-compress install-strip-compress \ install-bin-strip install-info-compress install-man-compress \ uninstall uninstall-bin uninstall-info uninstall-man \ doc info man check dist clean distclean all : $(progname) ddrescuelog $(progname) : $(objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(objs) ddrescuelog : $(lobjs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(lobjs) static_$(progname) : $(objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -static -o $@ $(objs) non_posix.o : non_posix.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(use_non_posix) -c -o $@ $< 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 $@ $< # prevent 'make' from trying to remake source files $(VPATH)/configure $(VPATH)/Makefile.in $(VPATH)/doc/$(pkgname).texi : ; MAKEFLAGS += -r .SUFFIXES : $(objs) : Makefile $(ddobjs) : mapfile.h mapbook.h $(logobjs) : Makefile mapfile.h ddrescuelog.h arg_parser.o : arg_parser.h block.o : mapfile.h command_mode.o : rational.h rescuebook.h ddrescuelog.o : arg_parser.h main_common.cc loggers.o : mapfile.h loggers.h main.o : arg_parser.h loggers.h non_posix.h rational.h rescuebook.h \ main_common.cc mapfile.o : mapfile.h non_posix.o : non_posix.h rational.o : rational.h rescuebook.o : loggers.h rational.h rescuebook.h doc : info man info : $(VPATH)/doc/$(pkgname).info $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texi cd $(VPATH)/doc && $(MAKEINFO) $(pkgname).texi 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 mapfiles' \ -o $@ --info-page=$(pkgname) ./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-strip : install-bin-strip install-info install-man install-compress : install-bin install-info-compress install-man-compress install-strip-compress : install-bin-strip install-info-compress install-man-compress 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-bin-strip : all $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install-bin install-info : if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi -rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"* $(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info" -if $(CAN_RUN_INSTALLINFO) ; then \ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \ fi install-info-compress : install-info lzip -v -9 "$(DESTDIR)$(infodir)/$(pkgname).info" install-man : if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi -rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"* -rm -f "$(DESTDIR)$(mandir)/man1/ddrescuelog.1"* $(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1" $(INSTALL_DATA) $(VPATH)/doc/ddrescuelog.1 "$(DESTDIR)$(mandir)/man1/ddrescuelog.1" install-man-compress : install-man lzip -v -9 "$(DESTDIR)$(mandir)/man1/$(progname).1" lzip -v -9 "$(DESTDIR)$(mandir)/man1/ddrescuelog.1" uninstall : uninstall-man uninstall-info uninstall-bin uninstall-bin : -rm -f "$(DESTDIR)$(bindir)/$(progname)" -rm -f "$(DESTDIR)$(bindir)/ddrescuelog" uninstall-info : -if $(CAN_RUN_INSTALLINFO) ; then \ install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \ fi -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 -Hustar --owner=root --group=root -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).texi \ $(DISTNAME)/*.h \ $(DISTNAME)/*.cc \ $(DISTNAME)/testsuite/check.sh \ $(DISTNAME)/testsuite/fox \ $(DISTNAME)/testsuite/mapfile[1-6]* \ $(DISTNAME)/testsuite/mapfile_blank \ $(DISTNAME)/testsuite/test.txt \ $(DISTNAME)/testsuite/test[1-5].txt rm -f $(DISTNAME) lzip -v -9 $(DISTNAME).tar clean : -rm -f $(progname) $(objs) -rm -f static_$(progname) ddrescuelog $(logobjs) distclean : clean -rm -f Makefile config.status *.tar *.tar.lz gddrescue-1.30/NEWS000066400000000000000000000060741512716454500141220ustar00rootroot00000000000000Changes in version 1.30: The changes in this version improve by orders of magnitude the automatic recovery of a drive with a dead head. For example, all the recoverable data in a 1 TB drive with one ot its 4 heads dead can now be recovered after just 283 read errors instead of the 3_782_794 read errors needed by ddrescue 1.29. (ddrescue 1.29 with the options '--cpass=1,2 --skip-size=32MiB' can recover the data after 880 read errors, but the point is that an unexperienced user can now achieve results that only an expert could achieve with the previous version of ddrescue). The pass 5 of the copying phase has been replaced by a new sweeping phase run after the trimming phase. The new option '-N, --no-sweep', which disables the reading of skipped areas, has been added. The short name '-N' has been reassigned from option '--no-trim' to option '--no-sweep'. Option '--no-trim' is no longer recommended because trimming has now a higher probability of finding good data. Pass 2 now copies only the blocks adjacent to at least one finished block. The trimming pass now trims only the edges adjacent to a finished block. The goal is to delimit the bad area as a whole. The initial skip size now defaults to 'infile_size / 32_768' instead of 'infile_size / 100_000'. '--retrim' now only marks blocks adjacent to a non-tried or finished block. '--extend-outfile=0' now extends outfile to the size of infile. In rescue mode, '--size=output' now uses the size of the output file or device, for example to overwrite it: 'ddrescue --force --size=output /dev/urandom /dev/mydisk'. (Suggested by Stefan Monnier). The remaining time is now estimated by using the average rate of the last 60 seconds instead of the last 30 seconds. (Suggested by Stefan Monnier). A line showing 'average rate' and 'read errors' has been added to the file generated by the event logger. Large numbers in option arguments are now accepted with underscore separators (-s 123_456_789). The option '-H, --make-test', which creates a mapfile for the test mode of ddrescue based on the disc geometry given, has been added to ddrescuelog. This option has helped in the development of some of the improvements in this version of ddrescue, and is a work in progress. The geometries implemented so far are some of those described in the following article: H. Wong, "Discovering Hard Disk Physical Geometry through Microbenchmarking", Sept., 2019. Available online at An example of recovery of a tar.lz backup using a lziprecover-generated FEC recovery record appended to the backup itself has been added to the manual. (Lziprecover's FEC algorithm can repair any kind of file, but its ability to repair lzip files is greater than for other kinds of files. Lziprecover can use the statistical properties of lzip data to repair a lzip file rescued with ddrescue, even if the fec file is so damaged that it has lost both CRC arrays). (It would be good that lzip were more widely used inside GNU, given its advantages over gzip for the compression of source tarballs and backups). gddrescue-1.30/README000066400000000000000000000117651512716454500143060ustar00rootroot00000000000000See the file INSTALL for compilation and installation instructions. Description GNU ddrescue is a data recovery tool. It copies data from one file or block device (hard disc, cdrom, etc) to another, trying to rescue the good parts first in case of read errors. The ddrescue package also includes ddrescuelog, an auxiliary tool that manipulates ddrescue mapfiles, shows mapfile contents, converts mapfiles to/from other formats, compares mapfiles, tests rescue status, and can delete a mapfile if the rescue is done. Ddrescuelog operations can be restricted to one or several parts of the mapfile 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, restart it from a new position, etc. If you use the mapfile feature of ddrescue, the data are rescued efficiently, (only the blocks needed are read). Also you may interrupt the rescue at any time and resume it later at the same point. The mapfile is an essential part of ddrescue's effectiveness. Use it unless you know what you are doing. 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 the same area damaged in all copies is low (if the errors are randomly located). Using the mapfile, only the blocks needed are read from the second and successive copies. The mapfile is periodically saved to disc, as well as when ddrescue finishes or is interrupted. A backup copy of the mapfile with the extension ".bak" is also periodically created (if possible). So in case of a crash you can resume the rescue with little recopying. The same mapfile can be used for multiple commands that copy different areas of the input file, and for multiple recovery attempts over different subsets. Ddrescue recommends lzip for compression of backups because the lzip format is designed for long-term archiving and provides data recovery capabilities which nicely complement those of ddrescue. (Ddrescue reads as many sectors as it can, while lziprecover uses other data to repair the sectors that ddrescue was not able to read). Lziprecover's FEC algorithm can repair any kind of file, but its ability to repair lzip files is greater than for other kinds of files. Lziprecover can use the statistical properties of lzip data to repair a lzip file rescued with ddrescue, even if the fec file is so damaged that it has lost both CRC arrays. Lziprecover fec files can be used as recovery record for tar.lz archives. If the cause of file corruption is a damaged medium, the combination ddrescue + lziprecover is the recommended option for recovering data from damaged files. Because ddrescue needs to read and write at random places, it only works on seekable (random access) input and output files. Therefore, the only way of creating a compressed image with ddrescue is to create a normal (uncompressed) image first, and then compress that image. 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. The manual explains how to use direct disc access or raw devices with ddrescue. One of the strengths of ddrescue is that it is interface-agnostic, and so can be used for any kind of device supported by your kernel (ATA, SATA, SCSI, old MFM drives, floppy discs, or even flash media cards like SD). Recordable CD and DVD media keep their data only for a finite time (typically for some years). After that time, data loss develops slowly with read errors growing from the outer region towards the inside. It is a good idea to make two (or more) copies of every important CD-ROM/DVD you burn so that you can later recover them 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. Ddrescue uses Arg_parser for command-line argument parsing: http://www.nongnu.org/arg-parser/arg_parser.html Ddrescue uses Rational to parse small fractions from the command line: http://www.nongnu.org/arg-parser/rational.html Copyright (C) 2004-2026 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.30/arg_parser.cc000066400000000000000000000150131512716454500160500ustar00rootroot00000000000000/* Arg_parser - POSIX/GNU command-line argument parser. (C++ version) Copyright (C) 2006-2026 Antonio Diaz Diaz. This library is free software. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 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 "arg_parser.h" namespace { bool is_number( const char * const p ) { return std::isdigit( *p ) || ( *p == '.' && std::isdigit( p[1] ) ) || std::strcmp( p, "inf" ) == 0 || std::strcmp( p, "Inf" ) == 0 || std::strcmp( p, "INF" ) == 0; } } // end namespace 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].long_name && std::strncmp( options[i].long_name, &opt[2], len ) == 0 ) { if( std::strlen( options[i].long_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, options[index].long_name ) ); if( opt[len+2] ) // '--=' syntax { if( options[index].has_arg == no ) { error_ = "option '--"; error_ += options[index].long_name; error_ += "' doesn't allow an argument"; return false; } if( options[index].has_arg == yes && !opt[len+3] ) { error_ = "option '--"; error_ += options[index].long_name; error_ += "' requires an argument"; return false; } data.back().argument = &opt[len+3]; // argument may be empty return true; } if( options[index].has_arg == yes || options[index].has_arg == yesme ) { if( !arg || ( options[index].has_arg == yes && !arg[0] ) ) { error_ = "option '--"; error_ += options[index].long_name; error_ += "' requires an argument"; return false; } ++argind; data.back().argument = arg; // argument may be empty 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; error_ += '\''; 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 || options[index].has_arg == yesme ) { if( !arg || ( options[index].has_arg == yes && !arg[0] ) ) { error_ = "option requires an argument -- '"; error_ += c; error_ += '\''; return false; } ++argind; cind = 0; data.back().argument = arg; // argument may be empty } } return true; } Arg_parser::Arg_parser( const int argc, const char * const argv[], const Option options[], const int flags ) : argv_index_( argc ) { if( argc < 2 || !argv || !options ) return; std::vector< const char * > 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 && ( ch2 == '-' || (flags & neg_non_opt) == 0 || !is_number( argv[argind] + 1 ) ) ) { const char * const opt = argv[argind]; // we found an option 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( flags & (in_order_stop | in_order_skip) ) break; else if( flags & in_order ) data.push_back( Record( argv[argind++] ) ); else non_options.push_back( argv[argind++] ); } if( !error_.empty() ) data.clear(); else if( flags & in_order_skip ) argv_index_ = argind; else // copy non-option arguments { for( unsigned i = 0; i < non_options.size(); ++i ) data.push_back( Record( non_options[i] ) ); while( argind < argc ) data.push_back( Record( argv[argind++] ) ); } } Arg_parser::Arg_parser( const char * const opt, const char * const arg, const Option options[] ) : argv_index_( 0 ) { 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_.empty() ) data.clear(); } else data.push_back( Record( opt ) ); } gddrescue-1.30/arg_parser.h000066400000000000000000000104151512716454500157130ustar00rootroot00000000000000/* Arg_parser - POSIX/GNU command-line argument parser. (C++ version) Copyright (C) 2006-2026 Antonio Diaz Diaz. This library is free software. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 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. */ /* 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 long_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 options were specified before all the non-option arguments for the purposes of parsing, even if the user of your program intermixed options and non-option arguments. If you want the arguments in the exact order the user typed them, call 'Arg_parser' with 'flags' = 'in_order'. The argument '--' terminates all options; any following arguments are treated as non-option arguments, even if they begin with a hyphen. The syntax of options with an optional argument is '-' (without whitespace), or '--='. The syntax of options with an empty argument is '- ""', '-- ""', or '--=""'. */ class Arg_parser { public: enum Flags { in_order = 1, in_order_stop = 2, in_order_skip = 4, neg_non_opt = 8 }; // negative is non-option enum Has_arg { no, yes, maybe, yesme }; // yesme = yes but maybe empty struct Option { int code; // Short option letter or code ( code != 0 ) const char * long_name; // Long option name (maybe null) Has_arg has_arg; }; private: struct Record { int code; std::string parsed_name; std::string argument; explicit Record( const unsigned char c ) : code( c ), parsed_name( "-" ) { parsed_name += c; } Record( const int c, const char * const long_name ) : code( c ), parsed_name( "--" ) { parsed_name += long_name; } explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {} }; const std::string empty_arg; std::string error_; std::vector< Record > data; int argv_index_; 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 int flags = 0 ); // 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_; } int argv_index() const { return argv_index_; } // 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; } // Full name of the option parsed (short or long). const std::string & parsed_name( const int i ) const { if( i >= 0 && i < arguments() ) return data[i].parsed_name; else return empty_arg; } const std::string & argument( const int i ) const { if( i >= 0 && i < arguments() ) return data[i].argument; else return empty_arg; } }; gddrescue-1.30/block.cc000066400000000000000000000072421512716454500150220ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.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 ) { const int rest = end() % alignment; if( size_ > rest ) size_ -= rest; } } bool Block::join( const Block & b ) // join contiguous blocks { if( this->follows( b ) ) pos_ = b.pos_; else if( !b.follows( *this ) ) return false; if( b.size_ > LLONG_MAX - end() ) internal_error( "size overflow joining two Blocks." ); size_ += b.size_; return true; } // move the boundary of two consecutive Blocks to pos void Block::move_boundary( Block & b, const long long pos ) { if( end() != b.pos_ || pos <= pos_ || pos >= b.end() ) internal_error( "bad argument moving the boundary of two Blocks." ); b.size_ = b.end() - pos; b.pos_ = pos; size_ = pos - pos_; } 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 ); } Domain::Domain( const long long p, const long long s, const char * const mapname, const bool loose ) { reset_cached_in_size(); const Block b( p, s ); if( !mapname || !*mapname ) { block_vector.push_back( b ); return; } Mapfile mapfile( mapname ); if( !mapfile.read_mapfile( loose ? '?' : 0 ) ) { show_file_error( mapname, "Mapfile does not exist or is not readable." ); std::exit( 1 ); } mapfile.compact_sblock_vector(); for( long i = 0; i < mapfile.sblocks(); ++i ) { const Sblock & sb = mapfile.sblock( i ); if( sb.status() == sb.finished ) block_vector.push_back( sb ); } if( block_vector.empty() ) block_vector.push_back( Block( 0, 0 ) ); else this->crop( b ); } void Domain::crop( const Block & b ) { reset_cached_in_size(); unsigned long r = block_vector.size(); while( r > 0 && b < block_vector[r-1] ) --r; if( r > 0 ) block_vector[r-1].crop( b ); if( r <= 0 || block_vector[r-1].size() <= 0 ) // no block overlaps b { block_vector.clear(); block_vector.push_back( Block( 0, 0 ) ); return; } if( r < block_vector.size() ) // remove blocks beyond b block_vector.erase( block_vector.begin() + r, block_vector.end() ); if( b.pos() <= 0 ) return; --r; // block_vector[r] is now the last non-cropped-out block unsigned long l = 0; while( l < r && block_vector[l] < b ) ++l; if( l < r ) block_vector[l].crop( b ); // crop block overlapping b if( l > 0 ) // remove blocks before b block_vector.erase( block_vector.begin(), block_vector.begin() + l ); } gddrescue-1.30/command_mode.cc000066400000000000000000000115461512716454500163540ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" #include "mapbook.h" #include "rational.h" #include "rescuebook.h" int Rescuebook::copy_command( const char * const command ) { long long pos, size; const int n = std::sscanf( command, "%lli %lli", &pos, &size ); if( n != 2 || pos < 0 || size <= 0 ) return 1; const long long end = Block( pos, size ).end(); while( pos < end ) { Block b( pos, softbs() ); find_chunk( b, Sblock::non_tried, domain(), softbs(), false, true ); if( b.size() <= 0 || b.pos() >= end ) break; if( b.end() > end ) b.size( end - b.pos() ); pos = b.end(); int copied_size = 0, error_size = 0; int retval = copy_block( b, copied_size, error_size ); if( retval ) return 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( iname_, early_eof_msg ); retval = 1; } } if( copied_size > 0 ) change_chunk_status( Block( b.pos(), copied_size ), Sblock::finished ); if( error_size > 0 ) { change_chunk_status( Block( b.pos() + copied_size, error_size ), Sblock::bad_sector ); struct stat istat; if( stat( iname_, &istat ) != 0 ) { final_msg( iname_, disap_msg, errno ); retval = 1; } } if( retval ) return retval; } return 0; } int Rescuebook::status_command( const char * const command ) const { long long pos, size; const int n = std::sscanf( command, "%lli %lli", &pos, &size ); if( n != 2 || pos < 0 || size <= 0 ) return 1; const Block b( pos, size ); const long index = find_index( pos ); if( index < 0 ) return 1; for( long i = index; i < sblocks(); ++i ) { const Sblock & sb = sblock( i ); if( sb.pos() >= b.end() ) break; if( !domain().includes( sb ) && domain() < sb ) break; Block c( sb ); c.crop( b ); std::printf( "0x%08llX 0x%08llX %c\n", c.pos(), c.size(), sb.status() ); } return 0; } // Return values: 1 write error/unknown command, 0 OK. // int Rescuebook::do_commands( const int ides, const int odes ) { ides_ = ides; odes_ = odes; // set_signals(); // ignore signals initial_time(); int retval = 0; while( true ) { std::string command; while( true ) { const int c = std::fgetc( stdin ); if( c == '\n' ) { if( command.size() ) break; else continue; } if( c == EOF ) { command = "f"; break; } // discard partial command if( !std::isspace( c ) ) command += c; else if( command.size() && !std::isspace( command.end()[-1] ) ) command += ' '; } if( command == "q" ) break; int tmp = 0; // -1 finish, 0 OK, 1 error, 2 fatal error const bool finish = command == "f"; if( finish || command == "u" ) { if( finish ) compact_sblock_vector(); if( !update_mapfile( odes_, true ) ) { if( finish ) { emergency_save(); tmp = 2; } else tmp = 1; } else if( finish ) tmp = -1; } else if( command.size() > 1 && command[0] == 'c' ) tmp = copy_command( command.c_str() + 1 ); else if( command.size() > 1 && command[0] == 's' ) tmp = status_command( command.c_str() + 1 ); else { std::printf( "error: unknown command '%s'\n", command.c_str() ); retval = 1; if( safe_fflush( stdout ) ) continue; else tmp = 2; } if( tmp <= 0 ) std::fputs( "done\n", stdout ); else { if( final_msg().size() ) { printf( "error: %s%s%s\n", final_msg().c_str(), ( final_errno() > 0 ) ? ": " : "", ( final_errno() > 0 ) ? std::strerror( final_errno() ) : "" ); final_msg( "" ); } else std::fputs( "error\n", stdout ); } if( !safe_fflush( stdout ) ) tmp = 2; if( tmp ) { if( tmp > 0 ) retval = 1; if( tmp != 1 ) break; } } if( close( odes_ ) != 0 ) { show_file_error( oname_, "Error closing outfile", errno ); if( retval == 0 ) retval = 1; } return retval; } gddrescue-1.30/configure000077500000000000000000000144501512716454500153270ustar00rootroot00000000000000#! /bin/sh # configure script for GNU ddrescue - Data recovery tool # Copyright (C) 2004-2026 Antonio Diaz Diaz. # # This configure script is free software: you have unlimited permission # to copy, distribute, and modify it. pkgname=ddrescue pkgversion=1.30 progname=ddrescue use_non_posix= srctrigger=doc/${pkgname}.texi # 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= MAKEINFO=makeinfo # checking whether we are using GNU C++. /bin/sh -c "${CXX} --version" > /dev/null 2>&1 || { CXX=c++ ; CXXFLAGS=-O2 ; } # 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 if [ -z "${args}" ] ; then args="\"${option}\"" else args="${args} \"${option}\"" ; fi # 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: $0 [OPTION]... [VAR=VALUE]..." echo echo "To assign makefile variables (e.g., CXX, CXXFLAGS...), specify them as" echo "arguments to configure in the form VAR=VALUE." echo echo "Options and variables: [defaults in brackets]" echo " -h, --help display this help and exit" echo " -V, --version output version information and exit" echo " --srcdir=DIR find the source code 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 " --enable-non-posix enable non-portable code and ioctl's [disable]" echo " CXX=COMPILER C++ compiler to use [${CXX}]" echo " CPPFLAGS=OPTIONS command-line options for the preprocessor [${CPPFLAGS}]" echo " CXXFLAGS=OPTIONS command-line options for the C++ compiler [${CXXFLAGS}]" echo " CXXFLAGS+=OPTIONS append options to the current value of CXXFLAGS" echo " LDFLAGS=OPTIONS command-line options for the linker [${LDFLAGS}]" echo " MAKEINFO=NAME makeinfo program to use [${MAKEINFO}]" 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 ;; --enable-non-posix) use_non_posix=-DUSE_NON_POSIX ;; CXX=*) CXX=${optarg} ;; CPPFLAGS=*) CPPFLAGS=${optarg} ;; CXXFLAGS=*) CXXFLAGS=${optarg} ;; CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;; LDFLAGS=*) LDFLAGS=${optarg} ;; MAKEINFO=*) MAKEINFO=${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 whether 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 code, 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 source code 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. Don't 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" if [ -n "${use_non_posix}" ] ; then echo "USE_NON_POSIX = yes" ; fi 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}" echo "MAKEINFO = ${MAKEINFO}" rm -f Makefile cat > Makefile << EOF # Makefile for GNU ddrescue - Data recovery tool # Copyright (C) 2004-2026 Antonio Diaz Diaz. # This file was generated automatically by configure. Don't edit. # # This Makefile is free software: you have unlimited permission # to copy, distribute, and modify it. pkgname = ${pkgname} pkgversion = ${pkgversion} progname = ${progname} use_non_posix = ${use_non_posix} VPATH = ${srcdir} prefix = ${prefix} exec_prefix = ${exec_prefix} bindir = ${bindir} datarootdir = ${datarootdir} infodir = ${infodir} mandir = ${mandir} CXX = ${CXX} CPPFLAGS = ${CPPFLAGS} CXXFLAGS = ${CXXFLAGS} LDFLAGS = ${LDFLAGS} MAKEINFO = ${MAKEINFO} EOF cat "${srcdir}/Makefile.in" >> Makefile echo "OK. Now you can run make." gddrescue-1.30/ddrescuelog.cc000066400000000000000000001072711512716454500162330ustar00rootroot00000000000000/* GNU ddrescuelog - Tool for ddrescue mapfiles Copyright (C) 2011-2026 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 2 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 command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., bug) which caused ddrescuelog to panic. */ #include #include #include #include #include #include "mapfile.h" #include "ddrescuelog.h" #include "arg_parser.h" namespace { const char * const Program_name = "GNU ddrescuelog"; const char * const program_name = "ddrescuelog"; const char * invocation_name = program_name; // default value enum Format { f_list, f_bitmap_be, f_bitmap_le }; enum Mode { m_none, m_and, m_annotate, m_change, m_compare, m_complete, m_create, m_delete, m_done_st, m_invert, m_list, m_make_test, m_or, m_shift, m_status, m_xor }; void show_help( const int hardbs ) { std::fputs( "GNU ddrescuelog is a tool that manipulates ddrescue mapfiles, shows mapfile\n" "contents, converts mapfiles to/from other formats, compares mapfiles, tests\n" "rescue status, and can delete a mapfile if the rescue is done. Ddrescuelog\n" "operations can be restricted to one or several parts of the mapfile if the\n" "domain setting options are used.\n" "\nUse a hyphen '-' as mapfile to read the mapfile from standard input\n" "(also in the options taking a mapfile argument) or to write the mapfile\n" "created by '--create-mapfile' to standard output.\n" "\nNOTE: In versions of ddrescue prior to 1.20 the mapfile was called\n" "'logfile'. The format is the same; only the name has changed.\n", stdout ); std::printf( "\nUsage: %s [options] mapfile\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 mapfile\n" " -A, --annotate-mapfile add comments with human-readable pos/sizes\n" " -b, --block-size= block (sector) size in bytes [default %d]\n", hardbs ); std::fputs( " -B, --binary-prefixes show binary multipliers in numbers [SI]\n" " -c, --create-mapfile[=] create mapfile from list of blocks [+-]\n" " -C, --complete-mapfile[=] complete mapfile adding blocks of type t [?]\n" " -d, --delete-if-done delete the mapfile if rescue is finished\n" " -D, --done-status return 0 if rescue is finished\n" " -f, --force overwrite existing output files\n" " -F, --format= format for -c and -l (list, bitmap-[bl]e)\n" " -H, --make-test= create mapfile for test mode of ddrescue\n" " -i, --input-position= starting position of rescue domain [0]\n" " -l, --list-blocks= print block numbers of given types (?*/-+)\n" " -L, --loose-domain accept unordered domain mapfile with gaps\n" " -m, --domain-mapfile= restrict domain to finished blocks in \n" " -n, --invert-mapfile invert block types (finished <--> others)\n" " -o, --output-position= starting position in output file [ipos]\n" " -p, --compare-mapfile= compare block types in domain of both files\n" " -P, --compare-as-domain= like -p but compare finished blocks only\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 mapfile contents\n" " -v, --verbose be verbose (a 2nd -v gives more)\n" " -x, --xor-mapfile= XOR the finished blocks in file with mapfile\n" " -y, --and-mapfile= AND the finished blocks in file with mapfile\n" " -z, --or-mapfile= OR the finished blocks in file with mapfile\n" " --shift shift all block positions by (opos - ipos)\n" "\nNumbers may be in decimal, hexadecimal, or octal, may contain underscore\n" "separators between groups of digits, and may be followed by a SI or binary\n" "multiplier and 's' for 'sectors': 1_234_567kB, 4Kis, 0x1234_5678, 07_777.\n" "The syntax of the argument of option '-H' is\n" "\n" "\n*Exit status*\n" "0 for a normal exit, 1 for environmental problems (file not found, invalid\n" "command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid\n" "input file, 3 for an internal consistency error (e.g., bug) which caused\n" "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", stdout ); } } // end namespace #include "main_common.cc" namespace { void parse_format( const std::string & sarg, const char * const option_name, Format & format ) { if( sarg == "list" ) format = f_list; else if( sarg == "bitmap-be" ) format = f_bitmap_be; else if( sarg == "bitmap" || sarg == "bitmap-le" ) format = f_bitmap_le; else { show_option_error( sarg.c_str(), "Invalid format name in", option_name ); std::exit( 1 ); } } void parse_types( const std::string & sarg, const char * const option_name, 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 < sarg.size(); ++i ) { const char ch = sarg[i]; if( ch == ',' ) { if( !comma_found ) { comma_found = true; p = &types2; continue; } show_option_error( sarg.c_str(), "Too many commas in argument of", option_name ); std::exit( 1 ); } if( !Sblock::isstatus( ch ) ) { error = true; break; } *p += ch; } if( types1.empty() || types2.empty() ) error = true; if( error ) { show_option_error( sarg.c_str(), inval_t_msg, option_name ); std::exit( 1 ); } if( types1.size() > types2.size() ) types2.append( types1.size() - types2.size(), types2.end()[-1] ); } void parse_2types( const std::string & sarg, const char * const option_name, Sblock::Status & type1, Sblock::Status & type2 ) { if( sarg.empty() ) return; if( sarg.size() != 2 || sarg[0] == sarg[1] || !Sblock::isstatus( sarg[0] ) || !Sblock::isstatus( sarg[1] ) ) { show_option_error( sarg.c_str(), inval_t_msg, option_name ); std::exit( 1 ); } type1 = Sblock::Status( sarg[0] ); type2 = Sblock::Status( sarg[1] ); } void parse_type( const std::string & sarg, const char * const option_name, Sblock::Status & complete_type ) { if( sarg.empty() ) return; if( sarg.size() != 1 || !Sblock::isstatus( sarg[0] ) ) { show_option_error( sarg.c_str(), inval_t_msg, option_name ); std::exit( 1 ); } complete_type = Sblock::Status( sarg[0] ); } void test_offset( const long long offset, const int hardbs ) { if( llabs( offset ) % hardbs ) { show_error( "Offset between '-i' and '-o' must be 0 or a multiple of sector size." ); std::exit( 1 ); } } int do_logic_ops( Domain & domain, const char * const mapname, const char * const second_mapname, const Mode program_mode ) { Mapfile mapfile( mapname ); if( !mapfile.read_mapfile() ) return not_readable( mapfile.pname() ); mapfile.compact_sblock_vector(); Mapfile mapfile2( second_mapname ); if( !mapfile2.read_mapfile() ) return not_readable( mapfile2.pname() ); mapfile2.compact_sblock_vector(); domain.crop( mapfile.extent() ); domain.crop( mapfile2.extent() ); if( domain.empty() ) return empty_domain(); mapfile.split_by_domain_borders( domain ); mapfile2.split_by_domain_borders( domain ); mapfile.split_by_mapfile_borders( mapfile2 ); mapfile2.split_by_mapfile_borders( mapfile ); for( long i = 0, j = 0; ; ++i, ++j ) { while( i < mapfile.sblocks() && !domain.includes( mapfile.sblock( i ) ) ) ++i; while( j < mapfile2.sblocks() && !domain.includes( mapfile2.sblock( j ) ) ) ++j; if( i >= mapfile.sblocks() || j >= mapfile2.sblocks() ) break; const Sblock & sb1 = mapfile.sblock( i ); const Sblock & sb2 = mapfile2.sblock( j ); if( sb1.pos() != sb2.pos() || sb1.size() != sb2.size() ) internal_error( "blocks got out of sync." ); const bool f1 = sb1.status() == sb1.finished; const bool f2 = sb2.status() == sb2.finished; switch( program_mode ) { case m_and: if( f1 && !f2 ) mapfile.change_sblock_status( i, sb1.bad_sector ); break; case m_or: if( !f1 && f2 ) mapfile.change_sblock_status( i, sb1.finished ); break; case m_xor: if( f2 ) mapfile.change_sblock_status( i, f1 ? sb1.bad_sector : sb1.finished ); break; default: internal_error( "invalid program_mode." ); } } mapfile.compact_sblock_vector(); if( !mapfile.write_mapfile( stdout ) || std::fclose( stdout ) != 0 ) { show_file_error( "(stdout)", "Error writing mapfile", errno ); return 1; } return 0; } int annotate_mapfile( Domain & domain, const char * const mapname ) { Mapfile mapfile( mapname ); if( !mapfile.read_mapfile() ) return not_readable( mapfile.pname() ); domain.crop( mapfile.extent() ); if( domain.empty() ) return empty_domain(); mapfile.split_by_domain_borders( domain ); if( !mapfile.write_mapfile( stdout, false, false, &domain ) || std::fclose( stdout ) != 0 ) { show_file_error( "(stdout)", "Error writing mapfile", errno ); return 1; } return 0; } int change_types( Domain & domain, const char * const mapname, const std::string & types1, const std::string & types2 ) { Mapfile mapfile( mapname ); if( !mapfile.read_mapfile() ) return not_readable( mapfile.pname() ); domain.crop( mapfile.extent() ); if( domain.empty() ) return empty_domain(); mapfile.split_by_domain_borders( domain ); for( long i = 0; i < mapfile.sblocks(); ++i ) { const Sblock & sb = mapfile.sblock( i ); if( !domain.includes( sb ) ) { if( domain < sb ) break; else continue; } const unsigned j = types1.find( sb.status() ); if( j < types1.size() ) mapfile.change_sblock_status( i, Sblock::Status( types2[j] ) ); } mapfile.compact_sblock_vector(); if( !mapfile.write_mapfile( stdout ) || std::fclose( stdout ) != 0 ) { show_file_error( "(stdout)", "Error writing mapfile", errno ); return 1; } return 0; } int set_for_compare( Domain & domain, Mapfile & mapfile, const bool as_domain, const bool loose ) { if( !mapfile.read_mapfile( ( as_domain && loose ) ? '?' : 0 ) ) return not_readable( mapfile.pname() ); mapfile.compact_sblock_vector(); domain.crop( mapfile.extent() ); if( domain.empty() ) return empty_domain(); mapfile.split_by_domain_borders( domain ); return -1; } int compare_mapfiles( Domain & domain, const char * const mapname, const char * const second_mapname, const bool as_domain, const bool loose ) { Domain domain2( domain ); Mapfile mapfile( mapname ); int retval = set_for_compare( domain, mapfile, as_domain, loose ); if( retval >= 0 ) return retval; Mapfile mapfile2( second_mapname ); retval = set_for_compare( domain2, mapfile2, as_domain, loose ); if( retval >= 0 ) return retval; retval = 0; if( !as_domain && domain != domain2 ) retval = 1; else { long i = 0, j = 0; while( true ) { while( i < mapfile.sblocks() && ( !domain.includes( mapfile.sblock( i ) ) || ( as_domain && mapfile.sblock( i ).status() != Sblock::finished ) ) ) ++i; while( j < mapfile2.sblocks() && ( !domain2.includes( mapfile2.sblock( j ) ) || ( as_domain && mapfile2.sblock( j ).status() != Sblock::finished ) ) ) ++j; if( ( i < mapfile.sblocks() ) != ( j < mapfile2.sblocks() ) ) { retval = 1; break; } // one file has more blocks if( i >= mapfile.sblocks() ) break; // successful compare if( mapfile.sblock( i++ ) != mapfile2.sblock( j++ ) ) { retval = 1; break; } } } if( retval && verbosity >= 0 ) std::fprintf( stderr, "%s: Mapfiles '%s' and '%s' differ.\n", program_name, mapfile.filename(), mapfile2.filename() ); return retval; } int complete_mapfile( const char * const mapname, const Sblock::Status complete_type ) { Mapfile mapfile( mapname ); if( !mapfile.read_mapfile( complete_type ) ) return not_readable( mapfile.pname() ); mapfile.compact_sblock_vector(); if( !mapfile.write_mapfile( stdout ) || std::fclose( stdout ) != 0 ) { show_file_error( "(stdout)", "Error writing mapfile", errno ); return 1; } return 0; } bool change_run_status( const Domain & domain, Mapfile & mapfile, const long long first_block, const long long last_block, const int hardbs, const Sblock::Status type1 ) { if( last_block > LLONG_MAX / hardbs ) { show_file_error( "(stdin)", "Too many blocks in bitmap." ); return false; } const long long size = ( last_block - first_block ) * hardbs; Block b( first_block * hardbs, size ); if( domain.includes( b ) ) // change status of all run in one step mapfile.change_chunk_status( b, type1, domain ); else if( domain.overlaps( b ) ) // change status of sectors in domain { const long long end = b.end(); b.size( hardbs ); while( b.pos() < end && domain.includes( b ) ) { mapfile.change_chunk_status( b, type1, domain ); b.shift( hardbs ); } } return true; } // mark every run of 1 bits read from stdin and in domain as type1 bool change_status_from_bitmap( const Domain & domain, Mapfile & mapfile, const int hardbs, const Sblock::Status type1, const bool little_endian ) { long long first_block = -1; // if >= 0, first block of run long long bytenum = -1; while( true ) { int byte = std::getchar(); if( byte == EOF ) { if( errno == EINTR ) { errno = 0; continue; } else break; } ++bytenum; if( little_endian ) for( int i = 0; i < 8; ++i, byte >>= 1 ) { if( byte & 1 ) { if( first_block < 0 ) first_block = 8 * bytenum + i; } else if( first_block >= 0 ) // end of run { if( !change_run_status( domain, mapfile, first_block, 8 * bytenum + i, hardbs, type1 ) ) return false; first_block = -1; } } else for( int i = 0; i < 8; ++i, byte <<= 1 ) { if( byte & 0x80 ) { if( first_block < 0 ) first_block = 8 * bytenum + i; } else if( first_block >= 0 ) // end of run { if( !change_run_status( domain, mapfile, first_block, 8 * bytenum + i, hardbs, type1 ) ) return false; first_block = -1; } } } if( first_block >= 0 && // tail copy !change_run_status( domain, mapfile, first_block, 8 * bytenum + 8, hardbs, type1 ) ) return false; return true; } // mark every block read from stdin and in domain as type1 bool change_status_from_list( const Domain & domain, Mapfile & mapfile, const int hardbs, const Sblock::Status type1 ) { for( unsigned long linenum = 1; ; ++linenum ) { long long block; const int n = std::scanf( "%lli\n", &block ); if( n < 0 ) break; // EOF if( n != 1 || block < 0 || block > LLONG_MAX / hardbs ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s: (stdin): Error reading block number " "at line %lu\n", program_name, linenum ); return false; } const Block b( block * hardbs, hardbs ); if( domain.includes( b ) ) mapfile.change_chunk_status( b, type1, domain ); } return true; } int create_mapfile( const long long offset, const Domain & domain, const char * const mapname, const int hardbs, const Format format, const Sblock::Status type1, const Sblock::Status type2, const bool force ) { if( domain.empty() ) return empty_domain(); test_offset( offset, hardbs ); if( format != f_list && isatty( STDIN_FILENO ) ) { show_file_error( "(stdin)", "I won't read bitmap data from a terminal." ); std::exit( 1 ); } Mapfile mapfile( mapname ); const bool to_stdout = std::strcmp( mapname, "-" ) == 0; if( !to_stdout && !force && mapfile.read_mapfile( 0, false ) ) { show_file_error( mapname, "Mapfile exists. Use '--force' to overwrite it." ); return 1; } mapfile.set_to_status( type2 ); // mark all mapfile as type2 mapfile.split_by_domain_borders( domain ); if( format == f_list ) { if( !change_status_from_list( domain, mapfile, hardbs, type1 ) ) return 2; } else { if( !change_status_from_bitmap( domain, mapfile, hardbs, type1, format == f_bitmap_le ) ) return 2; } if( std::ferror( stdin ) || !std::feof( stdin ) || std::fclose( stdin ) != 0 ) { show_file_error( "(stdin)", "Error reading block list or bitmap", errno ); return 1; } mapfile.truncate_vector( domain.end(), true ); mapfile.shift_blocks( offset, type2 ); mapfile.compact_sblock_vector(); if( !mapfile.write_mapfile( to_stdout ? stdout : 0 ) || ( to_stdout && std::fclose( stdout ) != 0 ) ) { show_file_error( mapfile.pname( false ), "Error writing mapfile", errno ); return 1; } return 0; } int test_if_done( Domain & domain, const char * const mapname, const bool del ) { Mapfile mapfile( mapname ); if( !mapfile.read_mapfile() ) return not_readable( mapfile.pname() ); domain.crop( mapfile.extent() ); if( domain.empty() ) return empty_domain(); mapfile.split_by_domain_borders( domain ); for( long i = 0; i < mapfile.sblocks(); ++i ) { const Sblock & sb = mapfile.sblock( i ); if( !domain.includes( sb ) ) { if( domain < sb ) break; else continue; } if( sb.status() != sb.finished ) { if( verbosity >= 1 ) show_file_error( mapfile.pname(), "Mapfile not done." ); return 1; } } if( !del || std::strcmp( mapname, "-" ) == 0 ) return 0; if( std::remove( mapname ) != 0 ) { show_file_error( mapname, "Error deleting mapfile", errno ); return 1; } if( verbosity >= 1 ) show_file_error( mapname, "Mapfile successfully deleted." ); return 0; } int shift_blocks( const long long ipos, const long long opos, Domain & domain, const char * const mapname ) { if( ipos != 0 && opos != 0 ) { show_error( "Either '-i' or '-o' must be 0" ); return 1; } const long long offset = opos - ipos; Mapfile mapfile( mapname ); if( !mapfile.read_mapfile() ) return not_readable( mapfile.pname() ); domain.crop( mapfile.extent() ); if( domain.empty() ) return empty_domain(); mapfile.truncate_vector( domain.end(), true ); mapfile.shift_blocks( offset, Sblock::non_tried ); mapfile.compact_sblock_vector(); if( !mapfile.write_mapfile( stdout ) || std::fclose( stdout ) != 0 ) { show_file_error( "(stdout)", "Error writing mapfile", errno ); return 1; } return 0; } bool put_byte( const unsigned char byte ) { while( true ) { if( std::putchar( byte ) != EOF ) return true; if( errno != EINTR ) return false; } } bool put_bits( long long bits, int & bitnum, unsigned char & byte, const bool is_one, const bool little_endian ) { bool error = false; while( bits > 0 && bitnum != 0 ) // add bits to current byte { --bits; if( is_one ) byte |= 1 << ( little_endian ? bitnum : 7 - bitnum ); if( ++bitnum >= 8 ) { bitnum = 0; if( !put_byte( byte ) ) error = true; } } if( bits <= 0 ) return !error; byte = is_one ? 0xFF : 0; // output whole bytes while( bits >= 8 ) { bits -= 8; if( !put_byte( byte ) ) error = true; } byte = 0; for( ; bits > 0; --bits, ++bitnum ) // add rest of bits if( is_one ) byte |= 1 << ( little_endian ? bitnum : 7 - bitnum ); return !error; } bool to_bitmap( const long long offset, const Domain & domain, const Mapfile & mapfile, const int hardbs, const std::string & blocktypes, const bool little_endian ) { // bits corresponding to negative block numbers must be skipped long long bits_to_skip = ( offset < 0 ) ? -offset / hardbs : 0; long long pos = mapfile.extent().pos(); // may be > 0 int bitnum = 0; // 0 to 7 unsigned char byte = 0; bool error = false; bool prev_was_one = false; // 0's must be prepended to bitmap if offset is positive if( offset >= hardbs && !put_bits( offset / hardbs, bitnum, byte, 0, little_endian ) ) error = true; // 0's must be prepended to bitmap if mapfile start is >= hardbs if( pos >= hardbs && !put_bits( pos / hardbs, bitnum, byte, 0, little_endian ) ) error = true; for( long i = 0; i < mapfile.sblocks(); ++i ) { const Sblock & sb = mapfile.sblock( i ); const bool is_one = domain.includes( sb ) && blocktypes.find( sb.status() ) < blocktypes.size(); if( pos != sb.pos() ) internal_error( "blocks are not contiguous." ); if( pos % hardbs ) // complete a partial block { const int rest = hardbs - pos % hardbs; if( is_one ) prev_was_one = true; if( sb.size() < rest ) { pos += sb.size(); continue; } if( bits_to_skip > 0 ) --bits_to_skip; else if( !put_bits( 1, bitnum, byte, prev_was_one, little_endian ) ) error = true; pos += rest; } long long bits_in_run = ( sb.end() - pos ) / hardbs; pos += bits_in_run * hardbs; // add whole blocks if( bits_to_skip > 0 ) { if( bits_to_skip >= bits_in_run ) { bits_to_skip -= bits_in_run; bits_in_run = 0; } else { bits_in_run -= bits_to_skip; bits_to_skip = 0; } } if( bits_in_run > 0 && !put_bits( bits_in_run, bitnum, byte, is_one, little_endian ) ) error = true; if( pos < sb.end() ) { pos = sb.end(); prev_was_one = is_one; } // rest } if( pos % hardbs && bits_to_skip <= 0 && // partial tail bit !put_bits( 1, bitnum, byte, prev_was_one, little_endian ) ) error = true; if( bitnum != 0 && !put_byte( byte ) ) error = true; // tail copy return !error; } bool to_badblocks( const long long offset, const Domain & domain, const Mapfile & mapfile, const int hardbs, const std::string & blocktypes ) { long long last_block = -1; bool error = false; for( long i = 0; i < mapfile.sblocks(); ++i ) { const Sblock & sb = mapfile.sblock( i ); if( !domain.includes( sb ) ) { if( domain < sb ) break; else continue; } if( blocktypes.find( sb.status() ) >= blocktypes.size() ) continue; long long block = ( sb.pos() + offset ) / hardbs; // block numbers can't be negative because domain starts at ipos if( block < 0 ) internal_error( "negative block number." ); if( block < last_block ) internal_error( "block out of order." ); for( ; block * hardbs < sb.end() + offset; ++block ) if( block > last_block ) { last_block = block; if( std::printf( "%lld\n", block ) < 0 ) error = true; } } return !error; } int list_blocks( const long long offset, Domain & domain, const char * const mapname, const int hardbs, const Format format, const std::string & blocktypes ) { bool error = false; test_offset( offset, hardbs ); if( format != f_list && isatty( STDOUT_FILENO ) ) { show_file_error( "(stdout)", "I won't write bitmap data to a terminal." ); std::exit( 1 ); } Mapfile mapfile( mapname ); if( !mapfile.read_mapfile() ) return not_readable( mapfile.pname() ); domain.crop( mapfile.extent() ); if( domain.empty() ) return empty_domain(); mapfile.split_by_domain_borders( domain ); if( format == f_list ) { if( !to_badblocks( offset, domain, mapfile, hardbs, blocktypes ) ) error = true; } else { if( !to_bitmap( offset, domain, mapfile, hardbs, blocktypes, format == f_bitmap_le ) ) error = true; } if( std::fclose( stdout ) != 0 || error ) { show_file_error( "(stdout)", "Error writing block list or bitmap", errno ); return 1; } return 0; } int show_status( Domain & domain, const char * const mapname, const bool loose ) { long long non_tried_size = 0, non_trimmed_size = 0; long long non_scraped_size = 0, bad_size = 0, finished_size = 0; unsigned long non_tried_areas = 0, non_trimmed_areas = 0; unsigned long non_scraped_areas = 0, bad_areas = 0, finished_areas = 0; Mapfile mapfile( mapname ); if( !mapfile.read_mapfile( loose ? '?' : 0 ) ) return not_readable( mapfile.pname() ); mapfile.compact_sblock_vector(); const Block extent = mapfile.extent(); domain.crop( extent ); if( domain.empty() ) return empty_domain(); const long true_sblocks = mapfile.sblocks(); mapfile.split_by_domain_borders( domain ); for( long i = 0; i < mapfile.sblocks(); ++i ) { const Sblock & sb = mapfile.sblock( i ); if( !domain.includes( sb ) ) { if( domain < sb ) break; else continue; } switch( sb.status() ) { case Sblock::non_tried: non_tried_size += sb.size(); ++non_tried_areas; break; case Sblock::non_trimmed: non_trimmed_size += sb.size(); ++non_trimmed_areas; break; case Sblock::non_scraped: non_scraped_size += sb.size(); ++non_scraped_areas; break; case Sblock::bad_sector: bad_size += sb.size(); ++bad_areas; break; case Sblock::finished: finished_size += sb.size(); ++finished_areas; break; } } const long long domain_size = domain.in_size(); if( verbosity >= 1 ) std::printf( "\n%s", mapname ); std::printf( "\n current pos: %9sB, current status: %s\n", format_num( mapfile.current_pos() ), Mapfile::status_name( mapfile.current_status() ) ); std::printf( "mapfile extent: %9sB, in %7s area(s)\n", format_num( extent.size() ), format_num3( true_sblocks ) ); if( domain.pos() > 0 || domain.end() < extent.end() || domain.blocks() > 1 ) { std::printf( " domain begin: %9sB, domain end: %9sB\n", format_num( domain.pos() ), format_num( domain.end() ) ); std::printf( " domain size: %9sB, in %7s area(s)\n", format_num( domain_size ), format_num3( domain.blocks() ) ); } std::printf( "\n non-tried: %9sB, in %7s area(s) (%s)\n", format_num( non_tried_size ), format_num3( non_tried_areas ), format_percentage( non_tried_size, domain_size ) ); std::printf( " rescued: %9sB, in %7s area(s) (%s)\n", format_num( finished_size ), format_num3( finished_areas ), format_percentage( finished_size, domain_size ) ); std::printf( " non-trimmed: %9sB, in %7s area(s) (%s)\n", format_num( non_trimmed_size ), format_num3( non_trimmed_areas ), format_percentage( non_trimmed_size, domain_size ) ); std::printf( " non-scraped: %9sB, in %7s area(s) (%s)\n", format_num( non_scraped_size ), format_num3( non_scraped_areas ), format_percentage( non_scraped_size, domain_size ) ); std::printf( " bad-sector: %9sB, in %7s area(s) (%s)\n", format_num( bad_size ), format_num3( bad_areas ), format_percentage( bad_size, domain_size ) ); return 0; } } // end namespace 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_mapfile_name = 0; const char * second_mapname = 0; const int default_hardbs = 512; int hardbs = default_hardbs; Format format = f_list; Mode program_mode = m_none; bool as_domain = false; bool force = false; bool loose = false; std::string types1, types2; Sblock::Status type1 = Sblock::finished, type2 = Sblock::bad_sector; Sblock::Status complete_type = Sblock::non_tried; if( argc > 0 ) invocation_name = argv[0]; command_line = invocation_name; for( int i = 1; i < argc; ++i ) { command_line += ' '; command_line += argv[i]; } enum Optcode { opt_shi = 256 }; const Arg_parser::Option options[] = { { 'a', "change-types", Arg_parser::yes }, { 'A', "annotate-mapfile", Arg_parser::no }, { 'b', "block-size", Arg_parser::yes }, { 'b', "sector-size", Arg_parser::yes }, { 'B', "binary-prefixes", Arg_parser::no }, { 'c', "create-mapfile", Arg_parser::maybe }, { 'C', "complete-mapfile", Arg_parser::maybe }, { 'd', "delete-if-done", Arg_parser::no }, { 'D', "done-status", Arg_parser::no }, { 'f', "force", Arg_parser::no }, { 'F', "format", Arg_parser::yes }, { 'h', "help", Arg_parser::no }, { 'H', "make-test", Arg_parser::yes }, { 'i', "input-position", Arg_parser::yes }, { 'l', "list-blocks", Arg_parser::yes }, { 'L', "loose-domain", Arg_parser::no }, { 'm', "domain-mapfile", Arg_parser::yes }, { 'n', "invert-mapfile", Arg_parser::no }, { 'o', "output-position", Arg_parser::yes }, { 'p', "compare-mapfile", Arg_parser::yes }, { 'P', "compare-as-domain", 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-mapfile", Arg_parser::yes }, { 'y', "and-mapfile", Arg_parser::yes }, { 'z', "or-mapfile", Arg_parser::yes }, { opt_shi, "shift", Arg_parser::no }, { 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 pn = parser.parsed_name( argind ).c_str(); const std::string & sarg = parser.argument( argind ); const char * const arg = sarg.c_str(); switch( code ) { case 'a': set_mode( program_mode, m_change ); parse_types( sarg, pn, types1, types2 ); break; case 'A': set_mode( program_mode, m_annotate ); break; case 'b': hardbs = getnum( arg, pn, 0, 1, INT_MAX ); break; case 'B': format_num( 0, 0, -1 ); break; // set binary prefixes case 'c': set_mode( program_mode, m_create ); parse_2types( sarg, pn, type1, type2 ); break; case 'C': set_mode( program_mode, m_complete ); parse_type( sarg, pn, complete_type ); 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 'F': parse_format( sarg, pn, format ); break; case 'h': show_help( default_hardbs ); return 0; case 'H': set_mode( program_mode, m_make_test ); parse_chs( arg, pn ); break; case 'i': ipos = getnum( arg, pn, hardbs, 0 ); break; case 'l': set_mode( program_mode, m_list ); types1 = sarg; check_types( arg, types1, pn, false ); break; case 'L': loose = true; break; case 'm': set_name( &domain_mapfile_name, arg, pn ); break; case 'n': set_mode( program_mode, m_invert ); break; case 'o': opos = getnum( arg, pn, hardbs, 0 ); break; case 'p': case 'P': set_mode( program_mode, m_compare ); second_mapname = arg; as_domain = code == 'P'; break; case 'q': verbosity = -1; break; case 's': max_size = getnum( arg, pn, 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_mapname = arg; break; case 'y': set_mode( program_mode, m_and ); second_mapname = arg; break; case 'z': set_mode( program_mode, m_or ); second_mapname = arg; break; case opt_shi: set_mode( program_mode, m_shift ); 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; const int mapfiles = parser.arguments() - argind; if( program_mode == m_status ) { if( mapfiles < 1 ) { show_error( "At least one mapfile must be specified.", 0, true ); return 1; } // show mapfile names if more than one mapfile is specified if( mapfiles > 1 && verbosity == 0 ) verbosity = 1; } else if( mapfiles != 1 ) { if( mapfiles > 1 ) show_error( "Too many files.", 0, true ); else show_error( "A mapfile must be specified.", 0, true ); return 1; } int retval = 0; for( ; argind < parser.arguments(); ++argind ) { const char * const mapname = parser.argument( argind ).c_str(); Domain domain( ipos, max_size, domain_mapfile_name, loose ); 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, mapname, second_mapname, program_mode ); case m_annotate: return annotate_mapfile( domain, mapname ); case m_change: return change_types( domain, mapname, types1, types2 ); case m_compare: return compare_mapfiles( domain, mapname, second_mapname, as_domain, loose ); case m_complete: return complete_mapfile( mapname, complete_type ); case m_create: return create_mapfile( opos - ipos, domain, mapname, hardbs, format, type1, type2, force ); case m_delete: return test_if_done( domain, mapname, true ); case m_done_st: return test_if_done( domain, mapname, false ); case m_invert: return change_types( domain, mapname, "?*/-+", "++++-" ); case m_list: return list_blocks( opos - ipos, domain, mapname, hardbs, format, types1 ); case m_make_test: return make_test( mapname, hardbs, force ); case m_shift: return shift_blocks( ipos, opos, domain, mapname ); case m_status: retval = std::max( retval, show_status( domain, mapname, loose ) ); } } return retval; } gddrescue-1.30/ddrescuelog.h000066400000000000000000000016071512716454500160710ustar00rootroot00000000000000/* GNU ddrescuelog - Tool for ddrescue mapfiles Copyright (C) 2011-2026 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 2 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 . */ void parse_chs( const char * const arg, const char * const pn ); int make_test( const char * const mapname, const int hardbs, const bool force ); gddrescue-1.30/doc/000077500000000000000000000000001512716454500141615ustar00rootroot00000000000000gddrescue-1.30/doc/ddrescue.1000066400000000000000000000155201512716454500160440ustar00rootroot00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. .TH DDRESCUE "1" "January 2026" "GNU ddrescue 1.30" "User Commands" .SH NAME ddrescue \- data recovery tool .SH SYNOPSIS .B ddrescue [\fI\,options\/\fR] \fI\,infile outfile \/\fR[\fI\,mapfile\/\fR] .SH DESCRIPTION GNU ddrescue is a data recovery tool. It copies data from one file or block device (hard disc, cdrom, etc) to another, trying to rescue the good parts first in case of read errors. .PP Always use a mapfile unless you know you won't need it. Without a mapfile, ddrescue can't resume a rescue, only reinitiate it. Be careful to not specify by mistake an old mapfile from an unrelated rescue. .PP NOTE: In versions of ddrescue prior to 1.20 the mapfile was called \&'logfile'. The format is the same; only the name has changed. .PP If you reboot, check the device names before restarting ddrescue. Don't 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\-trimmed, non\-scraped 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 don't read new data beyond mapfile limits .TP \fB\-d\fR, \fB\-\-idirect\fR use direct disc access for input file .TP \fB\-D\fR, \fB\-\-odirect\fR use direct disc access for output file .TP \fB\-e\fR, \fB\-\-max\-bad\-areas\fR=\fI\,[\/\fR+] maximum number of [new] bad 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 blocks of given types with data (?*/\-+l) .TP \fB\-G\fR, \fB\-\-generate\-mode\fR generate approximate mapfile from partial copy .TP \fB\-H\fR, \fB\-\-test\-mode=\fR set map of good/bad blocks from given mapfile .TP \fB\-i\fR, \fB\-\-input\-position=\fR starting position of domain in input file [0] .TP \fB\-I\fR, \fB\-\-check\-input\-size\fR compare input file size with size in mapfile .TP \fB\-J\fR, \fB\-\-check\-on\-error\fR reread latest good sector after every error .TP \fB\-K\fR, \fB\-\-skip\-size\fR=\fI\,[\/\fR][,] initial,maximum size to skip on read error .TP \fB\-L\fR, \fB\-\-loose\-domain\fR accept unordered domain mapfile with gaps .TP \fB\-m\fR, \fB\-\-domain\-mapfile=\fR restrict domain to finished blocks in .TP \fB\-M\fR, \fB\-\-retrim\fR mark some failed blocks as non\-trimmed .TP \fB\-n\fR, \fB\-\-no\-scrape\fR skip the scraping phase .TP \fB\-N\fR, \fB\-\-no\-sweep\fR skip the sweeping phase .TP \fB\-\-no\-trim\fR skip the trimming phase .TP \fB\-o\fR, \fB\-\-output\-position=\fR starting position in output file [ipos] .TP \fB\-O\fR, \fB\-\-reopen\-on\-error\fR reopen input file after every read error .TP \fB\-p\fR, \fB\-\-preallocate\fR preallocate space on disc for output file .TP \fB\-P\fR, \fB\-\-data\-preview[=\fR] show some lines of the latest data read [3] .TP \fB\-q\fR, \fB\-\-quiet\fR suppress all messages .TP \fB\-r\fR, \fB\-\-retry\-passes=\fR exit after retry passes (\fB\-1\fR=\fI\,infinity\/\fR) [0] .TP \fB\-R\fR, \fB\-\-reverse\fR reverse the direction of all passes .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\-u\fR, \fB\-\-unidirectional\fR run all passes in the same direction .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\-W\fR, \fB\-\-compare\-before\-write\fR omit superfluous writes in rescue mode .TP \fB\-x\fR, \fB\-\-extend\-outfile=\fR extend outfile size to be at least this long .TP \fB\-X\fR, \fB\-\-max\-read\-errors=\fR maximum number of read errors allowed .TP \fB\-y\fR, \fB\-\-synchronous\fR use synchronous writes for output file .TP \fB\-Z\fR, \fB\-\-max\-read\-rate=\fR maximum read rate in bytes/s .TP \fB\-\-ask\fR ask for confirmation before starting the copy .TP \fB\-\-bad\-sector\-data=\fR treat sectors with data as read errors .TP \fB\-\-command\-mode\fR execute commands from standard input .TP \fB\-\-continue\-on\-errno=\fR[,] treat errno code as non\-fatal .TP \fB\-\-cpass=\fR select what copying pass(es) to run .TP \fB\-\-delay\-slow=\fR initial delay before checking slow reads [30] .TP \fB\-\-log\-events=\fR log significant events in .TP \fB\-\-log\-rates=\fR log rates and error sizes in .TP \fB\-\-log\-reads=\fR log all read operations in .TP \fB\-\-mapfile\-interval\fR=\fI\,[i][\/\fR,i] save/sync mapfile at given interval [auto] .TP \fB\-\-max\-slow\-reads=\fR maximum number of slow reads allowed .TP \fB\-\-pause\-on\-error=\fR time to wait after each read error [0] .TP \fB\-\-pause\-on\-pass=\fR time to wait between passes [0] .TP \fB\-\-reset\-slow\fR reset slow reads if rate rises above min .TP \fB\-\-same\-file\fR allow infile and outfile to be the same file .PP Numbers may be in decimal, hexadecimal, or octal, may contain underscore separators between groups of digits, and may be followed by a SI or binary multiplier and 's' for 'sectors': 1_234_567kB, 4Kis, 0x1234_5678, 07_777. In rescue mode, '\-\-size=output' uses the size of the output file or device. Time intervals have the format 1[.5][smhd] or 1/2[smhd]. .SH "EXIT STATUS" 0 for a normal exit, 1 for environmental problems (file not found, invalid command\-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., 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 2026 Antonio Diaz Diaz. License GPLv2+: GNU GPL version 2 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.30/doc/ddrescue.info000066400000000000000000002740771512716454500166550ustar00rootroot00000000000000This is ddrescue.info, produced by makeinfo version 4.13+ from ddrescue.texi. 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.30, 1 January 2026). * 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 * Output:: Meaning of ddrescue's screen output * Invoking ddrescue:: Command-line interface * Argument syntax:: By convention, options start with a hyphen * Mapfile structure:: Detailed format of the mapfile * Emergency save:: Saving the mapfile in case of trouble * Optical media:: Copying CD-ROMs and DVDs * Examples:: A small tutorial with examples * Direct disc access:: Bypassing the kernel cache * Command mode:: Copying parts of the input file on demand * Fill mode:: Selectively overwriting the output file * Generate mode:: Generating an approximate mapfile * Ddrescuelog:: Tool for ddrescue mapfiles * Invoking ddrescuelog:: Command-line interface * Problems:: Reporting bugs * Concept index:: Index of concepts Copyright (C) 2004-2026 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 to rescue the good parts first 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, restart it from a new position, etc. If you use the mapfile feature of ddrescue, the data are rescued efficiently, (only the blocks needed are read). Also you may interrupt the rescue at any time and resume it later at the same point. The mapfile is an essential part of ddrescue's effectiveness. Use it unless you know what you are doing. 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 the same area damaged in all copies is low (if the errors are randomly located). Using the mapfile, only the blocks needed are read from the second and successive copies. Ddrescue recommends lzip for compression of backups because the lzip format is designed for long-term archiving and provides data recovery capabilities which nicely complement those of ddrescue. (Ddrescue reads as many sectors as it can, while lziprecover uses other data to repair the sectors that ddrescue was not able to read). Lziprecover's FEC algorithm can repair any kind of file, but its ability to repair lzip files is greater than for other kinds of files. Lziprecover can use the statistical properties of lzip data to repair a lzip file rescued with ddrescue, even if the fec file is so damaged that it has lost both CRC arrays. Lziprecover fec files can be used as recovery record for tar.lz archives. If the cause of file corruption is a damaged medium, the combination ddrescue + lziprecover is the recommended option for recovering data from damaged files. *Note lziprecover example1::, *note lziprecover example2::, *note lziprecover example3::, and *note lziprecover example4::, for examples. *Note lziprecover manual: (lziprecover)Top, for details about lziprecover. Because ddrescue needs to read and write at random places, it only works on seekable (random access) input and output files. Therefore, the only way of creating a compressed image with ddrescue is to create a normal (uncompressed) image first, and then compress that image. If your system supports it, ddrescue can use direct disc access to read the input file, bypassing the kernel cache. One of the strengths of ddrescue is that it is interface-agnostic, and so can be used for any kind of device supported by your kernel (ATA, SATA, SCSI, old MFM drives, floppy discs, or even flash media cards like SD). 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. The starting position (or beginning position) is the lowest position in the block. The end of the block is its starting position plus 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 names associated to devices). 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 (file names associated to partitions). 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. CD-ROMs and DVDs 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 may define it with the options '--input-position', '--size', and '--domain-mapfile'. The rescue domain defaults to the whole input file or mapfile. If ddrescue can't determine the size of the input file, the rescue domain defaults to the maximum size of a block (at least 2^63 - 1 bytes, or 8 EiB minus 1 byte). Ddrescue never tries to read any data outside the rescue domain except when unaligned direct disc access is requested (*note Direct disc access::). If it does, please, report it as a bug. The data shown by ddrescue (amount of data rescued, number of bad areas, etc) may vary or even become zero if you limit the rescue domain. Don't worry, they have not disappeared; they are simply out of the rescue domain specified. Sector Hardware block. Smallest accessible amount of data on a block 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. Never try to rescue a r/w mounted partition. The resulting copy may be useless. It is best that the device or partition to be rescued is not mounted at all, not even read-only. 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 (for example, udev enabled systems). If you reboot such a system, pass the option '--ask' to ddrescue and check that the device names match the model and serial number of the input and output devices before allowing ddrescue to proceed. You may also check the devices with commands like 'hdparm -I /dev/sda' or 'smartctl -i /dev/sda'. 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. When using a (graphical) frontend, be careful to not insert or remove any devices to avoid changes in the mapping of devices to device names between the moment the devices are selected in the frontend and the call to ddrescue. Be careful even if the frontend passes '--ask' to ddrescue, because OUTFILE may be changed between user confirmation and actual opening. It is recommended to run ddrescue on a POSIX system, but if you run it on Cygwin be prepared to find mysterious 'Permission denied' error messages caused by Windows returning misleading error codes and then Cygwin mapping some of those error codes to EACCES, making it impossible for ddrescue to know what failed, or even whether the error is fatal or not. *Note --continue-on-errno::.  File: ddrescue.info, Node: Algorithm, Next: Output, Prev: Important advice, Up: Top 4 Algorithm *********** GNU ddrescue is not a derivative of dd, nor is related to dd in any way except in that both can be used for copying data from one device to another. The key difference is that ddrescue uses a sophisticated algorithm to copy data from failing drives causing them as little additional damage as possible. Versions of ddrescue prior to 1.19 used a divide-and-conquer strategy to rescue the difficult parts of the drive. But that caused a lot of head movement, which is bad for the drive. Therefore, newer versions try to minimize head movement to minimize drive damage. 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 read the data sequentially but switch to small size reads when they find errors. 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 divided in five phases: copying, trimming, sweeping, scraping, and retrying. Each phase is described below. Disc sectors are marked successively as non-tried, non-trimmed, non-scraped, and bad-sector until they are successfully read and marked as finished. The user may interrupt the process at any point, but a bad drive can block ddrescue for a long time until the kernel gives up. The amount of work remaining for a given phase can be calculated by comparing the current size of the corresponding areas with their size at the end of the previous pass. Namely the size of non-tried while copying or sweeping, the size of non-trimmed while trimming, the size of non-scraped while scraping, and the size of bad-sector while retrying. *Note Output::. The steps of the algorithm are: 1) Optionally read a mapfile describing the status of a multipart or previously interrupted rescue. If no mapfile is specified, or is empty, or does not exist, mark all the rescue domain as non-tried. 2) (First phase; Copying) Copying is done in up to four passes. The first pass reads the non-tried parts of the input file, marking the failed blocks as non-trimmed and skipping beyond them. The second pass runs in the opposite direction as the first pass and delimits the blocks skipped by the first pass. The first two passes also skip beyond slow areas. The slow areas skipped are tried later in two additional passes (before trimming). The copying direction is reversed after each pass until all the rescue domain is tried. The third and fourth passes read the blocks skipped due to slow areas (if any) by the first two passes, in the same direction that each block was skipped. For each block, passes 2 to 4 skip the rest of the block after finding the first error in the block. The purpose of the multiple passes is to delimit large bad areas fast, recover the most promising areas first, keep the mapfile small, and produce good starting points for trimming. Only non-tried areas are read in large blocks. Trimming, scraping, and retrying are done sector by sector. Each sector is tried at most two times: the first in the copying or sweeping phases as part of a large block read, the second during trimming, scraping, or retrying as a single sector read. 3) (Second phase; Trimming) Try again sector by sector the edges of the large block reads failed during the copying phase. Trimming is done in one pass as follows. For each non-trimmed block, if the preceding block is a finished block, read forwards one sector at a time from the leading edge of the block until a bad sector is found. Then, if the following block is a finished block, read backwards one sector at a time from the trailing edge of the block until a bad sector is found. Then mark the bad sectors found (if any) as bad-sector, and mark the rest of the block as non-scraped unless it is adjacent to a non-tried block. 4) (Third phase; Sweeping) Copy the non-tried areas skipped during the copying phase because of read errors. Sweeping may have a low probability of finding good data if the bad areas are large and have been well delimited by the copying phase. Therefore, sweeping is run after trimming the blocks adjacent to finished blocks, which has a high probability of finding good data. Sweeping is done in one pass with skipping disabled. It tries to copy each non-tried block and trim it if needed. Then it marks the bad sectors found (if any) as bad-sector, and marks the rest of the block as non-scraped. 5) (Fourth phase; Scraping) Scrape together, sector by sector, the data not recovered nor marked as bad-sector by the copying, trimming, or sweeping phases. Scraping is done in one pass. Each non-scraped block is read forwards, one sector at a time. Any bad sectors found are marked as bad-sector. 6) (Fifth phase; Retrying) Optionally try to read again the bad sectors until the number of retry passes specified is reached. The direction is reversed after each pass. Every bad sector is tried only once in each pass. Ddrescue can't know if a bad sector is unrecoverable or if it will be eventually read after some retries. 7) Optionally write a mapfile for later use. When ddrescue finishes the steps above, any areas marked as bad-sector will remain untouched in the output file. If the output file is a regular file created by ddrescue, the areas marked as bad-sector will contain zeros. If it is a device or a previously existing file, the areas marked as bad-sector will still contain the data previously present there. The mapfile is periodically saved to disc, as well as when ddrescue finishes or is interrupted. A backup copy of the mapfile with the extension '.bak' is also periodically created (if possible). So in case of a crash you can resume the rescue with little recopying. The default interval between saves varies from 30 seconds to 5 minutes depending on mapfile size (larger mapfiles are saved at longer intervals), but may be overriden. *Note --mapfile-interval::. The same mapfile 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/sdc hdimage mapfile ddrescue -i0 -s1MiB -d -r3 /dev/sdc hdimage mapfile Then rescue some key disc areas. ddrescue -i30GiB -s10GiB /dev/sdc hdimage mapfile ddrescue -i230GiB -s5GiB /dev/sdc hdimage mapfile Now rescue the rest (does not recopy what is already done). ddrescue /dev/sdc hdimage mapfile ddrescue -d -r3 /dev/sdc hdimage mapfile  File: ddrescue.info, Node: Output, Next: Invoking ddrescue, Prev: Algorithm, Up: Top 5 Meaning of ddrescue's screen output ************************************* The output of ddrescue looks like this: GNU ddrescue 1.30 Press Ctrl-C to interrupt Initial status (read from mapfile) rescued: 1665 MB, tried: 0 B, bad-sector: 0 B, bad areas: 0 Current status ipos: 2874 MB, non-trimmed: 0 B, current rate: 21479 kB/s opos: 2874 MB, non-scraped: 0 B, average rate: 21023 kB/s non-tried: 13603 MB, bad-sector: 0 B, error rate: 0 B/s rescued: 2401 MB, bad areas: 0, run time: 35s pct rescued: 15.00%, read errors: 0, remaining time: 10m slow reads: 5, time since last successful read: 0s Copying non-tried blocks... Pass 1 (forwards) Ddrescue scrolls forward after each pass. This keeps on the screen the final status of the previous pass, making it easier to estimate the amount of work done by the current pass. The meaning of each field is as follows: 'ipos' Input position. The position in the input file where data are being currently read from. 'opos' Output position. The position in the output file where data are being currently written to. 'non-tried' Size of the part of the rescue domain pending to be tried. This is the sum of the sizes of all the non-tried blocks. 'rescued' Size of the part of the rescue domain already successfully recovered. This is the sum of the sizes of all the finished blocks. 'pct rescued' Percentage of the rescue domain that has been successfully recovered. 'slow reads' Number of times that the read rate fell below '--min-read-rate' during the first two passes of the copying phase. *Note --min-read-rate::. 'tried' Size of the part of the rescue domain already tried but not yet rescued. This is the sum of the sizes of all the non-trimmed, non-scraped, and bad-sector blocks. 'non-trimmed' Size of the part of the rescue domain pending to be trimmed. This is the sum of the sizes of all the non-trimmed blocks. 'non-scraped' Size of the part of the rescue domain pending to be scraped. This is the sum of the sizes of all the non-scraped blocks. 'bad-sector' Total error size. This is the size of the part of the rescue domain formed by known bad sectors. The total error size is the sum of the sizes of all the bad-sector blocks. It increases during the trimming, sweeping, and scraping phases, and may decrease during the retrying phase. A sector is not marked as bad-sector and considered part of a bad area until it has been tried individually instead of as part of a large block read. Note that as ddrescue retries the bad-sector blocks, the good data found may divide them into smaller blocks, decreasing the total error size but increasing the number of bad areas. 'bad areas' Number of separate bad-sector blocks inside the rescue domain. Non-trimmed and non-scraped blocks are not considered bad areas. *Note --max-bad-areas::. 'read errors' Number of failed read attempts. *Note --max-error-rate::. 'current rate' The read rate measured during the last second. 'average rate' The average read rate measured during the current run. 'error rate' The read error rate measured during the last second. 'run time' Time elapsed since the beginning of the current run. 'remaining time' Estimated remaining time to rescue all the data in the rescue domain. The remaining time is calculated using the average rate of the last 60 seconds and does not take into account that some parts of the rescue domain may be excluded from the rescue (for example with '--no-sweep'), or that some areas may be unrecoverable. Therefore it may be imprecise, may vary widely during the rescue, and may show a nonzero value at the end of the rescue. In particular it may go down to a few seconds at the end of the first pass, just to grow to hours or days in the following passes. Such is the nature of ddrescue; the good parts are usually recovered fast, while the rest may take a long time. 'time since last successful read' Time elapsed since the last successful read attempt.  File: ddrescue.info, Node: Invoking ddrescue, Next: Argument syntax, Prev: Output, Up: Top 6 Invoking ddrescue ******************* The format for running ddrescue is: ddrescue [OPTIONS] INFILE OUTFILE [MAPFILE] INFILE and OUTFILE may be files, devices, or partitions. MAPFILE is a regular file and must be placed in an existing directory. If MAPFILE does not exist, ddrescue creates it. Be careful to not specify by mistake an old MAPFILE from an unrelated rescue. Ddrescue tries to create a backup copy of the mapfile, with the name MAPFILE.bak, every time it is going to overwrite a fsynced MAPFILE. *Note --mapfile-interval::. Always use a mapfile unless you know you won't need it. Without a mapfile, ddrescue can't resume a rescue, only reinitiate it. ddrescue supports the following options: *Note Argument syntax::. '-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. This version number should be included in all bug reports. '-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 during the first two passes of the copying phase, ddrescue skips ahead a variable amount depending on rate and error histories. The blocks skipped are tried in additional passes (before trimming). '--min-read-rate' is ignored in all passes but the first two. If BYTES is 0 (auto), the minimum read rate is recalculated every second as (average_rate / 10). '-A' '--try-again' Mark all non-trimmed and non-scraped blocks inside the rescue domain as non-tried before beginning the rescue. Try this if the drive stops responding and ddrescue immediately starts scraping failed blocks when restarted. If '--retrim' is also specified, mark also the most promising bad sectors inside the rescue domain as non-tried. *Note --retrim::. '-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. In rescue mode, any non-finished subsector that is found during the initial read of the mapfile is joined to its corresponding sector (if it is also not finished), marking the whole sector with the less processed state, so as to make sure that sub-sector data is not discarded from a successful read during the rescue. (A subsector is a block smaller than sector size). Subsector joining is performed in all the mapfile, not only in the rescue domain. '-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 MAPFILE. Don't read new data beyond MAPFILE 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. '-C' can only be used after a first rescue attempt, possibly limited with the option '--size', has produced a complete MAPFILE. If '-C' is not specified, ddrescue extends the MAPFILE from position 0 to the size of OUTFILE, adding one non-tried block before the existing blocks and another one after them if needed. '-d' '--idirect' Use direct disc access to read from INFILE, bypassing the kernel cache. (Opens the file with the flag 'O_DIRECT'). Sector size must be correctly set for this to work. Not all systems support this. *Note Direct disc access::. If your system does not support direct disc access, ddrescue warns you. If the sector size is not correctly set, an unaligned read error may happen, in which case ddrescue exits with error status 1. '-D' '--odirect' Use direct disc access to write to OUTFILE, bypassing the kernel cache. (Opens the file with the flag 'O_DIRECT'). 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 warns you. If the sector size is not correctly set, a write error is reported and no data is rescued. Some OSs have a bug that prevents them from detecting write errors properly (or at all) on some devices if direct disc access is not used for OUTFILE. '-e [+]N' '--max-bad-areas=[+]N' Maximum number of bad areas allowed before giving up. Defaults to infinity. If N is preceded by '+' the number refers to new bad areas found in this run, not counting those already present in the MAPFILE. *Note --max-read-errors::. '-E BYTES' '--max-error-rate=BYTES' Maximum rate of read errors allowed before giving up, in bytes per second. Defaults to infinity. The rate being measured is that of actually failed reads, so ddrescue may exit because of this rate being exceeded even if the total error size (size of bad-sector areas) does not change because the areas being tried are being marked as non-trimmed or non-scraped, or are already marked as bad-sector. '-f' '--force' Force overwrite of OUTFILE. Needed when OUTFILE is not a regular file, but a device or partition. This option is just a safeguard to prevent the inadvertent destruction of partitions, and is ignored for regular files. '-F TYPES' '--fill-mode=TYPES' Fill the blocks in OUTFILE specified as any of TYPES in MAPFILE, with data read from INFILE. TYPES contains one or more of the status characters defined in the chapter Mapfile structure (*note Mapfile structure::) and an optional 'l' for sector location data. See the chapter Fill mode (*note Fill mode::) for a complete description of the fill mode. '-G' '--generate-mode' Generate an approximate MAPFILE 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. '-H FILE' '--test-mode=FILE' Build a map of good/bad blocks using the mapfile FILE and use it to simulate read errors in INFILE. The blocks marked as finished in FILE are read normally. All other block types are considered read errors without even trying to read them from INFILE. The apparent size of INFILE is truncated to the extent of FILE. This mode is an aid in improving the algorithm of ddrescue and is also useful to check that ddrescue produces accurate results in presence of read errors. Use a hyphen '-' as FILE to read the mapfile from standard input. *Note --pause-on-error::. '-i BYTES' '--input-position=BYTES' Starting position of the rescue domain in INFILE, in bytes. Defaults to 0. This is not the point from which ddrescue starts copying. (For example, if you pass the option '--reverse' to ddrescue, it starts copying from the end of the rescue domain). 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' '--check-input-size' Compare the size of INFILE with the size calculated from the list of blocks contained in the MAPFILE, 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 MAPFILE may be incomplete, for example after doing a partial rescue. '-J' '--check-on-error' After every read error, read again the last good sector found and check that it returns the same data. Exit with status 2 if the read fails or returns inconsistent data. Exit with status 1 if a read error happens before a good sector is found. This option performs one extra read after each error, wearing the drive faster. Use it only on drives that stop responding or return garbage data after finding errors. You may need to power cycle the drive before restarting ddrescue. '-K [INITIAL][,MAX]' '--skip-size=[INITIAL][,MAX]' Set limits to skip size during the copying phase. At least one of INITIAL or MAX must be specified. INITIAL is the size to skip on the first read error or slow read, in bytes. MAX is the maximum size to skip. The values given are rounded to the next multiple of sector size. The skip size is doubled for each read error or slow read until it reaches MAX or, if MAX is omitted, 1% of the size of INFILE, and is reset to INITIAL when good data are found. Valid values range from 64 KiB to 1 EiB. INITIAL defaults to INFILE_SIZE / 32_768 with a minimum value of 64 KiB. An INITIAL value of 0 disables skipping entirely. If ddrescue is having difficulties skipping away from a large area with scattered errors, or if the device has large bad areas at regular intervals, you may increase the initial skip size with this option. Inversely, if ddrescue is skipping too much, leaving large non-tried areas behind each error (which will be read later in the usually slower backwards direction), you may reduce the maximum skip size, or disable skipping. '--skip-size' is independent from '--cluster-size'. The size to skip is calculated from the end of the block that just failed. '-L' '--loose-domain' Accept an incomplete synthetic (user fabricated) domain mapfile or test-mode mapfile, and fill the gaps in the list of data blocks with non-tried blocks. The blocks in the mapfile may be unordered, may overlap other blocks of the same status, and don't need to be contiguous. This option allows making quick edits to a mapfile without all the size calculations involved in making all data blocks contiguous again. '-m FILE' '--domain-mapfile=FILE' Restrict the rescue domain to the blocks marked as finished in the mapfile FILE. This is useful for merging partially recovered images of backups, or if the destination drive fails during the rescue. Use a hyphen '-' as FILE to read the domain mapfile from standard input. Specialized tools like ddrutility or partclone can produce a domain mapfile listing all the used blocks in a partition, making the rescue more efficient. Trailing empty space in the partition is not copied to OUTFILE. If you need OUTFILE to be the same size as the partition (to mount it, for example), you may use '--extend-outfile=0', '--extend-outfile=', or '--preallocate'. '--extend-outfile' increases the size without writing data to OUTFILE, and may therefore be more efficient than '--preallocate'. Partclone saves the size of the partition as the value of 'current_pos' in the domain mapfile. '-M' '--retrim' Mark the failed blocks inside the rescue domain adjacent to a non-tried or finished block as non-trimmed before beginning the rescue. This might make perhaps possible to rescue some of them. '-n' '--no-scrape' Skip the scraping phase. Avoids spending a lot of time trying to rescue the most difficult parts of the file. '-N' '--no-sweep' Skip the sweeping phase. May be useful when the drive has a dead head. '--no-trim' Skip the trimming phase. This option is not recommended because trimming has a high probability of finding good data. '-o BYTES' '--output-position=BYTES' Starting position of the image of the rescue domain 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. '-O' '--reopen-on-error' Close INFILE and then reopen it after every read error encountered. If '--min-read-rate' is set, also close and reopen INFILE after every slow read encountered during the first two passes of the copying phase. Use this option if you notice a permanent drop in transfer rate after finding read errors or slow areas. But be warned that most probably the slowing-down is intentionally caused by the kernel in an attempt to increase the probability of reading data from the device. This option may also be needed to reset the error status of the input device when using the option '--continue-on-errno'. *Note --min-read-rate::, *note --continue-on-errno::. '-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 options '--input-position', '--output-position', '--size', and '--domain-mapfile'. '-P[LINES]' '--data-preview[=LINES]' Show LINES lines of the latest data read in '16-byte hex + ASCII' format. Valid values for LINES range from 1 to 32. If LINES is omitted, a default value of 3 is used. '-q' '--quiet' Quiet operation. Suppress all messages. '-r N' '--retry-passes=N' Exit after the given number of retry passes. Defaults to 0. -1 means infinity. Every bad sector is tried only once in each pass. The direction is reversed after each pass. To retry bad sectors detected on a previous run, you must specify a nonzero number of retry passes. A command like 'ddrescue -f -r-1 /dev/sdcard /dev/null mapfile' can be used to read repeatedly until the device controller succeeds and remaps the bad sectors internally. '-R' '--reverse' Reverse the direction of all passes (copying, trimming, sweeping, scraping, and retrying). Every pass that is normally run forwards is now run backwards, and vice versa. '-R' does not modify the size of the blocks copied during each phase, just the order in which they are tried. '-s BYTES' '--size=BYTES' Maximum size of the rescue domain in bytes. It limits the amount of input data to be copied. -1 removes any previous size limit. In rescue mode, '--size=output' uses the size of the output file or device (for example to overwrite it). By default, ddrescue limits the amount of data to be copied to the size of the input file, but if ddrescue can't determine the size of the input file, you may need to specify it with this option. Note that this option does not specify the size of the resulting OUTFILE. 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 mapfile '-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. Use this option only with an empty or zeroed OUTFILE because if a block in OUTFILE contains nonzero data, it won't be overwritten by a corresponding block of zeros in INFILE, resulting in a corrupt copy. '-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 an integer or 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. INTERVAL has a resolution of one second; fractions of a second are not allowed. *Note --max-read-errors::. '-u' '--unidirectional' Run all passes in the same direction. Forwards by default, or backwards if the option '--reverse' is also given. '-v' '--verbose' Verbose mode. Further -v's (up to 4) increase the verbosity level. Some large numbers in messages (like device sizes) are printed in groups of 3 digits separated by underscore characters to make them more readable. '-w' '--ignore-write-errors' Make fill mode ignore write errors. This is useful to avoid ddrescue exiting because of new bad sectors 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. Note that in rescue mode a write error is fatal, which means that the rescue needs to be repeated or else OUTFILE needs to be copied to a third drive using MAPFILE as domain. *Note --domain-mapfile::. '-W' '--compare-before-write' Omit superfluous writes in rescue mode. Before writing each block of data to OUTFILE, compare the data already present there with the data about to be written and, if they match, omit the write. Possible advantages are that on some devices reads are faster than writes and it may reduce wear when writing to a solid state device. '-x BYTES' '--extend-outfile=BYTES' Extend the size of OUTFILE to make it at least BYTES long. If BYTES is 0, extend the size of OUTFILE to that of INFILE. If the size of OUTFILE is already equal or longer than BYTES or the size of INFILE, then this option does nothing. Use this option to guarantee a minimum size for OUTFILE. Only regular files can be extended. '-X N' '--max-read-errors=N' Maximum number of read errors allowed before giving up. Defaults to infinity. Exit with status 1 if more than N read errors are encountered. '--max-read-errors=0' is similar but different to '--timeout=0', which waits until the screen status is refreshed (at least 1 second). If there is at least one successful read per second, '--timeout=0' does not make ddrescue to exit. *Note --timeout::. '--max-read-errors=0' is also similar but different to '--max-bad-areas=+0', which exits when a new bad area is found. If the read errors are adjacent to existing bad areas, no new bad areas are produced (just enlarged), and '--max-bad-areas=+0' does not make ddrescue to exit. *Note --max-bad-areas::. '-y' '--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. Use it to make sure that all writes have been committed to disc when ddrescue finishes. Else the kernel may cache all the writes and pretend that it has finished. '-Z BYTES' '--max-read-rate=BYTES' Maximum read rate, in bytes per second. If BYTES is too small, the actual read rate is rounded up to the equivalent of a whole number of cluster reads per second. Use this option to limit the bandwidth used by ddrescue, for example when recovering over a network. '--ask' Ask for user confirmation before starting the copy. If the first letter of the answer is 'y', ddrescue starts copying. Else it exits with status 1. If they can be obtained, ddrescue shows the model and serial number of the input and output devices. Ddrescue also shows the size in bytes of the corresponding file or device if it exists. The format used is [MODEL::SERIAL_NUMBER] (SIZE) '--bad-sector-data=FILE' Treat as a read error any sector containing the same data as FILE. If FILE is larger than the sector size, the rest of FILE is discarded. This option is useful when the drive, instead of signaling a read error, returns known garbage data (different for each drive model). If you need to use this option, it means that the failing drive lacks adequate integrity checking. Better avoid such drives. '--command-mode' Read commands from the standard input and execute them, copying parts of the input file on demand. Command-line arguments controling the display (like '--data-preview') or the automatic algorithm (like '--max-errors' or '--reverse') have no effect in command mode. *Note Command mode::, for a complete description of the command mode. '--continue-on-errno=CODE[,CODE]...' Treat errno code CODE as non-fatal. This option may be useful on systems that incorrectly return fatal errno codes for non-fatal errors. If ddrescue exits because of a fatal read error, it prints in the final message the value of the variable 'errno', which can then be used as argument to this option. Multiple errno values may be specified with cumulative effect, either in the same argument, or by specifying multiple instances of this option. The option '--reopen-on-error' may be needed when using this option. *Note --reopen-on-error::. '--cpass=RANGE' Select what pass(es) to run during the copying phase. Valid pass values range from 1 to 4. To run only the given pass(es), specify also '--no-trim', '--no-sweep', and '--no-scrape'. '--cpass=0' skips the copying phase entirely. Examples of RANGE Passes run ------------------------------- 1 1 1,2,3 1, 2, 3 2-4 2, 3, 4 '--delay-slow=INTERVAL' Initial delay before ddrescue starts checking for slow reads. Defaults to 30 seconds. INTERVAL is formatted as in the option '--timeout' above. *Note --timeout::. '--log-events=FILE' Log all significant events (start of each pass and end of run) in FILE. If FILE already exists, the new events are appended at the end of FILE. For each event two lines are printed containing a time stamp, the amount of data rescued, and a message describing the event. The 'end of run' line also contains the current position and status. If ddrescue exits because of an error or interruption, the cause is also logged in FILE. '--log-rates=FILE' Log rates and error sizes every second in FILE. If FILE already exists, it is overwritten. Every time the screen is updated with new details, some of those details (time, input position, current and average rates, number of bad areas, and total error size) are written to FILE in a format usable by plotting utilities like gnuplot. This allows a posterior analysis of the drive to see if it has any weak zones (areas where the transfer rate drops well below the sustained average). '--log-reads=FILE' Log all read operations in FILE. If FILE already exists, it is overwritten. Every read attempt and its result (position, size, copied size, error size, and errno (if different from EIO)) is written to FILE. (The position written is always the beginning of the block tried, even if reading backwards). A line is also written at the beginning of each phase (copying, trimming, sweeping, scraping, and retrying). Finally, a line with a time mark is written every second (unless the read takes more time). Use this option with caution because FILE may become very large very quickly. Use lzip to compress FILE if you need to store or transmit it. '--mapfile-interval=[SAVE_INTERVAL][,SYNC_INTERVAL]' Change the interval at which ddrescue saves and fsyncs the MAPFILE. At least one of SAVE_INTERVAL or SYNC_INTERVAL must be specified. A SAVE_INTERVAL of -1 chooses the default automatic interval (from 30 seconds to 5 minutes depending on mapfile size). A SAVE_INTERVAL of 0 saves the MAPFILE after every read (use with caution). SYNC_INTERVAL is the interval between fsync calls. Default SYNC_INTERVAL is 5 minutes. Minimum SYNC_INTERVAL is 5 seconds. SYNC_INTERVAL must be greater or equal than SAVE_INTERVAL. Intervals are formatted as in the option '--timeout' above. *Note --timeout::. In practice, fsyncs are a subset of saves. I.e., some of the times when the MAPFILE is saved, it is also fsync'ed. Therefore, '--mapfile-interval=30,45' is really '--mapfile-interval=30,60'. The time needed to write the MAPFILE is excluded from the mapfile save and sync intervals. (Some mapfiles may take several seconds to write). '--max-slow-reads=N' Maximum number of slow reads allowed before giving up. Defaults to infinity. Exit with status 1 if more than N slow reads are encountered during the first two passes of the copying phase. Only works if a minimum read rate has been set with '--min-read-rate'. *Note --min-read-rate::. '--pause-on-error=INTERVAL' Time to wait after each read error. Also after each slow read if a minimum read rate has been set with '--min-read-rate'. Defaults to 0. INTERVAL is formatted as in the option '--timeout' above. If INTERVAL begins with 's', the pause is simulated and INTERVAL can be smaller than one second; the time displayed is increased by INTERVAL but without performing any pause. Pause simulation can be useful in combination with '--test-mode' for testing purposes. *Note --min-read-rate::, *note --test-mode::, *note --timeout::. '--pause-on-pass=INTERVAL' Time to wait between passes. Defaults to 0. INTERVAL is formatted as in the option '--timeout' above. *Note --timeout::. '--reset-slow' Reset the slow reads counter every time the read rate reaches or surpasses '--min-read-rate'. With this option, ddrescue only exits after the read rate has remained below '--min-read-rate' for at least as many seconds as the argument given to '--max-slow-reads'. *Note --min-read-rate::, *note --max-slow-reads::. '--same-file' Allow INFILE and OUTFILE to be the same file or device. This may be used to test the writing ability of a drive. It may also be used to copy part of a file to another location inside or beyond the end of the same file by setting different values for '--input-position' and '--output-position'. If the data to be copied overlap with the destination, the right copying direction must be chosen to avoid overwriting the overlapping part before it is copied. Numbers given as arguments to options (positions, sizes, rates, etc) may be expressed as decimal, hexadecimal, or octal values (using the same syntax as integer constants in C++), may contain underscore separators between groups of 3 or more digits (2 or more digits for hexadecimal), and may be followed by a multiplier and an optional 'B' for "byte". (1_234_567kB, 4Kis, 0x1234_5678, 07_777_777). The 's' multiplier may be appended to any of the other multipliers. For example, 'ks' means kilosectors (1000 * sector_size), and 'Kis' means kibisectors (1024 * sector_size). 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) R ronnabyte (10^27) | Ri robibyte (2^90) Q quettabyte (10^30) | Qi quebibyte (2^100) Exit status: 0 for a normal exit, 1 for environmental problems (file not found, invalid command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., bug) which caused ddrescue to panic. If ddrescue is interrupted by a signal, it updates MAPFILE and then terminates by raising the signal received.  File: ddrescue.info, Node: Argument syntax, Next: Mapfile structure, Prev: Invoking ddrescue, Up: Top 7 Syntax of command-line arguments ********************************** POSIX recommends these conventions for command-line arguments. * A command-line argument is an option if it begins with a hyphen ('-'). * Option names are single alphanumeric characters. * Certain options require an argument. * An option and its argument may or may not appear as separate tokens. (In other words, the whitespace separating them is optional). Thus, '-o foo' and '-ofoo' are equivalent. * One or more options without arguments, followed by at most one option that takes an argument, may follow a hyphen in a single token. Thus, '-abc' is equivalent to '-a -b -c'. * Options typically precede other non-option arguments. * The argument '--' terminates all options; any following arguments are treated as non-option arguments, even if they begin with a hyphen. * A token consisting of a single hyphen character is interpreted as an ordinary non-option argument. By convention, it is used to specify standard input, standard output, or a file named '-'. GNU adds "long options" to these conventions: * A long option consists of two hyphens ('--') followed by a name made of alphanumeric characters and hyphens. Option names are typically one to three words long, with hyphens to separate words. Abbreviations can be used for the long option names as long as the abbreviations are unique. * A long option and its argument may or may not appear as separate tokens. In the latter case they must be separated by an equal sign '='. Thus, '--foo bar' and '--foo=bar' are equivalent. The syntax of options with an optional argument is '-' (without whitespace), or '--='.  File: ddrescue.info, Node: Mapfile structure, Next: Emergency save, Prev: Argument syntax, Up: Top 8 Mapfile structure ******************* NOTE: In versions of ddrescue prior to 1.20 the mapfile was called 'logfile'. The format is the same; only the name has changed. The mapfile 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. The character '#' at begin of line or after whitespace starts a comment that extends to the end of the line. The heading comments contain the version of ddrescue or ddrescuelog that created the mapfile, the command line used, and the time when the program started. If the mapfile was created by ddrescue it also contains the current time when the mapfile was saved and a copy of the status message from the screen describing the operation being performed (copying, trimming, finished, etc). They are intended as information for the user. The first non-comment line is the status line. It contains a non-negative integer, a status character, and a positive decimal integer. The first integer is the position being tried in the input file. (The beginning of the block being tried in a forward pass or the end of the block in a backward pass). The status character is one of these: Character Meaning ------------------------------------------- '?' copying non-tried blocks '*' trimming non-trimmed blocks '%' sweeping non-tried blocks '/' scraping non-scraped blocks '-' retrying bad sectors 'F' filling the blocks specified 'G' generating approximate mapfile '+' finished Finally, the last integer is the number of the current pass in the current phase. The status line allows ddrescue to resume the copying phase instead of restarting it from pass 1. It also allows the retrying phase to resume in the same direction it was interrupted. 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-scraped '-' failed block bad-sector(s) '+' finished block And here is an example mapfile: # Mapfile. Created by GNU ddrescue version 1.30 # Command line: ddrescue -d -c18 /dev/fd0 fdimage mapfile # Start time: 2015-07-21 09:37:44 # Current time: 2015-07-21 09:38:19 # Copying non-tried blocks... Pass 1 (forwards) # current_pos current_status current_pass 0x00120000 ? 1 # 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 as integer constants in C++, except for current_pass, which must be a decimal integer.  File: ddrescue.info, Node: Emergency save, Next: Optical media, Prev: Mapfile structure, Up: Top 9 Saving the mapfile in case of trouble *************************************** The mapfile is an essential part of ddrescue's effectiveness. Without a mapfile, ddrescue can't resume a rescue, only reinitiate it. Given that a difficult rescue may take days to complete, it would be a serious drawback if the mapfile were lost because of a solvable problem like a lack of space on the device the mapfile is written to. In case of trouble writing the mapfile, ddrescue prints a message like this: Error writing mapfile 'MAPFILE': No space left on device Fix the problem and press ENTER to retry, or E+ENTER for an emergency save and exit, or Q+ENTER to abort. You may try to fix the problem, for example deleting some files to make room for the mapfile, and press to retry. If the problem can't be fixed, you may press followed by to try an emergency save and exit. Ddrescue tries to write the mapfile to the file 'ddrescue.map' in the current directory or, if this fails, to '$HOME/ddrescue.map'. If the mapfile is written successfully, ddrescue exits with status 1. Else it prints the above message again. Or you may press followed by to quit and exit with status 1. In this case the content of the mapfile is lost.  File: ddrescue.info, Node: Optical media, Next: Examples, Prev: Emergency save, Up: Top 10 Copying CD-ROMs and DVDs *************************** Ddrescue may be better than dd for copying recordable CD-ROMs because the two lead out sectors at the end of some of them may cause a read error that prevents the whole last record from being copied by dd, potentially losing data. Also dd may create an image larger than the original if the 'sync' conversion and a block size larger than the sector size are specified. In the special case of reading CD-ROMs (but not DVDs), the specialized tool dvdisaster may be a better option than ddrescue for recovering data because dvdisaster can read and analyze raw CD sectors, which ddrescue can't. Recordable CD and DVD media keep their data only for a finite time (typically for some years). After that time, data loss develops slowly with read errors growing from the outer region towards the inside. It is a good idea to make two (or more) copies of every important CD-ROM/DVD you burn so that you can later recover them with ddrescue. If you have only one copy of a CD-ROM or DVD that fails when being copied, and if you have access to multiple optical media drives, you have a better chance of recovering the bad sectors since one drive may fail to read a particular sector, but another drive might be able to squeeze the data out of it, depending on the laser frequency and the sensitivity of the laser-sensor that reads the reflected laser light. Example 1: Rescue a CD-ROM in '/dev/cdrom'. ddrescue -n -b2048 /dev/cdrom cdimage mapfile ddrescue -d -r1 -b2048 /dev/cdrom cdimage mapfile (if bad-sector size is zero, cdimage now contains a complete image of the CD-ROM and you can write it to a blank CD-ROM) Example 2: Rescue a CD-ROM in '/dev/cdrom' from two copies. ddrescue -n -b2048 /dev/cdrom cdimage mapfile ddrescue -d -b2048 /dev/cdrom cdimage mapfile (insert second copy in the CD drive) ddrescue -d -r1 -b2048 /dev/cdrom cdimage mapfile (if bad-sector size is zero, cdimage now contains a complete image of the CD-ROM and you can write it to a blank CD-ROM) Example 3: Rescue a CD-ROM in '/dev/cdrom' using two CD drives from two different computers, writing the image into an USB drive mounted on '/mnt/mem'. ddrescue -n -b2048 /dev/cdrom /mnt/mem/cdimage /mnt/mem/mapfile ddrescue -d -r1 -b2048 /dev/cdrom /mnt/mem/cdimage /mnt/mem/mapfile (umount the USB drive and move both USB drive and CD-ROM to second computer) ddrescue -d -r1 -b2048 /dev/cdrom /mnt/mem/cdimage /mnt/mem/mapfile (if bad-sector size is zero, /mnt/mem/cdimage now contains a complete image of the CD-ROM and you can write it to a blank CD-ROM) Example 4: Merge the partially recovered images of 3 identical DVDs using their mapfiles as domain mapfiles. ddrescue -m mapfile1 dvdimage1 dvdimage mapfile ddrescue -m mapfile2 dvdimage2 dvdimage mapfile ddrescue -m mapfile3 dvdimage3 dvdimage mapfile (if bad-sector size is zero, dvdimage now contains a complete image of the DVD and you can write it to a blank DVD) Example 5: Recover a lzip compressed backup from two copies on CD-ROM with error-checked merging of copies. ddrescue -d -r1 -b2048 /dev/cdrom cdimage1 mapfile1 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 -d -r1 -b2048 /dev/cdrom cdimage2 mapfile2 mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz umount /mnt/cdimage lziprecover -v -m -o backup.tar.lz rescued1.tar.lz rescued2.tar.lz Input files merged successfully. lziprecover -tv backup.tar.lz backup.tar.lz: ok  File: ddrescue.info, Node: Examples, Next: Direct disc access, Prev: Optical media, Up: Top 11 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 are 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 appropriate 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. *Note Optical media::, for rescue examples of CD-ROMs and DVDs. Example 1: Fully automatic rescue of a whole disc with two ext2 partitions in '/dev/sda' to '/dev/sdb'. Note: you don't need to partition '/dev/sdb' beforehand, but if the partition table on '/dev/sda' is damaged, you'll need to recreate it somehow on '/dev/sdb'. ddrescue -f -r3 /dev/sda /dev/sdb mapfile fdisk /dev/sdb e2fsck -v -f /dev/sdb1 e2fsck -v -f /dev/sdb2 Example 2: Rescue an ext2 partition in '/dev/sda2' to '/dev/sdb2'. Note: you need to create the partition sdb2 with fdisk first. sdb2 should be of appropriate type and size. ddrescue -f -n /dev/sda2 /dev/sdb2 mapfile ddrescue -d -f -r3 /dev/sda2 /dev/sdb2 mapfile e2fsck -v -f /dev/sdb2 mount -t ext2 -o ro /dev/sdb2 /mnt (read rescued files from /mnt) Example 3: While rescuing the whole drive '/dev/sda' to '/dev/sdb', '/dev/sda' freezes up at position 12_345_678. ddrescue -f /dev/sda /dev/sdb mapfile # /dev/sda freezes here (restart /dev/sda or reboot computer) (restart copy at a safe distance from the troubled sector) ddrescue -f -i 12350000 /dev/sda /dev/sdb mapfile (then copy backwards down to the troubled sector) ddrescue -f -R /dev/sda /dev/sdb mapfile Example 4: While rescuing the whole drive '/dev/sda' to '/dev/sdb', '/dev/sdb' fails and you have to rescue the data to a third drive, '/dev/sdc'. ddrescue -f -n /dev/sda /dev/sdb mapfile1 # /dev/sdb fails here ddrescue -f -m mapfile1 /dev/sdb /dev/sdc mapfile2 ddrescue -f -n /dev/sda /dev/sdc mapfile2 ddrescue -d -f -r3 /dev/sda /dev/sdc mapfile2 Example 5: While rescuing a partition in '/dev/sda1' to the file 'hdimage', '/dev/sda1' stops responding and begins returning read errors, causing ddrescue to mark the rest of the partition as non-scraped. ddrescue -n /dev/sda1 hdimage mapfile # /dev/sda1 fails here (restart /dev/sda or reboot computer) ddrescue -n -A -i -O /dev/sda1 hdimage mapfile (if /dev/sda1 fails again, restart /dev/sda or reboot computer and then repeat the above command as many times as needed until it succeeds. is the position where the drive stopped responding) ddrescue -d -r3 /dev/sda1 hdimage mapfile Example 6: While rescuing a partition in '/dev/sda1' to the file 'hdimage', sda1 disappears from '/dev'. ddrescue -n /dev/sda1 hdimage mapfile # /dev/sda1 fails here (restart /dev/sda or reboot computer and then repeat the above command as many times as needed until it succeeds) ddrescue -d -r3 /dev/sda1 hdimage mapfile Example 7: While rescuing a partition in '/dev/sda1' to the file 'hdimage', the partition table of '/dev/sda' becomes unreadable and the OS no longer shows sda1 in '/dev'. The solution is to shift the mapfile and read the rest of the partition sda1 from '/dev/sda'. Note: you need to know the offset of the partition sda1 in the drive sda and the size of sda1. ddrescue /dev/sda1 hdimage mapfile # partition table fails here ddrescuelog --shift -o mapfile > shifted_mapfile ddrescue -i -o0 -s /dev/sda hdimage shifted_mapfile Example 8: After rescuing a partition in '/dev/sda1' to the file 'hdimage', expand 'hdimage' to copy the whole drive in '/dev/sda' without recopying the already copied partition '/dev/sda1'. The solution is to shift the mapfile, move the data of sda1 to its final position in 'hdimage', and then read the rest of the data from '/dev/sda'. Note: you need to know the offset of the partition sda1 in the drive sda and the size of sda1. ddrescue /dev/sda1 hdimage mapfile # rescue partition ddrescuelog --shift -o mapfile > shifted_mapfile ddrescue --same-file -o -s --reverse hdimage hdimage ddrescue /dev/sda hdimage shifted_mapfile # rescue rest of drive Example 9: Recover a collection of photos from a damaged external drive ('/dev/sdc1'). The photos are protected with forward error correction (fec) files created by lziprecover. The photos are in directory 'photos', and the fec files are in directory 'photos-fec'. ddrescue -b4096 -r10 /dev/sdc1 hdimage mapfile mount -o loop,ro hdimage /mnt/hdimage cp -a /mnt/hdimage/photos photos cp -a /mnt/hdimage/photos-fec photos-fec umount /mnt/hdimage lziprecover -v -Fr --fec-file=photos-fec/ photos/* (Check and rename repaired files. They are named 'photos/*_fixed') Example 10: Recover a damaged tar.lz backup using the recovery record appended to the backup itself. The damaged backup comes from a damaged partition copied with ddrescue. ddrescue -b4096 -r10 /dev/sdc1 hdimage mapfile mount -o loop,ro hdimage /mnt/hdimage cp /mnt/hdimage/backup.tar.lz backup.tar.lz umount /mnt/hdimage lzip -t backup.tar.lz backup.tar.lz: Decoder error at pos 1_020_530 lziprecover --dump=tdata backup.tar.lz | \ lziprecover -v -Fr --fec-file=- backup.tar.lz Example 11: Recover a damaged tar.lz backup with a zeroed sector of 4096 bytes at file position 1_019_904, using as reference a previous backup. The damaged backup comes from a damaged partition copied with ddrescue. ddrescue -b4096 -r10 /dev/sdc1 hdimage mapfile mount -o loop,ro hdimage /mnt/hdimage cp /mnt/hdimage/backup.tar.lz backup.tar.lz umount /mnt/hdimage lzip -t backup.tar.lz backup.tar.lz: Decoder error at pos 1_020_530 lziprecover -vv -e --reference-file=old_backup.tar backup.tar.lz Reproducing bad area in member 1 of 1 (begin = 1_019_904, size = 4096, value = 0x00) (master mpos = 1_019_903, dpos = 5_857_954) warning: old_backup.tar: Partial match found at offset 5_743_778, len 9546 Reference data may be mixed with other data. Trying level -9 Reproducing position 1_015_808 Member reproduced successfully. Copy of input file reproduced successfully.  File: ddrescue.info, Node: Direct disc access, Next: Command mode, Prev: Examples, Up: Top 12 Direct disc access ********************* If you notice that the positions and sizes in MAPFILE 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 for INFILE, or read from a raw device, to bypass the kernel cache and rescue more of your data. NOTE! Sector size must be correctly set with the option '--sector-size' for direct disc access to work. NOTE: Direct disc access can copy arbitrary domains by reading whole sectors and then writing only the requested part. This is the only case where ddrescue tries to read data outside the rescue domain. Try the option '--idirect' 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 especial 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 option '--size' or '--complete-only' 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/sdb1 /dev/sdc1 mapfile ddrescue -d -f -r3 /dev/sdb1 /dev/sdc1 mapfile e2fsck -v -f /dev/sdc1 mount -t ext2 -o ro /dev/sdc1 /mnt Example 2: using a raw device. raw /dev/raw/raw1 /dev/sdb1 ddrescue -f -n /dev/sdb1 /dev/sdc1 mapfile ddrescue -C -f -r3 /dev/raw/raw1 /dev/sdc1 mapfile raw /dev/raw/raw1 0 0 e2fsck -v -f /dev/sdc1 mount -t ext2 -o ro /dev/sdc1 /mnt  File: ddrescue.info, Node: Command mode, Next: Fill mode, Prev: Direct disc access, Up: Top 13 Copying parts of the input file on demand ******************************************** The command mode of ddrescue implements a scripting interface similar to the one of ed. *Note ed manual: (ed)Top. In this mode commands are read from the standard input and executed to copy parts of the input file to the output file, retrieve information from the mapfile, or write the mapfile to disc. Ddrescue's responses are written to standard output. "done\n" for a successfully executed command, "error\n" for a failed command (for example because of wrong arguments), and "error: ERROR MESSAGE\n" for serious or fatal errors like write errors. If end-of-file is detected on standard input, ddrescue discards any partial command being read and executes the 'f' (finish) command. All ddrescue commands are single characters, though some require additonal parameters separated by spaces. Only one command is allowed per line. Ddrescue recognizes the following commands: 'c POS SIZE' Copy command. Copies a block of data from INFILE to OUTFILE and updates the internal copy of the mapfile. The areas already marked as finished in the mapfile are not copied again. 'f' Finish command. Compacts the internal copy of the mapfile and writes it to MAPFILE (if it was specified in the command line). Then prints "done\n" to standard output and quits. On startup, the mapfile is first compacted and then split following the rescue domain borders. The finish command compacts the mapfile again before exiting. If writing MAPFILE to disc fails, a non-interactive emergency save is tried before exiting. *Note Emergency save::. 'q' Quit command. Exits ddrescue. Does not update the mapfile. 's POS SIZE' Status command. Writes to standard output one or more lines in mapfile format (*note Mapfile structure::), showing the status of the areas included in the block requested. A line consisting of the string "done" marks the end of the list. 'u' Update mapfile command. Writes the internal copy of the mapfile to MAPFILE (if it was specified in the command line). If update mapfile fails, you may try to fix the problem, for example deleting some files to make room for MAPFILE, before trying to update it again.  File: ddrescue.info, Node: Fill mode, Next: Generate mode, Prev: Command mode, Up: Top 14 Fill mode ************ When ddrescue is invoked with the option '--fill-mode' it operates in 'fill mode', which is different from the default 'rescue mode'. That is, in 'fill mode' ddrescue does not rescue anything. It only fills with data read from INFILE the blocks of OUTFILE whose status character from MAPFILE coincides with one of the type characters specified in the argument to '--fill-mode'. If the argument to '--fill-mode' contains an 'l', ddrescue writes location data (position, sector number, and status) into each sector filled. With bad sectors filled in this way, it should be possible to retry the recovery of important files, as the location of the error is known by looking into the unfinished copy of the file. In fill mode INFILE does not need to be seekable and it may be of any size. If it is too small, the data is 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 is read. Then the same data is written to every cluster or sector to be filled. Note that in fill mode INFILE is always read from position 0. If you specify a '--input-position', it refers to the original INFILE from which MAPFILE was built, and is only used to calculate the offset between input and output positions. Note also that when filling the INFILE of the original rescue run you should not set '--output-position', whereas when filling the OUTFILE of the original rescue run you should keep the original offset between '--input-position' and '--output-position'. The option '--fill-mode' implies '--complete-only'. In fill mode MAPFILE is updated to allow resumability when interrupted or in case of a crash, but as nothing is being rescued MAPFILE is not destroyed. The status line is the only part of MAPFILE 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 ': ddrescue --fill-mode=- <(printf "BAD-SECTOR ") outfile mapfile And the following command line fills all the non-finished areas in the destination file with copies of the string 'NON-RESCUED-SECTOR ': ddrescue --fill-mode='?*/-' <(printf "NON-RESCUED-SECTOR ") outfile mapfile Example 2: Wipe only the good sectors, leaving the bad sectors alone. This way, the drive still tests bad (i.e., with unreadable sectors). This is the fastest way of wiping a failing drive, and is especially useful when sending the drive back to the manufacturer for warranty replacement. ddrescue --fill-mode=+ --force /dev/zero bad_drive mapfile 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=- -f --synchronous /dev/zero bad_drive mapfile 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. Don't use sparse writes. This yields a mapfile containing 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". Use '--fill-mode=l-' if you want location data. 3) Mount the copied drive (or the image file, via loopback device) read-only. 4) Grep for the fill string in all the files. Those files containing the string reside (at least partially) in damaged disc areas. Note that if all the damaged areas are in unused space, grep does not find the string in any file, which means that no files are damaged. 5) Take note of the location data of any important files that you want to retry. 6) Unmount the copied drive or image file. 7) Retry the sectors belonging to the important files until they are rescued or until it is clear that they can't be rescued. 8) 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 mapfile printf "DEADBEEF" > tmpfile ddrescue --fill-mode=l- tmpfile cdimage mapfile rm tmpfile mount -t iso9660 -o loop,ro cdimage /mnt/cdimage find /mnt/cdimage -type f -exec grep -l "DEADBEEF" '{}' ';' (note that my_thesis.txt has a bad sector at pos 0x1234_5000) umount /mnt/cdimage ddrescue -b2048 -i0x1234_5000 -s2048 -dr9 /dev/cdrom cdimage mapfile ddrescue --fill-mode=- /dev/zero cdimage mapfile mount -t iso9660 -o loop,ro cdimage /mnt/cdimage cp -a /mnt/cdimage/my_thesis.txt /safe/place/my_thesis.txt  File: ddrescue.info, Node: Generate mode, Next: Ddrescuelog, Prev: Fill mode, Up: Top 15 Generate mode **************** When ddrescue is invoked with the option '--generate-mode' it operates in 'generate mode', which is different from the default 'rescue mode'. That is, in 'generate mode' ddrescue does not rescue anything. It only tries to generate a MAPFILE for later use. So you didn't read the manual and started ddrescue without a MAPFILE. 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 MAPFILE, from INFILE and the (partial) copy in OUTFILE, that is almost as good as an exact MAPFILE. 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 MAPFILE, 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 nonzero. 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 mapfile with this command: ddrescue --generate-mode infile outfile mapfile 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 16 Ddrescuelog ************** Ddrescuelog is a tool that manipulates ddrescue mapfiles, shows mapfile contents, converts mapfiles to/from other formats, compares mapfiles, tests rescue status, and can delete a mapfile if the rescue is done. Ddrescuelog operations can be restricted to one or several parts of the mapfile if the domain setting options are used. When performing logic operations (AND, OR, XOR) on mapfiles of different extension, only the blocks present in both files are processed. Other blocks are left untouched. Here are some examples of how to use ddrescuelog, alone or in combination with other tools. Example 1: Delete the mapfile if the rescue is finished (all data have been recovered without errors left). ddrescue -f /dev/sda /dev/sdb mapfile ddrescuelog -d mapfile Example 2: Rescue two ext2 partitions in '/dev/sda' to '/dev/sdb' and repair the file systems using badblocks lists generated with ddrescuelog. File system block size is 4096. Note: you do need to partition '/dev/sdb' beforehand. fdisk /dev/sdb # partition /dev/sdb ddrescue -f /dev/sda1 /dev/sdb1 mapfile1 ddrescue -f /dev/sda2 /dev/sdb2 mapfile2 ddrescuelog -l- -b4096 mapfile1 > badblocks1 ddrescuelog -l- -b4096 mapfile2 > badblocks2 e2fsck -v -f -L badblocks1 /dev/sdb1 e2fsck -v -f -L badblocks2 /dev/sdb2 Example 3: Rescue a whole disc with two ext2 partitions in '/dev/sda' to '/dev/sdb' and repair the file systems using badblocks lists generated with ddrescuelog. Disc sector size is 512 (first '-b'), file system block size is 4096 (second '-b'). Arguments to options '-i' and '-s' are the starting positions and sizes of the partitions being rescued. Note: you don't need to partition '/dev/sdb' beforehand, but if the partition table on '/dev/sda' is damaged, you'll need to recreate it somehow on '/dev/sdb'. ddrescue -f /dev/sda /dev/sdb mapfile fdisk /dev/sdb # get partition sizes ddrescuelog -l- -b512 -i63s -o0 -s767457s -b4096 mapfile > badblocks1 ddrescuelog -l- -b512 -i767520s -o0 -s96520s -b4096 mapfile > badblocks2 e2fsck -v -f -L badblocks1 /dev/sdb1 e2fsck -v -f -L badblocks2 /dev/sdb2  File: ddrescue.info, Node: Invoking ddrescuelog, Next: Problems, Prev: Ddrescuelog, Up: Top 17 Invoking ddrescuelog *********************** The format for running ddrescuelog is: ddrescuelog [OPTIONS] MAPFILE Use a hyphen '-' as MAPFILE to read the mapfile from standard input (also in the options taking a mapfile argument) or to write the mapfile created by '--create-mapfile' to standard output. ddrescuelog supports the following options: *Note Argument syntax::. '-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. This version number should be included in all bug reports. '-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 command 'tr' does, and write the resulting mapfile to standard output. OLD_TYPES and NEW_TYPES are strings of block status characters as defined in the chapter Mapfile structure (*note Mapfile 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. '-A' '--annotate-mapfile' Add comments containing the human-readable positions and sizes of the blocks in MAPFILE which are included in the rescue domain, and write the resulting mapfile to standard output. '-b BYTES' '--block-size=BYTES' '--sector-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. The position of each option '-b' in the command line is significant; it changes the sector size for the following options until a new option '-b' appears in the command line. *Note double-b::. '-B' '--binary-prefixes' Show units with binary prefixes (powers of 1024). SI prefixes (powers of 1000) are used by default. (See table above, *note Invoking ddrescue::). '-c[TYPE1TYPE2]' '--create-mapfile[=TYPE1TYPE2]' Create a MAPFILE from a list of sectors read from standard input. The option '--format' determines the format of the input: either a list of sector numbers, or a bitmap. The sector numbers may be unordered. Only sectors included in the rescue domain are added to MAPFILE. If the mapfile is being created displaced from the input domain, the offset between '-i' and '-o' must be a multiple of the sector size. In this case, remember to specify '-o' because it defaults to the same value given to '-i', producing a default offset of 0. TYPE1 and TYPE2 are block status characters as defined in the chapter Mapfile structure (*note Mapfile structure::). TYPE1 sets the type for blocks included in the list, while TYPE2 sets the type for the rest of MAPFILE. If not specified, TYPE1 defaults to '+' and TYPE2 defaults to '-'. '-C[TYPE]' '--complete-mapfile[=TYPE]' Complete a synthetic (user fabricated) MAPFILE by filling the gaps with blocks of type TYPE, and write the completed mapfile to standard output. TYPE is one of the block status characters defined in the chapter Mapfile structure (*note Mapfile structure::). If TYPE is not specified, the gaps are filled with non-tried blocks. All gaps in MAPFILE are filled. Domain options are ignored. '-d' '--delete-if-done' Delete the given MAPFILE if all the blocks in the rescue domain have been successfully recovered. The exit status is 0 if MAPFILE could be deleted, 1 otherwise. If the mapfile is read from standard input, behave like '--done-status'. (There is nothing to delete). '-D' '--done-status' Test if all the blocks in the rescue domain have been successfully recovered. The exit status is 0 if all tested blocks are finished, 1 otherwise. '-f' '--force' Force overwrite of MAPFILE. '-F NAME' '--format=NAME' Select the input format for '--create-mapfile', or the output format for '--list-blocks'. The valid names are 'list', 'bitmap', 'bitmap-be' (big endian), and 'bitmap-le' (little endian). Plain 'bitmap' is equivalent to 'bitmap-le'. The default format is 'list' (a list of block numbers). In a big endian bitmap the first block is represented by the most significant bit of the first byte. In a little endian bitmap the first block is represented by the least significant bit of the first byte. '-H C:H:S:TRACK_ORDER:BAD_HEAD' '--make-test=C:H:S:TRACK_ORDER:BAD_HEAD' Create a domain mapfile simulating a failing head for the test mode of ddrescue. C:H:S means CYLINDERS:HEADS:SECTORS. For discs with variable number of sectors per track, S is specified as 'SECTORS_FIRST_TRACK-SECTORS_LAST_TRACK[,TRACKS_PER_ZONE]'. TRACK_ORDER is one of 'F' (forward), or 'FF' (hybrid serpentine). BAD_HEAD is a number in the range 0 to HEADS - 1. '-i BYTES' '--input-position=BYTES' Starting position of the rescue domain, in bytes. Defaults to 0. It refers to a position in the original INFILE. '-l TYPES' '--list-blocks=TYPES' By default print on standard output the sector numbers of the blocks specified as any of TYPES in MAPFILE and included in the rescue domain. The list format is one sector number per line in decimal, like the output of the program 'badblocks', so that it can be used as input for e2fsck or other similar filesystem repairing tool. If a bitmap '--format' is specified, write to standard output a bitmap of the endianness chosen, with ones for the sectors specified and zeros for sectors from other block types. The bits set to 1 in the bitmap should be equivalent to the list of blocks. TYPES contains one or more of the block status characters defined in the chapter Mapfile structure (*note Mapfile structure::). If the output numbers or bits are being created displaced from their position in the input domain, the offset between '-i' and '-o' must be a multiple of the block size. In this case, remember to specify '-o' because it defaults to the same value given to '-i', producing a default offset of 0. A sector is listed (or set to 1 in bitmap output) if selected, even partially. (The positions and sizes of the mapfile blocks are not required to be multiples of the sector size). '-L' '--loose-domain' Accept an incomplete synthetic (user fabricated) domain mapfile or compare-as-domain mapfile, and fill the gaps in the list of data blocks with non-tried blocks. The blocks in the mapfile may be unordered, may overlap other blocks of the same status, and don't need to be contiguous. This option allows making quick edits to a mapfile without all the size calculations involved in making all data blocks contiguous again. '-m FILE' '--domain-mapfile=FILE' Restrict the rescue domain to the blocks marked as finished in the mapfile FILE. '-n' '--invert-mapfile' Invert the types of the blocks in MAPFILE which are included in the rescue domain, and write the resulting mapfile to standard output. Finished blocks ('+') are changed to bad-sector ('-'), all other types are changed to finished. '--invert-mapfile' is equivalent to '--change-types=?*/-+,++++-' '-o BYTES' '--output-position=BYTES' Starting position of the image of the rescue domain in the original OUTFILE, in bytes. It is used by the options '--create-mapfile', '--list-blocks', and '--shift'. Defaults to '--input-position'. '-p FILE' '--compare-mapfile=FILE' Compare the types of the blocks included in the rescue domain. The exit status is 0 if all the blocks tested are the same in both FILE and MAPFILE, 1 otherwise. '-P FILE' '--compare-as-domain=FILE' Compare only the blocks marked as finished in the rescue domain. The exit status is 0 if all the blocks tested are the same in both FILE and MAPFILE, 1 otherwise. Two files comparing equal with this option are equivalent when used as domain mapfiles. '-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 INFILE. -1 removes any previous size limit. '-t' '--show-status' Print a summary of the contents of each MAPFILE to the standard output. This option allows more than one MAPFILE. If the domain setting options are used, the summary can be restricted to one or several parts of MAPFILE. '-v' '--verbose' Verbose mode. Further -v's (up to 4) increase the verbosity level. '-x FILE' '--xor-mapfile=FILE' Perform a logical XOR (exclusive OR) operation between the finished blocks in FILE and those in MAPFILE, and write the resulting mapfile to standard output. In other words, in the resulting mapfile a block is only shown as finished if it was finished in either of the two input mapfiles but not in both. '-y FILE' '--and-mapfile=FILE' Perform a logical AND operation between the finished blocks in FILE and those in MAPFILE, and write the resulting mapfile to standard output. In other words, in the resulting mapfile a block is only shown as finished if it was finished in both input mapfiles. '-z FILE' '--or-mapfile=FILE' Perform a logical OR operation between the finished blocks in FILE and those in MAPFILE, and write the resulting mapfile to standard output. In other words, in the resulting mapfile a block is shown as finished if it was finished in either of the two input mapfiles. '--shift' Shift the positions of all the blocks in MAPFILE by the offset ('--output-position' - '--input-position'), and write the resulting mapfile to standard output. Either '--input-position' or '--output-position' must be 0. Any blocks beyond the end of the rescue domain are removed before performing the shift. The remaining blocks are shifted even if they are outside the rescue domain. If the offset is positive, a non-tried block is inserted before the first block to fill the gap. Exit status: 0 for a normal exit, 1 for environmental problems (file not found, invalid command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., bug) which caused ddrescuelog to panic.  File: ddrescue.info, Node: Problems, Next: Concept index, Prev: Invoking ddrescuelog, Up: Top 18 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) * argument syntax: Argument syntax. (line 6) * basic concepts: Basic concepts. (line 6) * bugs: Problems. (line 6) * command mode: Command mode. (line 6) * ddrescuelog: Ddrescuelog. (line 6) * direct disc access: Direct disc access. (line 6) * emergency save: Emergency save. (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) * lzip: Introduction. (line 31) * mapfile structure: Mapfile structure. (line 6) * optical media: Optical media. (line 6) * options: Invoking ddrescue. (line 6) * output: Output. (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: Top201 Node: Introduction1629 Node: Basic concepts5013 Node: Important advice7363 Node: Algorithm9416 Node: Output16543 Node: Invoking ddrescue20995 Ref: --min-read-rate22081 Ref: --max-bad-areas25800 Ref: --max-error-rate26086 Ref: --test-mode27582 Ref: --domain-mapfile31401 Ref: --retrim32398 Ref: --reopen-on-error33269 Ref: --timeout36863 Ref: --max-read-errors39138 Ref: --continue-on-errno41852 Ref: --mapfile-interval44852 Ref: --max-slow-reads45900 Ref: --pause-on-error46231 Node: Argument syntax49671 Node: Mapfile structure51582 Node: Emergency save54862 Node: Optical media56286 Ref: lziprecover example159487 Node: Examples60189 Ref: lziprecover example265846 Ref: lziprecover example366448 Ref: lziprecover example466974 Node: Direct disc access67935 Node: Command mode70140 Node: Fill mode72540 Node: Generate mode77717 Node: Ddrescuelog79616 Ref: double-b81113 Node: Invoking ddrescuelog81981 Node: Problems92720 Node: Concept index93274  End Tag Table  Local Variables: coding: iso-8859-15 End: gddrescue-1.30/doc/ddrescue.texi000066400000000000000000002722051512716454500166620ustar00rootroot00000000000000\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 1 January 2026 @set VERSION 1.30 @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 @ifnottex @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 * Output:: Meaning of ddrescue's screen output * Invoking ddrescue:: Command-line interface * Argument syntax:: By convention, options start with a hyphen * Mapfile structure:: Detailed format of the mapfile * Emergency save:: Saving the mapfile in case of trouble * Optical media:: Copying CD-ROMs and DVDs * Examples:: A small tutorial with examples * Direct disc access:: Bypassing the kernel cache * Command mode:: Copying parts of the input file on demand * Fill mode:: Selectively overwriting the output file * Generate mode:: Generating an approximate mapfile * Ddrescuelog:: Tool for ddrescue mapfiles * Invoking ddrescuelog:: Command-line interface * Problems:: Reporting bugs * Concept index:: Index of concepts @end menu @sp 1 Copyright @copyright{} 2004-2026 Antonio Diaz Diaz. This manual is free documentation: you have unlimited permission to copy, distribute, and modify it. @end ifnottex @node Introduction @chapter Introduction @cindex introduction @uref{http://www.gnu.org/software/ddrescue/ddrescue.html,,GNU ddrescue} is a data recovery tool. It copies data from one file or block device (hard disc, cdrom, etc) to another, trying to rescue the good parts first 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, restart it from a new position, etc. If you use the mapfile feature of ddrescue, the data are rescued efficiently, (only the blocks needed are read). Also you may interrupt the rescue at any time and resume it later at the same point. The mapfile is an essential part of ddrescue's effectiveness. Use it unless you know what you are doing. 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 the same area damaged in all copies is low (if the errors are randomly located). Using the mapfile, only the blocks needed are read from the second and successive copies. @cindex lzip Ddrescue recommends @uref{http://www.nongnu.org/lzip/lzip.html,,lzip} for compression of backups because the lzip format is designed for long-term archiving and provides data recovery capabilities which nicely complement those of ddrescue. (Ddrescue reads as many sectors as it can, while lziprecover uses other data to repair the sectors that ddrescue was not able to read). Lziprecover's FEC algorithm can repair any kind of file, but its ability to repair lzip files is greater than for other kinds of files. Lziprecover can use the statistical properties of lzip data to repair a lzip file rescued with ddrescue, even if the fec file is so damaged that it has lost both CRC arrays. Lziprecover @uref{http://www.nongnu.org/lzip/manual/lziprecover_manual.html#Fec-files,, fec files} can be used as recovery record for tar.lz archives. If the cause of file corruption is a damaged medium, the combination @w{ddrescue + @uref{http://www.nongnu.org/lzip/lziprecover.html,,lziprecover}} is the recommended option for recovering data from damaged files. @xref{lziprecover example1}, @ref{lziprecover example2}, @ref{lziprecover example3}, and @ref{lziprecover example4}, for examples. @ifnothtml @xref{Top,lziprecover manual,,lziprecover}, for details about lziprecover. @end ifnothtml Because ddrescue needs to read and write at random places, it only works on seekable (random access) input and output files. Therefore, the only way of creating a compressed image with ddrescue is to create a normal (uncompressed) image first, and then compress that image. If your system supports it, ddrescue can use direct disc access to read the input file, bypassing the kernel cache. One of the strengths of ddrescue is that it is interface-agnostic, and so can be used for any kind of device supported by your kernel (ATA, SATA, SCSI, old MFM drives, floppy discs, or even flash media cards like SD). 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. The starting position (or beginning position) is the lowest position in the block. The end of the block is its starting position plus 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. @file{/dev/hda}, @file{/dev/sdb}, are device names (file names associated to devices). @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. @file{/dev/hda1}, @file{/dev/sdb3}, are partition names (file names associated to partitions). @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. CD-ROMs and DVDs 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 may define it with the options @option{--input-position}, @option{--size}, and @option{--domain-mapfile}. The rescue domain defaults to the whole input file or mapfile. If ddrescue can't determine the size of the input file, the rescue domain defaults to the maximum size of a block (at least @w{2^63 - 1} bytes, or @w{8 EiB} minus 1 byte). Ddrescue never tries to read any data outside the rescue domain except when unaligned direct disc access is requested (@pxref{Direct disc access}). If it does, please, report it as a bug. The data shown by ddrescue (amount of data rescued, number of bad areas, etc) may vary or even become zero if you limit the rescue domain. Don't worry, they have not disappeared; they are simply out of the rescue domain specified. @item Sector Hardware block. Smallest accessible amount of data on a block 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. Never try to rescue a r/w mounted partition. The resulting copy may be useless. It is best that the device or partition to be rescued is not mounted at all, not even read-only. 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 (for example, udev enabled systems). If you reboot such a system, pass the option @option{--ask} to ddrescue and check that the device names match the model and serial number of the input and output devices before allowing ddrescue to proceed. You may also check the devices with commands like @w{@samp{hdparm -I /dev/sda}} or @w{@samp{smartctl -i /dev/sda}}. 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. When using a (graphical) frontend, be careful to not insert or remove any devices to avoid changes in the mapping of devices to device names between the moment the devices are selected in the frontend and the call to ddrescue. Be careful even if the frontend passes @option{--ask} to ddrescue, because @var{outfile} may be changed between user confirmation and actual opening. It is recommended to run ddrescue on a POSIX system, but if you run it on Cygwin be prepared to find mysterious 'Permission denied' error messages caused by Windows returning misleading error codes and then Cygwin mapping some of those error codes to EACCES, making it impossible for ddrescue to know what failed, or even whether the error is fatal or not. @xref{--continue-on-errno}. @node Algorithm @chapter Algorithm @cindex algorithm GNU ddrescue is not a derivative of dd, nor is related to dd in any way except in that both can be used for copying data from one device to another. The key difference is that ddrescue uses a sophisticated algorithm to copy data from failing drives causing them as little additional damage as possible. Versions of ddrescue prior to 1.19 used a divide-and-conquer strategy to rescue the difficult parts of the drive. But that caused a lot of head movement, which is bad for the drive. Therefore, newer versions try to minimize head movement to minimize drive damage. 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 read the data sequentially but switch to small size reads when they find errors. 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 divided in five phases: copying, trimming, sweeping, scraping, and retrying. Each phase is described below. Disc sectors are marked successively as non-tried, non-trimmed, non-scraped, and bad-sector until they are successfully read and marked as finished. The user may interrupt the process at any point, but a bad drive can block ddrescue for a long time until the kernel gives up. The amount of work remaining for a given phase can be calculated by comparing the current size of the corresponding areas with their size at the end of the previous pass. Namely the size of non-tried while copying or sweeping, the size of non-trimmed while trimming, the size of non-scraped while scraping, and the size of bad-sector while retrying. @xref{Output}. The steps of the algorithm are: 1) Optionally read a mapfile describing the status of a multipart or previously interrupted rescue. If no mapfile is specified, or is empty, or does not exist, mark all the rescue domain as non-tried. 2) (First phase; Copying) Copying is done in up to four passes. The first pass reads the non-tried parts of the input file, marking the failed blocks as non-trimmed and skipping beyond them. The second pass runs in the opposite direction as the first pass and delimits the blocks skipped by the first pass. The first two passes also skip beyond slow areas. The slow areas skipped are tried later in two additional passes (before trimming). The copying direction is reversed after each pass until all the rescue domain is tried. The third and fourth passes read the blocks skipped due to slow areas (if any) by the first two passes, in the same direction that each block was skipped. For each block, passes 2 to 4 skip the rest of the block after finding the first error in the block. The purpose of the multiple passes is to delimit large bad areas fast, recover the most promising areas first, keep the mapfile small, and produce good starting points for trimming. Only non-tried areas are read in large blocks. Trimming, scraping, and retrying are done sector by sector. Each sector is tried at most two times: the first in the copying or sweeping phases as part of a large block read, the second during trimming, scraping, or retrying as a single sector read. 3) (Second phase; Trimming) Try again sector by sector the edges of the large block reads failed during the copying phase. Trimming is done in one pass as follows. For each non-trimmed block, if the preceding block is a finished block, read forwards one sector at a time from the leading edge of the block until a bad sector is found. Then, if the following block is a finished block, read backwards one sector at a time from the trailing edge of the block until a bad sector is found. Then mark the bad sectors found (if any) as bad-sector, and mark the rest of the block as non-scraped unless it is adjacent to a non-tried block. 4) (Third phase; Sweeping) Copy the non-tried areas skipped during the copying phase because of read errors. Sweeping may have a low probability of finding good data if the bad areas are large and have been well delimited by the copying phase. Therefore, sweeping is run after trimming the blocks adjacent to finished blocks, which has a high probability of finding good data. Sweeping is done in one pass with skipping disabled. It tries to copy each non-tried block and trim it if needed. Then it marks the bad sectors found (if any) as bad-sector, and marks the rest of the block as non-scraped. 5) (Fourth phase; Scraping) Scrape together, sector by sector, the data not recovered nor marked as bad-sector by the copying, trimming, or sweeping phases. Scraping is done in one pass. Each non-scraped block is read forwards, one sector at a time. Any bad sectors found are marked as bad-sector. 6) (Fifth phase; Retrying) Optionally try to read again the bad sectors until the number of retry passes specified is reached. The direction is reversed after each pass. Every bad sector is tried only once in each pass. Ddrescue can't know if a bad sector is unrecoverable or if it will be eventually read after some retries. 7) Optionally write a mapfile for later use. @sp 1 When ddrescue finishes the steps above, any areas marked as bad-sector will remain untouched in the output file. If the output file is a regular file created by ddrescue, the areas marked as bad-sector will contain zeros. If it is a device or a previously existing file, the areas marked as bad-sector will still contain the data previously present there. The mapfile is periodically saved to disc, as well as when ddrescue finishes or is interrupted. A backup copy of the mapfile with the extension @file{.bak} is also periodically created (if possible). So in case of a crash you can resume the rescue with little recopying. The default interval between saves varies from 30 seconds to 5 minutes depending on mapfile size (larger mapfiles are saved at longer intervals), but may be overriden. @xref{--mapfile-interval}. The same mapfile 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/sdc hdimage mapfile ddrescue -i0 -s1MiB -d -r3 /dev/sdc hdimage mapfile @end example @noindent Then rescue some key disc areas. @example ddrescue -i30GiB -s10GiB /dev/sdc hdimage mapfile ddrescue -i230GiB -s5GiB /dev/sdc hdimage mapfile @end example @noindent Now rescue the rest (does not recopy what is already done). @example ddrescue /dev/sdc hdimage mapfile ddrescue -d -r3 /dev/sdc hdimage mapfile @end example @node Output @chapter Meaning of ddrescue's screen output @cindex output The output of ddrescue looks like this: @example GNU ddrescue @value{VERSION} Press Ctrl-C to interrupt Initial status (read from mapfile) rescued: 1665 MB, tried: 0 B, bad-sector: 0 B, bad areas: 0 Current status ipos: 2874 MB, non-trimmed: 0 B, current rate: 21479 kB/s opos: 2874 MB, non-scraped: 0 B, average rate: 21023 kB/s non-tried: 13603 MB, bad-sector: 0 B, error rate: 0 B/s rescued: 2401 MB, bad areas: 0, run time: 35s pct rescued: 15.00%, read errors: 0, remaining time: 10m slow reads: 5, time since last successful read: 0s Copying non-tried blocks... Pass 1 (forwards) @end example Ddrescue scrolls forward after each pass. This keeps on the screen the final status of the previous pass, making it easier to estimate the amount of work done by the current pass. The meaning of each field is as follows: @table @code @item ipos Input position. The position in the input file where data are being currently read from. @item opos Output position. The position in the output file where data are being currently written to. @item non-tried Size of the part of the rescue domain pending to be tried. This is the sum of the sizes of all the non-tried blocks. @item rescued Size of the part of the rescue domain already successfully recovered. This is the sum of the sizes of all the finished blocks. @item pct rescued Percentage of the rescue domain that has been successfully recovered. @item slow reads Number of times that the read rate fell below @option{--min-read-rate} during the first two passes of the copying phase. @xref{--min-read-rate}. @item tried Size of the part of the rescue domain already tried but not yet rescued. This is the sum of the sizes of all the non-trimmed, non-scraped, and bad-sector blocks. @item non-trimmed Size of the part of the rescue domain pending to be trimmed. This is the sum of the sizes of all the non-trimmed blocks. @item non-scraped Size of the part of the rescue domain pending to be scraped. This is the sum of the sizes of all the non-scraped blocks. @item bad-sector Total error size. This is the size of the part of the rescue domain formed by known bad sectors. The total error size is the sum of the sizes of all the bad-sector blocks. It increases during the trimming, sweeping, and scraping phases, and may decrease during the retrying phase. A sector is not marked as bad-sector and considered part of a bad area until it has been tried individually instead of as part of a large block read. Note that as ddrescue retries the bad-sector blocks, the good data found may divide them into smaller blocks, decreasing the total error size but increasing the number of bad areas. @item bad areas Number of separate bad-sector blocks inside the rescue domain. Non-trimmed and non-scraped blocks are not considered bad areas. @xref{--max-bad-areas}. @item read errors Number of failed read attempts. @xref{--max-error-rate}. @item current rate The read rate measured during the last second. @item average rate The average read rate measured during the current run. @item error rate The read error rate measured during the last second. @item run time Time elapsed since the beginning of the current run. @item remaining time Estimated remaining time to rescue all the data in the rescue domain. The remaining time is calculated using the average rate of the last 60 seconds and does not take into account that some parts of the rescue domain may be excluded from the rescue (for example with @option{--no-sweep}), or that some areas may be unrecoverable. Therefore it may be imprecise, may vary widely during the rescue, and may show a nonzero value at the end of the rescue. In particular it may go down to a few seconds at the end of the first pass, just to grow to hours or days in the following passes. Such is the nature of ddrescue; the good parts are usually recovered fast, while the rest may take a long time. @item time since last successful read Time elapsed since the last successful read attempt. @end table @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{mapfile}] @end example @var{infile} and @var{outfile} may be files, devices, or partitions. @var{mapfile} is a regular file and must be placed in an existing directory. If @var{mapfile} does not exist, ddrescue creates it. Be careful to not specify by mistake an old @var{mapfile} from an unrelated rescue. Ddrescue tries to create a backup copy of the mapfile, with the name @var{mapfile}.bak, every time it is going to overwrite a fsynced @var{mapfile}. @xref{--mapfile-interval}. Always use a mapfile unless you know you won't need it. Without a mapfile, ddrescue can't resume a rescue, only reinitiate it. @noindent ddrescue supports the following options: @xref{Argument syntax}. @table @code @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. This version number should be included in all bug reports. @anchor{--min-read-rate} @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 during the first two passes of the copying phase, ddrescue skips ahead a variable amount depending on rate and error histories. The blocks skipped are tried in additional passes (before trimming). @option{--min-read-rate} is ignored in all passes but the first two. If @var{bytes} is 0 (auto), the minimum read rate is recalculated every second as @w{(average_rate / 10)}. @item -A @itemx --try-again Mark all non-trimmed and non-scraped blocks inside the rescue domain as non-tried before beginning the rescue. Try this if the drive stops responding and ddrescue immediately starts scraping failed blocks when restarted. If @option{--retrim} is also specified, mark also the most promising bad sectors inside the rescue domain as non-tried. @xref{--retrim}. @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. In rescue mode, any non-finished subsector that is found during the initial read of the mapfile is joined to its corresponding sector (if it is also not finished), marking the whole sector with the less processed state, so as to make sure that sub-sector data is not discarded from a successful read during the rescue. (A subsector is a block smaller than sector size). Subsector joining is performed in all the mapfile, not only in the rescue domain. @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{mapfile}. Don't read new data beyond @var{mapfile} 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. @option{-C} can only be used after a first rescue attempt, possibly limited with the option @option{--size}, has produced a complete @var{mapfile}. If @option{-C} is not specified, ddrescue extends the @var{mapfile} from position 0 to the size of @var{outfile}, adding one non-tried block before the existing blocks and another one after them if needed. @item -d @itemx --idirect Use direct disc access to read from @var{infile}, bypassing the kernel cache. (Opens the file with the flag @samp{O_DIRECT}). Sector size must be correctly set for this to work. Not all systems support this. @xref{Direct disc access}. If your system does not support direct disc access, ddrescue warns you. If the sector size is not correctly set, an unaligned read error may happen, in which case ddrescue exits with error status 1. @item -D @itemx --odirect Use direct disc access to write to @var{outfile}, bypassing the kernel cache. (Opens the file with the flag @samp{O_DIRECT}). 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 warns you. If the sector size is not correctly set, a write error is reported and no data is rescued. Some OSs have a bug that prevents them from detecting write errors properly (or at all) on some devices if direct disc access is not used for @var{outfile}. @anchor{--max-bad-areas} @item -e [+]@var{n} @itemx --max-bad-areas=[+]@var{n} Maximum number of bad areas allowed before giving up. Defaults to infinity. If @var{n} is preceded by @samp{+} the number refers to new bad areas found in this run, not counting those already present in the @var{mapfile}. @xref{--max-read-errors}. @anchor{--max-error-rate} @item -E @var{bytes} @itemx --max-error-rate=@var{bytes} Maximum rate of read errors allowed before giving up, in bytes per second. Defaults to infinity. The rate being measured is that of actually failed reads, so ddrescue may exit because of this rate being exceeded even if the total error size (size of bad-sector areas) does not change because the areas being tried are being marked as non-trimmed or non-scraped, or are already marked as bad-sector. @item -f @itemx --force Force overwrite of @var{outfile}. Needed when @var{outfile} is not a regular file, but a device or partition. This option is just a safeguard to prevent the inadvertent destruction of partitions, and is ignored for regular files. @item -F @var{types} @itemx --fill-mode=@var{types} Fill the blocks in @var{outfile} specified as any of @var{types} in @var{mapfile}, with data read from @var{infile}. @var{types} contains one or more of the status characters defined in the chapter Mapfile structure (@pxref{Mapfile structure}) and an optional @samp{l} for sector location data. 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{mapfile} from the @var{infile} and @var{outfile} of the original rescue run. Note that you must keep the original offset between @option{--input-position} and @option{--output-position} of the original rescue run. See the chapter Generate mode (@pxref{Generate mode}) for a complete description of the generate mode. @anchor{--test-mode} @item -H @var{file} @itemx --test-mode=@var{file} Build a map of good/bad blocks using the mapfile @var{file} and use it to simulate read errors in @var{infile}. The blocks marked as finished in @var{file} are read normally. All other block types are considered read errors without even trying to read them from @var{infile}. The apparent size of @var{infile} is truncated to the extent of @var{file}. This mode is an aid in improving the algorithm of ddrescue and is also useful to check that ddrescue produces accurate results in presence of read errors. Use a hyphen @samp{-} as @var{file} to read the mapfile from standard input. @xref{--pause-on-error}. @item -i @var{bytes} @itemx --input-position=@var{bytes} Starting position of the rescue domain in @var{infile}, in bytes. Defaults to 0. This is not the point from which ddrescue starts copying. (For example, if you pass the option @option{--reverse} to ddrescue, it starts copying from the end of the rescue domain). 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 --check-input-size Compare the size of @var{infile} with the size calculated from the list of blocks contained in the @var{mapfile}, 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{mapfile} may be incomplete, for example after doing a partial rescue. @item -J @itemx --check-on-error After every read error, read again the last good sector found and check that it returns the same data. Exit with status 2 if the read fails or returns inconsistent data. Exit with status 1 if a read error happens before a good sector is found. This option performs one extra read after each error, wearing the drive faster. Use it only on drives that stop responding or return garbage data after finding errors. You may need to power cycle the drive before restarting ddrescue. @item -K [@var{initial}][,@var{max}] @itemx --skip-size=[@var{initial}][,@var{max}] Set limits to skip size during the copying phase. At least one of @var{initial} or @var{max} must be specified. @var{initial} is the size to skip on the first read error or slow read, in bytes. @var{max} is the maximum size to skip. The values given are rounded to the next multiple of sector size. The skip size is doubled for each read error or slow read until it reaches @var{max} or, if @var{max} is omitted, 1% of the size of @var{infile}, and is reset to @var{initial} when good data are found. Valid values range from @w{64 KiB} to @w{1 EiB}. @var{initial} defaults to @w{@var{infile_size} / 32_768} with a minimum value of @w{64 KiB}. An @var{initial} value of 0 disables skipping entirely. If ddrescue is having difficulties skipping away from a large area with scattered errors, or if the device has large bad areas at regular intervals, you may increase the initial skip size with this option. Inversely, if ddrescue is skipping too much, leaving large non-tried areas behind each error (which will be read later in the usually slower backwards direction), you may reduce the maximum skip size, or disable skipping. @option{--skip-size} is independent from @option{--cluster-size}. The size to skip is calculated from the end of the block that just failed. @item -L @itemx --loose-domain Accept an incomplete synthetic (user fabricated) domain mapfile or test-mode mapfile, and fill the gaps in the list of data blocks with non-tried blocks. The blocks in the mapfile may be unordered, may overlap other blocks of the same status, and don't need to be contiguous. This option allows making quick edits to a mapfile without all the size calculations involved in making all data blocks contiguous again. @anchor{--domain-mapfile} @item -m @var{file} @itemx --domain-mapfile=@var{file} Restrict the rescue domain to the blocks marked as finished in the mapfile @var{file}. This is useful for merging partially recovered images of backups, or if the destination drive fails during the rescue. Use a hyphen @samp{-} as @var{file} to read the domain mapfile from standard input. Specialized tools like ddrutility or partclone can produce a domain mapfile listing all the used blocks in a partition, making the rescue more efficient. Trailing empty space in the partition is not copied to @var{outfile}. If you need @var{outfile} to be the same size as the partition (to mount it, for example), you may use @option{--extend-outfile=0}, @option{--extend-outfile=}, or @option{--preallocate}. @option{--extend-outfile} increases the size without writing data to @var{outfile}, and may therefore be more efficient than @option{--preallocate}. Partclone saves the size of the partition as the value of @samp{current_pos} in the domain mapfile. @anchor{--retrim} @item -M @itemx --retrim Mark the failed blocks inside the rescue domain adjacent to a non-tried or finished block as non-trimmed before beginning the rescue. This might make perhaps possible to rescue some of them. @item -n @itemx --no-scrape Skip the scraping phase. Avoids spending a lot of time trying to rescue the most difficult parts of the file. @item -N @itemx --no-sweep Skip the sweeping phase. May be useful when the drive has a dead head. @itemx --no-trim Skip the trimming phase. This option is not recommended because trimming has a high probability of finding good data. @item -o @var{bytes} @itemx --output-position=@var{bytes} Starting position of the image of the rescue domain in @var{outfile}, in bytes. Defaults to @option{--input-position}. The bytes below @var{bytes} aren't touched if they exist and truncation is not requested. Else they are set to 0. @anchor{--reopen-on-error} @item -O @itemx --reopen-on-error Close @var{infile} and then reopen it after every read error encountered. If @option{--min-read-rate} is set, also close and reopen @var{infile} after every slow read encountered during the first two passes of the copying phase. Use this option if you notice a permanent drop in transfer rate after finding read errors or slow areas. But be warned that most probably the slowing-down is intentionally caused by the kernel in an attempt to increase the probability of reading data from the device. This option may also be needed to reset the error status of the input device when using the option @option{--continue-on-errno}. @xref{--min-read-rate}, @ref{--continue-on-errno}. @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 options @option{--input-position}, @option{--output-position}, @option{--size}, and @option{--domain-mapfile}. @item -P[@var{lines}] @itemx --data-preview[=@var{lines}] Show @var{lines} lines of the latest data read in @w{@samp{16-byte hex + ASCII}} format. Valid values for @var{lines} range from 1 to 32. If @var{lines} is omitted, a default value of 3 is used. @item -q @itemx --quiet Quiet operation. Suppress all messages. @item -r @var{n} @itemx --retry-passes=@var{n} Exit after the given number of retry passes. Defaults to 0. -1 means infinity. Every bad sector is tried only once in each pass. The direction is reversed after each pass. To retry bad sectors detected on a previous run, you must specify a nonzero number of retry passes. A command like @w{@samp{ddrescue -f -r-1 /dev/sdcard /dev/null mapfile}} can be used to read repeatedly until the device controller succeeds and remaps the bad sectors internally. @item -R @itemx --reverse Reverse the direction of all passes (copying, trimming, sweeping, scraping, and retrying). Every pass that is normally run forwards is now run backwards, and vice versa. @option{-R} does not modify the size of the blocks copied during each phase, just the order in which they are tried. @item -s @var{bytes} @itemx --size=@var{bytes} Maximum size of the rescue domain in bytes. It limits the amount of input data to be copied. -1 removes any previous size limit. In rescue mode, @option{--size=output} uses the size of the output file or device (for example to overwrite it). By default, ddrescue limits the amount of data to be copied to the size of the input file, but if ddrescue can't determine the size of the input file, you may need to specify it with this option. Note that this option does not specify the size of the resulting @var{outfile}. 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 mapfile @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. Use this option only with an empty or zeroed @var{outfile} because if a block in @var{outfile} contains nonzero data, it won't be overwritten by a corresponding block of zeros in @var{infile}, resulting in a corrupt copy. @item -t @itemx --truncate Truncate @var{outfile} to zero size before writing to it. Only works for regular files, not for drives or partitions. @anchor{--timeout} @item -T @var{interval} @itemx --timeout=@var{interval} Maximum time since last successful read allowed before giving up. Defaults to infinity. @var{interval} is an integer or 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. @var{interval} has a resolution of one second; fractions of a second are not allowed. @xref{--max-read-errors}. @item -u @itemx --unidirectional Run all passes in the same direction. Forwards by default, or backwards if the option @option{--reverse} is also given. @item -v @itemx --verbose Verbose mode. Further -v's (up to 4) increase the verbosity level. Some large numbers in messages (like device sizes) are printed in groups of 3 digits separated by underscore characters to make them more readable. @item -w @itemx --ignore-write-errors Make fill mode ignore write errors. This is useful to avoid ddrescue exiting because of new bad sectors 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. Note that in rescue mode a write error is fatal, which means that the rescue needs to be repeated or else @var{outfile} needs to be copied to a third drive using @var{mapfile} as domain. @xref{--domain-mapfile}. @item -W @itemx --compare-before-write Omit superfluous writes in rescue mode. Before writing each block of data to @var{outfile}, compare the data already present there with the data about to be written and, if they match, omit the write. Possible advantages are that on some devices reads are faster than writes and it may reduce wear when writing to a solid state device. @item -x @var{bytes} @itemx --extend-outfile=@var{bytes} Extend the size of @var{outfile} to make it at least @var{bytes} long. If @var{bytes} is 0, extend the size of @var{outfile} to that of @var{infile}. If the size of @var{outfile} is already equal or longer than @var{bytes} or the size of @var{infile}, then this option does nothing. Use this option to guarantee a minimum size for @var{outfile}. Only regular files can be extended. @anchor{--max-read-errors} @item -X @var{n} @itemx --max-read-errors=@var{n} Maximum number of read errors allowed before giving up. Defaults to infinity. Exit with status 1 if more than @var{n} read errors are encountered. @option{--max-read-errors=0} is similar but different to @option{--timeout=0}, which waits until the screen status is refreshed (at least 1 second). If there is at least one successful read per second, @option{--timeout=0} does not make ddrescue to exit. @xref{--timeout}. @option{--max-read-errors=0} is also similar but different to @option{--max-bad-areas=+0}, which exits when a new bad area is found. If the read errors are adjacent to existing bad areas, no new bad areas are produced (just enlarged), and @option{--max-bad-areas=+0} does not make ddrescue to exit. @xref{--max-bad-areas}. @item -y @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. Use it to make sure that all writes have been committed to disc when ddrescue finishes. Else the kernel may cache all the writes and pretend that it has finished. @item -Z @var{bytes} @itemx --max-read-rate=@var{bytes} Maximum read rate, in bytes per second. If @var{bytes} is too small, the actual read rate is rounded up to the equivalent of a whole number of cluster reads per second. Use this option to limit the bandwidth used by ddrescue, for example when recovering over a network. @item --ask Ask for user confirmation before starting the copy. If the first letter of the answer is @samp{y}, ddrescue starts copying. Else it exits with status 1. If they can be obtained, ddrescue shows the model and serial number of the input and output devices. Ddrescue also shows the size in bytes of the corresponding file or device if it exists. The format used is @w{[@var{model}::@var{serial_number}] (@var{size})} @item --bad-sector-data=@var{file} Treat as a read error any sector containing the same data as @var{file}. If @var{file} is larger than the sector size, the rest of @var{file} is discarded. This option is useful when the drive, instead of signaling a read error, returns known garbage data (different for each drive model). If you need to use this option, it means that the failing drive lacks adequate integrity checking. Better avoid such drives. @item --command-mode Read commands from the standard input and execute them, copying parts of the input file on demand. Command-line arguments controling the display (like @option{--data-preview}) or the automatic algorithm (like @option{--max-errors} or @option{--reverse}) have no effect in command mode. @xref{Command mode}, for a complete description of the command mode. @anchor{--continue-on-errno} @item --continue-on-errno=@var{code}[,@var{code}]... Treat errno code @var{code} as non-fatal. This option may be useful on systems that incorrectly return fatal errno codes for non-fatal errors. If ddrescue exits because of a fatal read error, it prints in the final message the value of the variable 'errno', which can then be used as argument to this option. Multiple errno values may be specified with cumulative effect, either in the same argument, or by specifying multiple instances of this option. The option @option{--reopen-on-error} may be needed when using this option. @xref{--reopen-on-error}. @item --cpass=@var{range} Select what pass(es) to run during the copying phase. Valid pass values range from 1 to 4. To run only the given pass(es), specify also @option{--no-trim}, @option{--no-sweep}, and @option{--no-scrape}. @option{--cpass=0} skips the copying phase entirely. @multitable {Examples of @var{range}} {Passes run} @headitem Examples of @var{range} @tab Passes run @item 1 @tab 1 @item 1,2,3 @tab 1, 2, 3 @item 2-4 @tab 2, 3, 4 @end multitable @item --delay-slow=@var{interval} Initial delay before ddrescue starts checking for slow reads. Defaults to 30 seconds. @var{interval} is formatted as in the option @option{--timeout} above. @xref{--timeout}. @item --log-events=@var{file} Log all significant events (start of each pass and end of run) in @var{file}. If @var{file} already exists, the new events are appended at the end of @var{file}. For each event two lines are printed containing a time stamp, the amount of data rescued, and a message describing the event. The @samp{end of run} line also contains the current position and status. If ddrescue exits because of an error or interruption, the cause is also logged in @var{file}. @item --log-rates=@var{file} Log rates and error sizes every second in @var{file}. If @var{file} already exists, it is overwritten. Every time the screen is updated with new details, some of those details (time, input position, current and average rates, number of bad areas, and total error size) are written to @var{file} in a format usable by plotting utilities like gnuplot. This allows a posterior analysis of the drive to see if it has any weak zones (areas where the transfer rate drops well below the sustained average). @item --log-reads=@var{file} Log all read operations in @var{file}. If @var{file} already exists, it is overwritten. Every read attempt and its result (position, size, copied size, error size, and errno (if different from EIO)) is written to @var{file}. (The position written is always the beginning of the block tried, even if reading backwards). A line is also written at the beginning of each phase (copying, trimming, sweeping, scraping, and retrying). Finally, a line with a time mark is written every second (unless the read takes more time). Use this option with caution because @var{file} may become very large very quickly. Use lzip to compress @var{file} if you need to store or transmit it. @anchor{--mapfile-interval} @item --mapfile-interval=[@var{save_interval}][,@var{sync_interval}] Change the interval at which ddrescue saves and fsyncs the @var{mapfile}. At least one of @var{save_interval} or @var{sync_interval} must be specified. A @var{save_interval} of -1 chooses the default automatic interval (from 30 seconds to 5 minutes depending on mapfile size). A @var{save_interval} of 0 saves the @var{mapfile} after every read (use with caution). @var{sync_interval} is the interval between fsync calls. Default @var{sync_interval} is 5 minutes. Minimum @var{sync_interval} is 5 seconds. @var{sync_interval} must be greater or equal than @var{save_interval}. Intervals are formatted as in the option @option{--timeout} above. @xref{--timeout}. In practice, fsyncs are a subset of saves. I.e., some of the times when the @var{mapfile} is saved, it is also fsync'ed. Therefore, @option{--mapfile-interval=30,45} is really @option{--mapfile-interval=30,60}. The time needed to write the @var{mapfile} is excluded from the mapfile save and sync intervals. (Some mapfiles may take several seconds to write). @anchor{--max-slow-reads} @item --max-slow-reads=@var{n} Maximum number of slow reads allowed before giving up. Defaults to infinity. Exit with status 1 if more than @var{n} slow reads are encountered during the first two passes of the copying phase. Only works if a minimum read rate has been set with @option{--min-read-rate}. @xref{--min-read-rate}. @anchor{--pause-on-error} @item --pause-on-error=@var{interval} Time to wait after each read error. Also after each slow read if a minimum read rate has been set with @option{--min-read-rate}. Defaults to 0. @var{interval} is formatted as in the option @option{--timeout} above. If @var{interval} begins with @samp{s}, the pause is simulated and @var{interval} can be smaller than one second; the time displayed is increased by @var{interval} but without performing any pause. Pause simulation can be useful in combination with @option{--test-mode} for testing purposes. @xref{--min-read-rate}, @ref{--test-mode}, @ref{--timeout}. @item --pause-on-pass=@var{interval} Time to wait between passes. Defaults to 0. @var{interval} is formatted as in the option @option{--timeout} above. @xref{--timeout}. @item --reset-slow Reset the slow reads counter every time the read rate reaches or surpasses @option{--min-read-rate}. With this option, ddrescue only exits after the read rate has remained below @option{--min-read-rate} for at least as many seconds as the argument given to @option{--max-slow-reads}. @xref{--min-read-rate}, @ref{--max-slow-reads}. @item --same-file Allow @var{infile} and @var{outfile} to be the same file or device. This may be used to test the writing ability of a drive. It may also be used to copy part of a file to another location inside or beyond the end of the same file by setting different values for @option{--input-position} and @option{--output-position}. If the data to be copied overlap with the destination, the right copying direction must be chosen to avoid overwriting the overlapping part before it is copied. @end table Numbers given as arguments to options (positions, sizes, rates, etc) may be expressed as decimal, hexadecimal, or octal values (using the same syntax as integer constants in C++), may contain underscore separators between groups of 3 or more digits (2 or more digits for hexadecimal), and may be followed by a multiplier and an optional @samp{B} for "byte". (1_234_567kB, 4Kis, 0x1234_5678, 07_777_777). The @samp{s} multiplier may be appended to any of the other multipliers. For example, @samp{ks} means kilosectors @w{(1000 * sector_size)}, and @samp{Kis} means kibisectors @w{(1024 * sector_size)}. Table of SI and binary prefixes (unit multipliers): @multitable {Prefix} {kilobyte (10^3 = 1000)} {|} {Prefix} {kibibyte (2^10 = 1024)} @headitem Prefix @tab Value @tab | @tab Prefix @tab Value @item s @tab sectors @tab | @tab @tab @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) @item R @tab ronnabyte (10^27) @tab | @tab Ri @tab robibyte (2^90) @item Q @tab quettabyte (10^30) @tab | @tab Qi @tab quebibyte (2^100) @end multitable @sp 1 Exit status: 0 for a normal exit, 1 for environmental problems (file not found, invalid command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., bug) which caused ddrescue to panic. If ddrescue is interrupted by a signal, it updates @var{mapfile} and then terminates by raising the signal received. @node Argument syntax @chapter Syntax of command-line arguments @cindex argument syntax POSIX recommends these conventions for command-line arguments. @itemize @bullet @item A command-line argument is an option if it begins with a hyphen (@samp{-}). @item Option names are single alphanumeric characters. @item Certain options require an argument. @item An option and its argument may or may not appear as separate tokens. (In other words, the whitespace separating them is optional). Thus, @w{@option{-o foo}} and @option{-ofoo} are equivalent. @item One or more options without arguments, followed by at most one option that takes an argument, may follow a hyphen in a single token. Thus, @option{-abc} is equivalent to @w{@option{-a -b -c}}. @item Options typically precede other non-option arguments. @item The argument @samp{--} terminates all options; any following arguments are treated as non-option arguments, even if they begin with a hyphen. @item A token consisting of a single hyphen character is interpreted as an ordinary non-option argument. By convention, it is used to specify standard input, standard output, or a file named @samp{-}. @end itemize @noindent GNU adds @dfn{long options} to these conventions: @itemize @bullet @item A long option consists of two hyphens (@samp{--}) followed by a name made of alphanumeric characters and hyphens. Option names are typically one to three words long, with hyphens to separate words. Abbreviations can be used for the long option names as long as the abbreviations are unique. @item A long option and its argument may or may not appear as separate tokens. In the latter case they must be separated by an equal sign @samp{=}. Thus, @w{@option{--foo bar}} and @option{--foo=bar} are equivalent. @end itemize @noindent The syntax of options with an optional argument is @option{-} (without whitespace), or @option{--=}. @node Mapfile structure @chapter Mapfile structure @cindex mapfile structure NOTE: In versions of ddrescue prior to 1.20 the mapfile was called @samp{logfile}. The format is the same; only the name has changed. The mapfile 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. The character @samp{#} at begin of line or after whitespace starts a comment that extends to the end of the line. The heading comments contain the version of ddrescue or ddrescuelog that created the mapfile, the command line used, and the time when the program started. If the mapfile was created by ddrescue it also contains the current time when the mapfile was saved and a copy of the status message from the screen describing the operation being performed (copying, trimming, finished, etc). They are intended as information for the user. The first non-comment line is the status line. It contains a non-negative integer, a status character, and a positive decimal integer. The first integer is the position being tried in the input file. (The beginning of the block being tried in a forward pass or the end of the block in a backward pass). The status character is one of these: @multitable {Character} {generating approximate mapfile} @headitem Character @tab Meaning @item '?' @tab copying non-tried blocks @item '*' @tab trimming non-trimmed blocks @item '%' @tab sweeping non-tried blocks @item '/' @tab scraping non-scraped blocks @item '-' @tab retrying bad sectors @item 'F' @tab filling the blocks specified @item 'G' @tab generating approximate mapfile @item '+' @tab finished @end multitable Finally, the last integer is the number of the current pass in the current phase. The status line allows ddrescue to resume the copying phase instead of restarting it from pass 1. It also allows the retrying phase to resume in the same direction it was interrupted. 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)} @headitem Character @tab Meaning @item '?' @tab non-tried block @item '*' @tab failed block non-trimmed @item '/' @tab failed block non-scraped @item '-' @tab failed block bad-sector(s) @item '+' @tab finished block @end multitable @noindent And here is an example mapfile: @example # Mapfile. Created by GNU ddrescue version @value{VERSION} # Command line: ddrescue -d -c18 /dev/fd0 fdimage mapfile # Start time: 2015-07-21 09:37:44 # Current time: 2015-07-21 09:38:19 # Copying non-tried blocks... Pass 1 (forwards) # current_pos current_status current_pass 0x00120000 ? 1 # pos size status 0x00000000 0x00117000 + 0x00117000 0x00000200 - 0x00117200 0x00001000 / 0x00118200 0x00007E00 * 0x00120000 0x00048000 ? @end example If you edit the file, you may use decimal, hexadecimal, or octal values, using the same syntax as integer constants in C++, except for current_pass, which must be a decimal integer. @node Emergency save @chapter Saving the mapfile in case of trouble @cindex emergency save The mapfile is an essential part of ddrescue's effectiveness. Without a mapfile, ddrescue can't resume a rescue, only reinitiate it. Given that a difficult rescue may take days to complete, it would be a serious drawback if the mapfile were lost because of a solvable problem like a lack of space on the device the mapfile is written to. In case of trouble writing the mapfile, ddrescue prints a message like this: @example Error writing mapfile '@var{mapfile}': No space left on device Fix the problem and press ENTER to retry, or E+ENTER for an emergency save and exit, or Q+ENTER to abort. @end example You may try to fix the problem, for example deleting some files to make room for the mapfile, and press @key{Return} to retry. If the problem can't be fixed, you may press @key{e} followed by @key{Return} to try an emergency save and exit. Ddrescue tries to write the mapfile to the file @file{ddrescue.map} in the current directory or, if this fails, to @file{$HOME/ddrescue.map}. If the mapfile is written successfully, ddrescue exits with status 1. Else it prints the above message again. Or you may press @key{q} followed by @key{Return} to quit and exit with status 1. In this case the content of the mapfile is lost. @node Optical media @chapter Copying CD-ROMs and DVDs @cindex optical media Ddrescue may be better than dd for copying recordable CD-ROMs because the two lead out sectors at the end of some of them may cause a read error that prevents the whole last record from being copied by dd, potentially losing data. Also dd may create an image larger than the original if the @samp{sync} conversion and a block size larger than the sector size are specified. In the special case of reading CD-ROMs (but not DVDs), the specialized tool dvdisaster may be a better option than ddrescue for recovering data because dvdisaster can read and analyze raw CD sectors, which ddrescue can't. Recordable CD and DVD media keep their data only for a finite time (typically for some years). After that time, data loss develops slowly with read errors growing from the outer region towards the inside. It is a good idea to make two (or more) copies of every important CD-ROM/DVD you burn so that you can later recover them with ddrescue. If you have only one copy of a CD-ROM or DVD that fails when being copied, and if you have access to multiple optical media drives, you have a better chance of recovering the bad sectors since one drive may fail to read a particular sector, but another drive might be able to squeeze the data out of it, depending on the laser frequency and the sensitivity of the laser-sensor that reads the reflected laser light. @noindent Example 1: Rescue a CD-ROM in @file{/dev/cdrom}. @example ddrescue -n -b2048 /dev/cdrom cdimage mapfile ddrescue -d -r1 -b2048 /dev/cdrom cdimage mapfile (if bad-sector size is zero, cdimage now contains a complete image of the CD-ROM and you can write it to a blank CD-ROM) @end example @sp 1 @noindent Example 2: Rescue a CD-ROM in @file{/dev/cdrom} from two copies. @example ddrescue -n -b2048 /dev/cdrom cdimage mapfile ddrescue -d -b2048 /dev/cdrom cdimage mapfile (insert second copy in the CD drive) ddrescue -d -r1 -b2048 /dev/cdrom cdimage mapfile (if bad-sector size is zero, cdimage now contains a complete image of the CD-ROM and you can write it to a blank CD-ROM) @end example @sp 1 @noindent Example 3: Rescue a CD-ROM in @file{/dev/cdrom} using two CD drives from two different computers, writing the image into an USB drive mounted on @file{/mnt/mem}. @example ddrescue -n -b2048 /dev/cdrom /mnt/mem/cdimage /mnt/mem/mapfile ddrescue -d -r1 -b2048 /dev/cdrom /mnt/mem/cdimage /mnt/mem/mapfile (umount the USB drive and move both USB drive and CD-ROM to second computer) ddrescue -d -r1 -b2048 /dev/cdrom /mnt/mem/cdimage /mnt/mem/mapfile (if bad-sector size is zero, /mnt/mem/cdimage now contains a complete image of the CD-ROM and you can write it to a blank CD-ROM) @end example @sp 1 @noindent Example 4: Merge the partially recovered images of 3 identical DVDs using their mapfiles as domain mapfiles. @example ddrescue -m mapfile1 dvdimage1 dvdimage mapfile ddrescue -m mapfile2 dvdimage2 dvdimage mapfile ddrescue -m mapfile3 dvdimage3 dvdimage mapfile (if bad-sector size is zero, dvdimage now contains a complete image of the DVD and you can write it to a blank DVD) @end example @sp 1 @anchor{lziprecover example1} @noindent Example 5: Recover a lzip compressed backup from two copies on CD-ROM with error-checked merging of copies. @example ddrescue -d -r1 -b2048 /dev/cdrom cdimage1 mapfile1 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 -d -r1 -b2048 /dev/cdrom cdimage2 mapfile2 mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz umount /mnt/cdimage lziprecover -v -m -o backup.tar.lz rescued1.tar.lz rescued2.tar.lz Input files merged successfully. lziprecover -tv backup.tar.lz backup.tar.lz: ok @end example @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 are 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 appropriate 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 @file{/dev}, then you cannot rescue it. At least not with ddrescue. @xref{Optical media}, for rescue examples of CD-ROMs and DVDs. @sp 1 @noindent Example 1: Fully automatic rescue of a whole disc with two ext2 partitions in @file{/dev/sda} to @file{/dev/sdb}.@* Note: you don't need to partition @file{/dev/sdb} beforehand, but if the partition table on @file{/dev/sda} is damaged, you'll need to recreate it somehow on @file{/dev/sdb}. @example ddrescue -f -r3 /dev/sda /dev/sdb mapfile fdisk /dev/sdb e2fsck -v -f /dev/sdb1 e2fsck -v -f /dev/sdb2 @end example @sp 1 @noindent Example 2: Rescue an ext2 partition in @file{/dev/sda2} to @file{/dev/sdb2}.@* Note: you need to create the partition sdb2 with fdisk first. sdb2 should be of appropriate type and size. @example ddrescue -f -n /dev/sda2 /dev/sdb2 mapfile ddrescue -d -f -r3 /dev/sda2 /dev/sdb2 mapfile e2fsck -v -f /dev/sdb2 mount -t ext2 -o ro /dev/sdb2 /mnt (read rescued files from /mnt) @end example @sp 1 @noindent Example 3: While rescuing the whole drive @file{/dev/sda} to @file{/dev/sdb}, @file{/dev/sda} freezes up at position 12_345_678. @example ddrescue -f /dev/sda /dev/sdb mapfile # /dev/sda freezes here (restart /dev/sda or reboot computer) (restart copy at a safe distance from the troubled sector) ddrescue -f -i 12350000 /dev/sda /dev/sdb mapfile (then copy backwards down to the troubled sector) ddrescue -f -R /dev/sda /dev/sdb mapfile @end example @sp 1 @noindent Example 4: While rescuing the whole drive @file{/dev/sda} to @file{/dev/sdb}, @file{/dev/sdb} fails and you have to rescue the data to a third drive, @file{/dev/sdc}. @example ddrescue -f -n /dev/sda /dev/sdb mapfile1 # /dev/sdb fails here ddrescue -f -m mapfile1 /dev/sdb /dev/sdc mapfile2 ddrescue -f -n /dev/sda /dev/sdc mapfile2 ddrescue -d -f -r3 /dev/sda /dev/sdc mapfile2 @end example @sp 1 @noindent Example 5: While rescuing a partition in @file{/dev/sda1} to the file @file{hdimage}, @file{/dev/sda1} stops responding and begins returning read errors, causing ddrescue to mark the rest of the partition as non-scraped. @example ddrescue -n /dev/sda1 hdimage mapfile # /dev/sda1 fails here (restart /dev/sda or reboot computer) ddrescue -n -A -i -O /dev/sda1 hdimage mapfile (if /dev/sda1 fails again, restart /dev/sda or reboot computer and then repeat the above command as many times as needed until it succeeds. is the position where the drive stopped responding) ddrescue -d -r3 /dev/sda1 hdimage mapfile @end example @sp 1 @noindent Example 6: While rescuing a partition in @file{/dev/sda1} to the file @file{hdimage}, sda1 disappears from @file{/dev}. @example ddrescue -n /dev/sda1 hdimage mapfile # /dev/sda1 fails here (restart /dev/sda or reboot computer and then repeat the above command as many times as needed until it succeeds) ddrescue -d -r3 /dev/sda1 hdimage mapfile @end example @sp 1 @noindent Example 7: While rescuing a partition in @file{/dev/sda1} to the file @file{hdimage}, the partition table of @file{/dev/sda} becomes unreadable and the OS no longer shows sda1 in @file{/dev}. The solution is to shift the mapfile and read the rest of the partition sda1 from @file{/dev/sda}.@* Note: you need to know the offset of the partition sda1 in the drive sda and the size of sda1. @example ddrescue /dev/sda1 hdimage mapfile # partition table fails here ddrescuelog --shift -o mapfile > shifted_mapfile ddrescue -i -o0 -s /dev/sda hdimage shifted_mapfile @end example @sp 1 @noindent Example 8: After rescuing a partition in @file{/dev/sda1} to the file @file{hdimage}, expand @file{hdimage} to copy the whole drive in @file{/dev/sda} without recopying the already copied partition @file{/dev/sda1}. The solution is to shift the mapfile, move the data of sda1 to its final position in @file{hdimage}, and then read the rest of the data from @file{/dev/sda}.@* Note: you need to know the offset of the partition sda1 in the drive sda and the size of sda1. @example ddrescue /dev/sda1 hdimage mapfile # rescue partition ddrescuelog --shift -o mapfile > shifted_mapfile ddrescue --same-file -o -s --reverse hdimage hdimage ddrescue /dev/sda hdimage shifted_mapfile # rescue rest of drive @end example @sp 1 @anchor{lziprecover example2} @noindent Example 9: Recover a collection of photos from a damaged external drive (@file{/dev/sdc1}). The photos are protected with forward error correction (fec) files created by lziprecover. The photos are in directory @file{photos}, and the fec files are in directory @file{photos-fec}. @example ddrescue -b4096 -r10 /dev/sdc1 hdimage mapfile mount -o loop,ro hdimage /mnt/hdimage cp -a /mnt/hdimage/photos photos cp -a /mnt/hdimage/photos-fec photos-fec umount /mnt/hdimage lziprecover -v -Fr --fec-file=photos-fec/ photos/* (Check and rename repaired files. They are named @file{photos/*_fixed}) @end example @sp 1 @anchor{lziprecover example3} @noindent Example 10: Recover a damaged tar.lz backup using the recovery record appended to the backup itself. The damaged backup comes from a damaged partition copied with ddrescue. @example ddrescue -b4096 -r10 /dev/sdc1 hdimage mapfile mount -o loop,ro hdimage /mnt/hdimage cp /mnt/hdimage/backup.tar.lz backup.tar.lz umount /mnt/hdimage lzip -t backup.tar.lz backup.tar.lz: Decoder error at pos 1_020_530 lziprecover --dump=tdata backup.tar.lz | \ lziprecover -v -Fr --fec-file=- backup.tar.lz @end example @sp 1 @anchor{lziprecover example4} @noindent Example 11: Recover a damaged tar.lz backup with a zeroed sector of 4096 bytes at file position 1_019_904, using as reference a previous backup. The damaged backup comes from a damaged partition copied with ddrescue. @example ddrescue -b4096 -r10 /dev/sdc1 hdimage mapfile mount -o loop,ro hdimage /mnt/hdimage cp /mnt/hdimage/backup.tar.lz backup.tar.lz umount /mnt/hdimage lzip -t backup.tar.lz backup.tar.lz: Decoder error at pos 1_020_530 lziprecover -vv -e --reference-file=old_backup.tar backup.tar.lz Reproducing bad area in member 1 of 1 (begin = 1_019_904, size = 4096, value = 0x00) (master mpos = 1_019_903, dpos = 5_857_954) warning: old_backup.tar: Partial match found at offset 5_743_778, len 9546 Reference data may be mixed with other data. Trying level -9 Reproducing position 1_015_808 Member reproduced successfully. Copy of input file reproduced successfully. @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 @var{mapfile} 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 for @var{infile}, or read from a raw device, to bypass the kernel cache and rescue more of your data. NOTE! Sector size must be correctly set with the option @option{--sector-size} for direct disc access to work. NOTE: Direct disc access can copy arbitrary domains by reading whole sectors and then writing only the requested part. This is the only case where ddrescue tries to read data outside the rescue domain. Try the option @option{--idirect} 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 especial device names, like @file{/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 option @option{--size} or @option{--complete-only} 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. @noindent Example 1: using direct disc access. @example ddrescue -f -n /dev/sdb1 /dev/sdc1 mapfile ddrescue -d -f -r3 /dev/sdb1 /dev/sdc1 mapfile e2fsck -v -f /dev/sdc1 mount -t ext2 -o ro /dev/sdc1 /mnt @end example @sp 1 @noindent Example 2: using a raw device. @example raw /dev/raw/raw1 /dev/sdb1 ddrescue -f -n /dev/sdb1 /dev/sdc1 mapfile ddrescue -C -f -r3 /dev/raw/raw1 /dev/sdc1 mapfile raw /dev/raw/raw1 0 0 e2fsck -v -f /dev/sdc1 mount -t ext2 -o ro /dev/sdc1 /mnt @end example @node Command mode @chapter Copying parts of the input file on demand @cindex command mode The command mode of ddrescue implements a scripting interface similar to the one of @uref{http://www.gnu.org/software/ed/manual/ed_manual.html,,ed}. @ifnothtml @xref{Top,ed manual,,ed}. @end ifnothtml In this mode commands are read from the standard input and executed to copy parts of the input file to the output file, retrieve information from the mapfile, or write the mapfile to disc. Ddrescue's responses are written to standard output. "done\n" for a successfully executed command, "error\n" for a failed command (for example because of wrong arguments), and @w{"error: @var{error message}\n"} for serious or fatal errors like write errors. If end-of-file is detected on standard input, ddrescue discards any partial command being read and executes the @samp{f} (finish) command. All ddrescue commands are single characters, though some require additonal parameters separated by spaces. Only one command is allowed per line. Ddrescue recognizes the following commands: @table @code @item c @var{pos} @var{size} Copy command. Copies a block of data from @var{infile} to @var{outfile} and updates the internal copy of the mapfile. The areas already marked as finished in the mapfile are not copied again. @item f Finish command. Compacts the internal copy of the mapfile and writes it to @var{mapfile} (if it was specified in the command line). Then prints "done\n" to standard output and quits. On startup, the mapfile is first compacted and then split following the rescue domain borders. The finish command compacts the mapfile again before exiting. If writing @var{mapfile} to disc fails, a non-interactive emergency save is tried before exiting. @xref{Emergency save}. @item q Quit command. Exits ddrescue. Does not update the mapfile. @item s @var{pos} @var{size} Status command. Writes to standard output one or more lines in mapfile format (@pxref{Mapfile structure}), showing the status of the areas included in the block requested. A line consisting of the string "done" marks the end of the list. @item u Update mapfile command. Writes the internal copy of the mapfile to @var{mapfile} (if it was specified in the command line). If update mapfile fails, you may try to fix the problem, for example deleting some files to make room for @var{mapfile}, before trying to update it again. @end table @node Fill mode @chapter Fill mode @cindex fill Mode When ddrescue is invoked with the option @option{--fill-mode} it operates in 'fill mode', which is different from the default 'rescue mode'. That is, in 'fill mode' ddrescue does not rescue anything. It only fills with data read from @var{infile} the blocks of @var{outfile} whose status character from @var{mapfile} coincides with one of the type characters specified in the argument to @option{--fill-mode}. If the argument to @option{--fill-mode} contains an @samp{l}, ddrescue writes location data (position, sector number, and status) into each sector filled. With bad sectors filled in this way, it should be possible to retry the recovery of important files, as the location of the error is known by looking into the unfinished copy of the file. In fill mode @var{infile} does not need to be seekable and it may be of any size. If it is too small, the data is 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 is read. Then the same data is written to every cluster or sector to be filled. Note that in fill mode @var{infile} is always read from position 0. If you specify a @option{--input-position}, it refers to the original @var{infile} from which @var{mapfile} was built, and is only used to calculate the offset between input and output positions. Note also that when filling the @var{infile} of the original rescue run you should not set @option{--output-position}, whereas when filling the @var{outfile} of the original rescue run you should keep the original offset between @option{--input-position} and @option{--output-position}. The option @option{--fill-mode} implies @option{--complete-only}. In fill mode @var{mapfile} is updated to allow resumability when interrupted or in case of a crash, but as nothing is being rescued @var{mapfile} is not destroyed. The status line is the only part of @var{mapfile} that is modified. @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 ddrescue --fill-mode=- <(printf "BAD-SECTOR ") outfile mapfile @end example And the following command line fills all the non-finished areas in the destination file with copies of the string @w{@samp{NON-RESCUED-SECTOR }}: @example ddrescue --fill-mode='?*/-' <(printf "NON-RESCUED-SECTOR ") outfile mapfile @end example @noindent Example 2: Wipe only the good sectors, leaving the bad sectors alone. This way, the drive still tests bad (i.e., with unreadable sectors). This is the fastest way of wiping a failing drive, and is especially useful when sending the drive back to the manufacturer for warranty replacement. @example ddrescue --fill-mode=+ --force /dev/zero bad_drive mapfile @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=- -f --synchronous /dev/zero bad_drive mapfile @end example @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. Don't use sparse writes. This yields a mapfile containing 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". Use @option{--fill-mode=l-} if you want location data. 3) Mount the copied drive (or the image file, via loopback device) read-only. 4) Grep for the fill string in all the files. Those files containing the string reside (at least partially) in damaged disc areas. Note that if all the damaged areas are in unused space, grep does not find the string in any file, which means that no files are damaged. 5) Take note of the location data of any important files that you want to retry. 6) Unmount the copied drive or image file. 7) Retry the sectors belonging to the important files until they are rescued or until it is clear that they can't be rescued. 8) 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 mapfile printf "DEADBEEF" > tmpfile ddrescue --fill-mode=l- tmpfile cdimage mapfile rm tmpfile mount -t iso9660 -o loop,ro cdimage /mnt/cdimage find /mnt/cdimage -type f -exec grep -l "DEADBEEF" '@{@}' ';' (note that my_thesis.txt has a bad sector at pos 0x1234_5000) umount /mnt/cdimage ddrescue -b2048 -i0x1234_5000 -s2048 -dr9 /dev/cdrom cdimage mapfile ddrescue --fill-mode=- /dev/zero cdimage mapfile mount -t iso9660 -o loop,ro cdimage /mnt/cdimage cp -a /mnt/cdimage/my_thesis.txt /safe/place/my_thesis.txt @end example @node Generate mode @chapter Generate mode @cindex generate Mode When ddrescue is invoked with the option @option{--generate-mode} it operates in 'generate mode', which is different from the default 'rescue mode'. That is, in 'generate mode' ddrescue does not rescue anything. It only tries to generate a @var{mapfile} for later use. So you didn't read the manual and started ddrescue without a @var{mapfile}. 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{@samp{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 @var{mapfile}, from @var{infile} and the (partial) copy in @var{outfile}, that is almost as good as an exact @var{mapfile}. 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 @var{mapfile}, 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 nonzero. 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 mapfile with this command: @example ddrescue --generate-mode infile outfile mapfile @end example @noindent Note that you must keep the original offset between @option{--input-position} and @option{--output-position} of the original rescue run. @node Ddrescuelog @chapter Ddrescuelog @cindex ddrescuelog Ddrescuelog is a tool that manipulates ddrescue mapfiles, shows mapfile contents, converts mapfiles to/from other formats, compares mapfiles, tests rescue status, and can delete a mapfile if the rescue is done. Ddrescuelog operations can be restricted to one or several parts of the mapfile if the domain setting options are used. When performing logic operations (AND, OR, XOR) on mapfiles of different extension, only the blocks present in both files are processed. Other blocks are left untouched. Here are some examples of how to use ddrescuelog, alone or in combination with other tools. @noindent Example 1: Delete the mapfile if the rescue is finished (all data have been recovered without errors left). @example ddrescue -f /dev/sda /dev/sdb mapfile ddrescuelog -d mapfile @end example @sp 1 @noindent Example 2: Rescue two ext2 partitions in @file{/dev/sda} to @file{/dev/sdb} and repair the file systems using badblocks lists generated with ddrescuelog. File system block size is 4096.@* Note: you do need to partition @file{/dev/sdb} beforehand. @example fdisk /dev/sdb # partition /dev/sdb ddrescue -f /dev/sda1 /dev/sdb1 mapfile1 ddrescue -f /dev/sda2 /dev/sdb2 mapfile2 ddrescuelog -l- -b4096 mapfile1 > badblocks1 ddrescuelog -l- -b4096 mapfile2 > badblocks2 e2fsck -v -f -L badblocks1 /dev/sdb1 e2fsck -v -f -L badblocks2 /dev/sdb2 @end example @sp 1 @anchor{double-b} @noindent Example 3: Rescue a whole disc with two ext2 partitions in @file{/dev/sda} to @file{/dev/sdb} and repair the file systems using badblocks lists generated with ddrescuelog. Disc sector size is 512 (first @option{-b}), file system block size is 4096 (second @option{-b}). Arguments to options @option{-i} and @option{-s} are the starting positions and sizes of the partitions being rescued.@* Note: you don't need to partition @file{/dev/sdb} beforehand, but if the partition table on @file{/dev/sda} is damaged, you'll need to recreate it somehow on @file{/dev/sdb}. @example ddrescue -f /dev/sda /dev/sdb mapfile fdisk /dev/sdb # get partition sizes ddrescuelog -l- -b512 -i63s -o0 -s767457s -b4096 mapfile > badblocks1 ddrescuelog -l- -b512 -i767520s -o0 -s96520s -b4096 mapfile > badblocks2 e2fsck -v -f -L badblocks1 /dev/sdb1 e2fsck -v -f -L badblocks2 /dev/sdb2 @end example @node Invoking ddrescuelog @chapter Invoking ddrescuelog @cindex invoking ddrescuelog The format for running ddrescuelog is: @example ddrescuelog [@var{options}] @var{mapfile} @end example Use a hyphen @samp{-} as @var{mapfile} to read the mapfile from standard input (also in the options taking a mapfile argument) or to write the mapfile created by @option{--create-mapfile} to standard output. @noindent ddrescuelog supports the following options: @xref{Argument syntax}. @table @code @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. This version number should be included in all bug reports. @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 command @samp{tr} does, and write the resulting mapfile to standard output. @var{old_types} and @var{new_types} are strings of block status characters as defined in the chapter Mapfile structure (@pxref{Mapfile 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 -A @itemx --annotate-mapfile Add comments containing the human-readable positions and sizes of the blocks in @var{mapfile} which are included in the rescue domain, and write the resulting mapfile to standard output. @item -b @var{bytes} @itemx --block-size=@var{bytes} @itemx --sector-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. The position of each option @option{-b} in the command line is significant; it changes the sector size for the following options until a new option @option{-b} appears in the command line. @xref{double-b}. @item -B @itemx --binary-prefixes Show units with binary prefixes (powers of 1024).@* SI prefixes (powers of 1000) are used by default. (See table above, @ref{Invoking ddrescue}). @item -c[@var{type1}@var{type2}] @itemx --create-mapfile[=@var{type1}@var{type2}] Create a @var{mapfile} from a list of sectors read from standard input. The option @option{--format} determines the format of the input: either a list of sector numbers, or a bitmap. The sector numbers may be unordered. Only sectors included in the rescue domain are added to @var{mapfile}. If the mapfile is being created displaced from the input domain, the offset between @option{-i} and @option{-o} must be a multiple of the sector size. In this case, remember to specify @option{-o} because it defaults to the same value given to @option{-i}, producing a default offset of 0. @var{type1} and @var{type2} are block status characters as defined in the chapter Mapfile structure (@pxref{Mapfile structure}). @var{type1} sets the type for blocks included in the list, while @var{type2} sets the type for the rest of @var{mapfile}. If not specified, @var{type1} defaults to @samp{+} and @var{type2} defaults to @samp{-}. @item -C[@var{type}] @itemx --complete-mapfile[=@var{type}] Complete a synthetic (user fabricated) @var{mapfile} by filling the gaps with blocks of type @var{type}, and write the completed mapfile to standard output. @var{type} is one of the block status characters defined in the chapter Mapfile structure (@pxref{Mapfile structure}). If @var{type} is not specified, the gaps are filled with non-tried blocks. All gaps in @var{mapfile} are filled. Domain options are ignored. @item -d @itemx --delete-if-done Delete the given @var{mapfile} if all the blocks in the rescue domain have been successfully recovered. The exit status is 0 if @var{mapfile} could be deleted, 1 otherwise. If the mapfile is read from standard input, behave like @option{--done-status}. (There is nothing to delete). @item -D @itemx --done-status Test if all the blocks in the rescue domain have been successfully recovered. The exit status is 0 if all tested blocks are finished, 1 otherwise. @item -f @itemx --force Force overwrite of @var{mapfile}. @item -F @var{name} @itemx --format=@var{name} Select the input format for @option{--create-mapfile}, or the output format for @option{--list-blocks}. The valid names are @samp{list}, @samp{bitmap}, @samp{bitmap-be} (big endian), and @samp{bitmap-le} (little endian). Plain @samp{bitmap} is equivalent to @samp{bitmap-le}. The default format is @samp{list} (a list of block numbers). In a big endian bitmap the first block is represented by the most significant bit of the first byte. In a little endian bitmap the first block is represented by the least significant bit of the first byte. @item -H @var{C}:@var{H}:@var{S}:@var{track_order}:@var{bad_head} @itemx --make-test=@var{C}:@var{H}:@var{S}:@var{track_order}:@var{bad_head} Create a domain mapfile simulating a failing head for the test mode of ddrescue. @var{C}:@var{H}:@var{S} means @var{cylinders}:@var{heads}:@var{sectors}. For discs with variable number of sectors per track, @var{S} is specified as @samp{@var{sectors_first_track}-@var{sectors_last_track}[,@var{tracks_per_zone}]}. @var{track_order} is one of @samp{F} (forward), or @samp{FF} (hybrid serpentine). @var{bad_head} is a number in the range 0 to @w{@var{heads} - 1}. @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 @var{infile}. @item -l @var{types} @itemx --list-blocks=@var{types} By default print on standard output the sector numbers of the blocks specified as any of @var{types} in @var{mapfile} and included in the rescue domain. The list format is one sector number per line in decimal, like the output of the program @samp{badblocks}, so that it can be used as input for e2fsck or other similar filesystem repairing tool. If a bitmap @option{--format} is specified, write to standard output a bitmap of the endianness chosen, with ones for the sectors specified and zeros for sectors from other block types. The bits set to 1 in the bitmap should be equivalent to the list of blocks. @var{types} contains one or more of the block status characters defined in the chapter Mapfile structure (@pxref{Mapfile structure}). If the output numbers or bits are being created displaced from their position in the input domain, the offset between @option{-i} and @option{-o} must be a multiple of the block size. In this case, remember to specify @option{-o} because it defaults to the same value given to @option{-i}, producing a default offset of 0. A sector is listed (or set to 1 in bitmap output) if selected, even partially. (The positions and sizes of the mapfile blocks are not required to be multiples of the sector size). @item -L @itemx --loose-domain Accept an incomplete synthetic (user fabricated) domain mapfile or compare-as-domain mapfile, and fill the gaps in the list of data blocks with non-tried blocks. The blocks in the mapfile may be unordered, may overlap other blocks of the same status, and don't need to be contiguous. This option allows making quick edits to a mapfile without all the size calculations involved in making all data blocks contiguous again. @item -m @var{file} @itemx --domain-mapfile=@var{file} Restrict the rescue domain to the blocks marked as finished in the mapfile @var{file}. @item -n @itemx --invert-mapfile Invert the types of the blocks in @var{mapfile} which are included in the rescue domain, and write the resulting mapfile to standard output. Finished blocks (@samp{+}) are changed to bad-sector (@samp{-}), all other types are changed to finished. @option{--invert-mapfile} is equivalent to @option{--change-types=?*/-+,++++-} @item -o @var{bytes} @itemx --output-position=@var{bytes} Starting position of the image of the rescue domain in the original @var{outfile}, in bytes. It is used by the options @option{--create-mapfile}, @option{--list-blocks}, and @option{--shift}. Defaults to @option{--input-position}. @item -p @var{file} @itemx --compare-mapfile=@var{file} Compare the types of the blocks included in the rescue domain. The exit status is 0 if all the blocks tested are the same in both @var{file} and @var{mapfile}, 1 otherwise. @item -P @var{file} @itemx --compare-as-domain=@var{file} Compare only the blocks marked as finished in the rescue domain. The exit status is 0 if all the blocks tested are the same in both @var{file} and @var{mapfile}, 1 otherwise. Two files comparing equal with this option are equivalent when used as domain mapfiles. @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 @var{infile}. -1 removes any previous size limit. @item -t @itemx --show-status Print a summary of the contents of each @var{mapfile} to the standard output. This option allows more than one @var{mapfile}. If the domain setting options are used, the summary can be restricted to one or several parts of @var{mapfile}. @item -v @itemx --verbose Verbose mode. Further -v's (up to 4) increase the verbosity level. @item -x @var{file} @itemx --xor-mapfile=@var{file} Perform a logical XOR (exclusive OR) operation between the finished blocks in @var{file} and those in @var{mapfile}, and write the resulting mapfile to standard output. In other words, in the resulting mapfile a block is only shown as finished if it was finished in either of the two input mapfiles but not in both. @item -y @var{file} @itemx --and-mapfile=@var{file} Perform a logical AND operation between the finished blocks in @var{file} and those in @var{mapfile}, and write the resulting mapfile to standard output. In other words, in the resulting mapfile a block is only shown as finished if it was finished in both input mapfiles. @item -z @var{file} @itemx --or-mapfile=@var{file} Perform a logical OR operation between the finished blocks in @var{file} and those in @var{mapfile}, and write the resulting mapfile to standard output. In other words, in the resulting mapfile a block is shown as finished if it was finished in either of the two input mapfiles. @item --shift Shift the positions of all the blocks in @var{mapfile} by the offset @w{(@option{--output-position} - @option{--input-position})}, and write the resulting mapfile to standard output. Either @option{--input-position} or @option{--output-position} must be 0. Any blocks beyond the end of the rescue domain are removed before performing the shift. The remaining blocks are shifted even if they are outside the rescue domain. If the offset is positive, a non-tried block is inserted before the first block to fill the gap. @end table Exit status: 0 for a normal exit, 1 for environmental problems (file not found, invalid command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., 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.30/doc/ddrescuelog.1000066400000000000000000000110701512716454500165420ustar00rootroot00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. .TH DDRESCUELOG "1" "January 2026" "GNU ddrescuelog 1.30" "User Commands" .SH NAME ddrescuelog \- tool for ddrescue mapfiles .SH SYNOPSIS .B ddrescuelog [\fI\,options\/\fR] \fI\,mapfile\/\fR .SH DESCRIPTION GNU ddrescuelog is a tool that manipulates ddrescue mapfiles, shows mapfile contents, converts mapfiles to/from other formats, compares mapfiles, tests rescue status, and can delete a mapfile if the rescue is done. Ddrescuelog operations can be restricted to one or several parts of the mapfile if the domain setting options are used. .PP Use a hyphen '\-' as mapfile to read the mapfile from standard input (also in the options taking a mapfile argument) or to write the mapfile created by '\-\-create\-mapfile' to standard output. .PP NOTE: In versions of ddrescue prior to 1.20 the mapfile was called \&'logfile'. The format is the same; only the name has changed. .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 mapfile .TP \fB\-A\fR, \fB\-\-annotate\-mapfile\fR add comments with human\-readable pos/sizes .TP \fB\-b\fR, \fB\-\-block\-size=\fR block (sector) size in bytes [default 512] .TP \fB\-B\fR, \fB\-\-binary\-prefixes\fR show binary multipliers in numbers [SI] .TP \fB\-c\fR, \fB\-\-create\-mapfile[=\fR] create mapfile from list of blocks [+\-] .TP \fB\-C\fR, \fB\-\-complete\-mapfile[=\fR] complete mapfile adding blocks of type t [?] .TP \fB\-d\fR, \fB\-\-delete\-if\-done\fR delete the mapfile 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\-F\fR, \fB\-\-format=\fR format for \fB\-c\fR and \fB\-l\fR (list, bitmap\-[bl]e) .TP \fB\-H\fR, \fB\-\-make\-test=\fR create mapfile for test mode of ddrescue .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\-L\fR, \fB\-\-loose\-domain\fR accept unordered domain mapfile with gaps .TP \fB\-m\fR, \fB\-\-domain\-mapfile=\fR restrict domain to finished blocks in .TP \fB\-n\fR, \fB\-\-invert\-mapfile\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\-mapfile=\fR compare block types in domain of both files .TP \fB\-P\fR, \fB\-\-compare\-as\-domain=\fR like \fB\-p\fR but compare finished blocks only .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 mapfile contents .TP \fB\-v\fR, \fB\-\-verbose\fR be verbose (a 2nd \fB\-v\fR gives more) .TP \fB\-x\fR, \fB\-\-xor\-mapfile=\fR XOR the finished blocks in file with mapfile .TP \fB\-y\fR, \fB\-\-and\-mapfile=\fR AND the finished blocks in file with mapfile .TP \fB\-z\fR, \fB\-\-or\-mapfile=\fR OR the finished blocks in file with mapfile .TP \fB\-\-shift\fR shift all block positions by (opos \- ipos) .PP Numbers may be in decimal, hexadecimal, or octal, may contain underscore separators between groups of digits, and may be followed by a SI or binary multiplier and 's' for 'sectors': 1_234_567kB, 4Kis, 0x1234_5678, 07_777. The syntax of the argument of option '\-H' is .SH "EXIT STATUS" 0 for a normal exit, 1 for environmental problems (file not found, invalid command\-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., 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 2026 Antonio Diaz Diaz. License GPLv2+: GNU GPL version 2 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 ddrescuelog is maintained as a Texinfo manual. If the .B info and .B ddrescuelog programs are properly installed at your site, the command .IP .B info ddrescue .PP should give you access to the complete manual. gddrescue-1.30/fillbook.cc000066400000000000000000000165541512716454500155370ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" #include "mapbook.h" // Return values: 1 write error, 0 OK. // int Fillbook::fill_block( const Sblock & sb ) { if( sb.size() <= 0 || sb.size() > softbs() ) internal_error( "bad size filling a Block." ); const int size = sb.size(); if( write_location_data ) // write location data into each sector for( long long pos = sb.pos(); pos < sb.end(); pos += hardbs() ) { char * const buf = (char *)iobuf() + ( pos - sb.pos() ); const int bufsize = std::min( 80LL, sb.end() - pos ); const int len = snprintf( buf, bufsize, "\n# position 0x%08llX sector 0x%08llX status %c", pos, pos / hardbs(), sb.status() ); if( len > 0 && len < bufsize ) buf[len] = ' '; } if( writeblockp( odes_, iobuf(), size, sb.pos() + offset() ) != size || ( synchronous_ && fsync( odes_ ) != 0 && errno != EINVAL ) ) { if( !ignore_write_errors ) final_msg( oname_, wr_err_msg, errno ); return 1; } filled_size += size; remaining_size -= size; return 0; } // Return values: 1 write error, 0 OK, -1 interrupted, -2 mapfile error. // int Fillbook::fill_areas() { const char * const msg = "Filling blocks..."; bool first_post = true; for( long 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, msg ); while( b.size() > 0 ) { current_pos( b.pos() ); if( verbosity >= 0 ) { show_status( b.pos(), msg, first_post ); first_post = false; } if( interrupted() ) return -1; const int retval = fill_block( Sblock( b, sb.status() ) ); 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_mapfile( odes_ ) ) return -2; b.pos( b.end() ); if( b.end() > sb.end() ) b.crop( sb ); } ++filled_areas; --remaining_areas; } fsync( odes_ ); // prevent early exit if kernel caches writes return 0; } void Fillbook::show_status( const long long ipos, const char * const msg, bool force ) { const char * const up = "\x1B[A"; if( t0 == 0 ) { t0 = t1 = initial_time(); first_size = last_size = filled_size; force = true; std::fputs( "\n\n\n", stdout ); } if( ipos >= 0 ) last_ipos = ipos; const long long t2 = std::time( 0 ); if( t2 < t1 ) // clock jumped back { t0 -= std::min( t0, t1 - t2 ); t1 = t2; } 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: %9sB, filled areas: %7s, current rate: %8sB/s\n", format_num( filled_size ), format_num3( filled_areas ), format_num( c_rate, 99999 ) ); std::printf( "remain size: %9sB, remain areas: %7s, average rate: %8sB/s\n", format_num( remaining_size ), format_num3( remaining_areas ), format_num( a_rate, 99999 ) ); std::printf( "current pos: %9sB, run time: %12s\n", format_num( last_ipos + offset() ), format_time( t1 - t0 ) ); if( msg && *msg ) { const int len = std::strlen( msg ); std::printf( "\r%s", msg ); for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout ); oldlen = len; } safe_fflush( stdout ); } } // Return values: 1 write error, 0 OK. // int Fillbook::do_fill( const int odes ) { 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( long 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::fputs( ctrlc_msg, stdout ); if( mapfile_exists() ) { std::fputs( initial_msg, stdout ); std::printf( "filled size: %9sB, filled areas: %7s\n", format_num( filled_size ), format_num3( filled_areas ) ); std::printf( "remaining size: %9sB, remaining areas: %7s\n", format_num( remaining_size ), format_num3( remaining_areas ) ); std::fputs( "Current status\n", stdout ); } } int retval = fill_areas(); const bool signaled = retval == -1; if( signaled ) retval = 0; if( verbosity >= 0 ) { show_status( -1, ( retval || signaled ) ? 0 : "Finished", true ); if( retval == -2 ) std::fputs( "\nMapfile error", stdout ); else if( signaled ) std::fputs( "\nInterrupted by user", stdout ); std::fputc( '\n', stdout ); safe_fflush( stdout ); } if( retval == -2 ) retval = 1; // mapfile error else { if( retval == 0 && !signaled ) current_status( finished ); compact_sblock_vector(); if( !update_mapfile( odes_, true ) && retval == 0 ) retval = 1; } if( final_msg().size() ) show_error( final_msg().c_str(), final_errno() ); if( close( odes_ ) != 0 ) { show_file_error( oname_, "Error closing outfile", errno ); if( retval == 0 ) retval = 1; } if( retval ) return retval; // errors have priority over signals if( signaled ) return signaled_exit(); return 0; } bool Fillbook::read_buffer( const int ides ) { const int rd = readblock( ides, iobuf(), softbs() ); if( rd <= 0 || errno != 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; } gddrescue-1.30/genbook.cc000066400000000000000000000154031512716454500153520ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" #include "mapbook.h" const char * format_time( const long long t, const bool low_prec ) { enum { buffers = 8, bufsize = 16 }; static char buffer[buffers][bufsize]; // circle of buffers for printf static int current = 0; if( t < 0 ) return "n/a"; char * const buf = buffer[current++]; current %= buffers; const int s = t % 60; const int m = ( t / 60 ) % 60; const int h = ( t / 3600 ) % 24; const int d = ( t / 86400 ) % 365; const long long y = t / 31536000; int len = 0; // max len is 11 chars (10h 10m 10s) if( y > 0 ) len = snprintf( buf, bufsize, "%lldy", y ); if( len >= 7 ) return buf; if( d > 0 && len >= 0 ) { len += snprintf( buf + len, bufsize - len, "%s%dd", len ? ( (d < 10) ? " " : " " ) : "", d ); if( y > 0 ) return buf; } if( h > 0 && len >= 0 && len <= 7 ) len += snprintf( buf + len, bufsize - len, "%s%dh", len ? ( (h < 10) ? " " : " " ) : "", h ); if( m > 0 && len >= 0 && len <= 7 ) len += snprintf( buf + len, bufsize - len, "%s%dm", len ? ( (m < 10) ? " " : " " ) : "", m ); if( ( s > 0 && len >= 0 && len <= 7 && !low_prec ) || len == 0 ) len += snprintf( buf + len, bufsize - len, "%s%ds", len ? ( (s < 10) ? " " : " " ) : "", s ); return buf; } // 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 = readblockp( 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, domain() ); finished_size += size; } gensize += size; pos += size; } } // Return values: 1 unexpected EOF, 0 OK, -1 interrupted, -2 mapfile error. // int Genbook::check_all() { const char * const msg = "Generating mapfile..."; 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, domain(), hardbs() ); if( b.size() <= 0 ) break; pos = b.end(); current_status( generating, msg ); current_pos( b.pos() ); if( verbosity >= 0 ) { show_status( b.pos(), msg, 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( iname_, early_eof_msg ); return 1; } if( !update_mapfile() ) return -2; } return 0; } 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 = initial_time(); first_size = last_size = gensize; force = true; std::fputs( "\n\n", stdout ); } if( ipos >= 0 ) last_ipos = ipos; const long long t2 = std::time( 0 ); if( t2 < t1 ) // clock jumped back { t0 -= std::min( t0, t1 - t2 ); t1 = t2; } 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: %9sB, generated: %9sB, current rate: %8sB/s\n", format_num( finished_size ), format_num( gensize ), format_num( c_rate, 99999 ) ); std::printf( " opos: %9sB, run time: %11s, average rate: %8sB/s\n", format_num( last_ipos + offset() ), format_time( t1 - t0 ), format_num( a_rate, 99999 ) ); if( msg && *msg ) { const int len = std::strlen( msg ); std::printf( "\r%s", msg ); for( int i = len; i < oldlen; ++i ) std::fputc( ' ', stdout ); oldlen = len; } safe_fflush( stdout ); } } // Return values: 1 write error, 0 OK. // int Genbook::do_generate( const int odes ) { finished_size = 0; gensize = 0; odes_ = odes; for( long i = 0; i < sblocks(); ++i ) { const Sblock & sb = sblock( i ); if( !domain().includes( sb ) ) { if( domain() < sb ) break; else continue; } if( sb.status() == sb.finished ) finished_size += sb.size(); if( sb.status() != sb.non_tried ) gensize += sb.size(); } set_signals(); if( verbosity >= 0 ) { std::fputs( ctrlc_msg, stdout ); if( mapfile_exists() ) { std::fputs( initial_msg, stdout ); std::printf( "rescued: %9sB, generated: %9sB\n", format_num( finished_size ), format_num( gensize ) ); std::fputs( "Current status\n", stdout ); } } int retval = check_all(); const bool signaled = retval == -1; if( signaled ) retval = 0; if( verbosity >= 0 ) { show_status( -1, ( retval || signaled ) ? 0 : "Finished", true ); if( retval == -2 ) std::fputs( "\nMapfile error", stdout ); else if( signaled ) std::fputs( "\nInterrupted by user", stdout ); std::fputc( '\n', stdout ); safe_fflush( stdout ); } if( retval == -2 ) retval = 1; // mapfile error else { if( retval == 0 && !signaled ) current_status( finished ); compact_sblock_vector(); if( !update_mapfile( -1, true ) && retval == 0 ) retval = 1; } if( final_msg().size() ) show_error( final_msg().c_str(), final_errno() ); if( retval ) return retval; // errors have priority over signals if( signaled ) return signaled_exit(); return 0; } gddrescue-1.30/io.cc000066400000000000000000000062741512716454500143430ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" #include "mapbook.h" namespace { int volatile signum_ = 0; // user pressed Ctrl-C or similar extern "C" void sighandler( int signum ) { if( signum_ == 0 && signum > 0 ) signum_ = signum; } int set_signal( const int signum, void (*handler)( int ) ) { struct sigaction new_action; new_action.sa_handler = handler; sigemptyset( &new_action.sa_mask ); new_action.sa_flags = SA_RESTART; return sigaction( signum, &new_action, 0 ); } } // end namespace /* Return the number of bytes really read. If (value returned < size) and (errno == 0), means EOF was reached. */ int readblock( const int fd, uint8_t * const buf, const int size ) { int sz = 0; errno = 0; while( sz < size ) { const int n = read( fd, buf + sz, size - sz ); if( n > 0 ) sz += n; else if( n == 0 ) break; // EOF else if( errno != EINTR ) break; errno = 0; } return sz; } /* Return the number of bytes really read. If (value returned < size) and (errno == 0), means EOF was reached. */ int readblockp( const int fd, uint8_t * const buf, const int size, const long long pos ) { int sz = 0; errno = 0; if( lseek( fd, pos, SEEK_SET ) >= 0 ) // returns 0 for /dev/zero while( sz < size ) { errno = 0; const int n = read( fd, buf + sz, size - sz ); if( n > 0 ) sz += n; else if( n == 0 ) break; // EOF else if( errno != EINTR ) break; } return sz; } /* Return the number of bytes really written. If (value returned < size), it is always an error. */ int writeblockp( const int fd, const uint8_t * const buf, const int size, const long long pos ) { int sz = 0; errno = 0; if( lseek( fd, pos, SEEK_SET ) >= 0 ) // returns 0 for /dev/null while( sz < size ) { errno = 0; const int n = write( fd, buf + sz, size - sz ); if( n > 0 ) sz += n; else if( n < 0 && errno != EINTR ) break; } return sz; } bool interrupted() { return ( signum_ > 0 ); } void set_signals() { signum_ = 0; set_signal( SIGHUP, sighandler ); set_signal( SIGINT, sighandler ); set_signal( SIGTERM, sighandler ); set_signal( SIGUSR1, SIG_IGN ); set_signal( SIGUSR2, SIG_IGN ); } int signaled_exit() { set_signal( signum_, SIG_DFL ); std::raise( signum_ ); return 128 + signum_; // in case std::raise fails to exit } gddrescue-1.30/loggers.cc000066400000000000000000000147511512716454500153750ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2013-2026 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 2 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 "mapfile.h" #include "loggers.h" namespace { const char * format_time_dhms( const long long t ) { static char buf[64]; const int s = t % 60; const int m = ( t / 60 ) % 60; const int h = ( t / 3600 ) % 24; const int d = ( t / 86400 ) % 365; const long long y = t / 31536000; if( y ) snprintf( buf, sizeof buf, "%lldy:%dd:%02dh:%02dm:%02ds", y, d, h, m, s ); else if( d ) snprintf( buf, sizeof buf, "%dd:%02dh:%02dm:%02ds", d, h, m, s ); else if( h ) snprintf( buf, sizeof buf, "%dh:%02dm:%02ds", h, m, s ); else if( m ) snprintf( buf, sizeof buf, "%dm:%02ds", m, s ); else snprintf( buf, sizeof buf, "%ds", s ); return buf; } } // end namespace Event_logger event_logger; Rate_logger rate_logger; Read_logger read_logger; void Logger::set_filename( const char * const name ) { if( !name || !*name ) return; // ignore name if( std::strcmp( name, "-" ) == 0 ) { show_error( "I won't write log data to standard output." ); std::exit( 1 ); } struct stat st; if( stat( name, &st ) == 0 && !S_ISREG( st.st_mode ) ) { show_file_error( name, "Logfile exists and is not a regular file." ); std::exit( 1 ); } filename_ = name; } bool Logger::close_file() { if( f && !error && !write_final_timestamp( f ) ) error = true; if( f && std::fclose( f ) != 0 ) error = true; // close even on error f = 0; return !error; } bool Event_logger::open_file() { if( !filename_ ) return true; if( !f ) { struct stat st; const bool file_exists = stat( filename_, &st ) == 0; f = std::fopen( filename_, "a" ); error = !f || ( file_exists && std::fputc( '\n', f ) == EOF ) || !write_file_header( f, "Events Logfile" ) || std::fputs( "# Time Rescued Event\n", f ) == EOF; } return !error; } bool Event_logger::echo_msg( const char * const msg ) { if( verbosity >= 0 ) std::printf( "\n %s", msg ); if( f && !error && std::fprintf( f, " %s\n", msg ) < 0 ) error = true; return !error; } bool Event_logger::print_msg( const long long time, const long long finished_size, const char * const percent_rescued, const char * const msg, const char * const a_rate, const unsigned long read_errors ) { if( f && !error ) { if( std::fprintf( f, "%15s %7sB/s %s\n%27s %s %7s read errors\n", format_time_dhms( time ), a_rate, msg, format_num3( finished_size ), percent_rescued, format_num3( read_errors ) ) < 0 ) error = true; else std::fflush( f ); } return !error; } bool Event_logger::print_eor( const long long time, const long long finished_size, const char * const percent_rescued, const long long current_pos, const char * const current_status_name, const char * const a_rate, const unsigned long read_errors ) { if( f && !error ) { if( std::fprintf( f, "%15s %7sB/s End of run (0x%08llX %s)\n" "%27s %s %7s read errors\n", format_time_dhms( time ), a_rate, current_pos, current_status_name, format_num3( finished_size ), percent_rescued, format_num3( read_errors ) ) < 0 ) error = true; else std::fflush( f ); } return !error; } bool Rate_logger::open_file() { if( !filename_ ) return true; if( !f ) { last_time = -1; f = std::fopen( filename_, "w" ); error = !f || !write_file_header( f, "Rates Logfile" ) || std::fputs( "#Time Ipos Current_rate Average_rate Bad_areas Bad_size\n", f ) == EOF; } return !error; } bool Rate_logger::print_line( const long long time, const long long ipos, const long long a_rate, const long long c_rate, const unsigned long bad_areas, const long long bad_size ) { if( f && !error && time > last_time ) { last_time = time; if( std::fprintf( f, "%2lld 0x%08llX %8lld %8lld %7lu %8lld\n", time, ipos, c_rate, a_rate, bad_areas, bad_size ) < 0 ) error = true; } return !error; } bool Read_logger::open_file() { if( !filename_ ) return true; if( !f ) { prev_is_msg = true; f = std::fopen( filename_, "w" ); error = !f || !write_file_header( f, "Reads Logfile" ) || std::fputs( "# Ipos Size Copied_size Error_size Errno\n", f ) == EOF; } return !error; } bool Read_logger::print_line( const long long ipos, const long long size, const int copied_size, const int error_size, const int errcode ) { if( f && !error ) { if( errcode <= 0 || errcode == EIO ) { if( std::fprintf( f, "0x%08llX %lld %d %d\n", ipos, size, copied_size, error_size ) < 0 ) error = true; } else { if( std::fprintf( f, "0x%08llX %lld %d %d %d\n", ipos, size, copied_size, error_size, errcode ) < 0 ) error = true; } } prev_is_msg = false; return !error; } bool Read_logger::print_msg( const long long time, const char * const msg ) { if( f && !error && std::fprintf( f, "%s# %s %s\n", prev_is_msg ? "" : "\n", format_time_dhms( time ), msg ) < 0 ) error = true; prev_is_msg = true; return !error; } bool Read_logger::print_time( const long long time ) { if( f && !error && time > 0 && std::fprintf( f, "# %s\n", format_time_dhms( time ) ) < 0 ) error = true; return !error; } gddrescue-1.30/loggers.h000066400000000000000000000051331512716454500152310ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2013-2026 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 2 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 . */ // requires '#include ' for 'FILE *' class Logger { protected: const char * filename_; FILE * f; // output stream bool error; public: Logger() : filename_( 0 ), f( 0 ), error( false ) {} bool active() const { return ( f != 0 && !error ); } const char * filename() const { return filename_; } void set_filename( const char * const name ); bool close_file(); }; class Event_logger : public Logger { public: bool open_file(); bool echo_msg( const char * const msg ); bool print_msg( const long long time, const long long finished_size, const char * const percent_rescued, const char * const msg, const char * const a_rate, const unsigned long read_errors ); bool print_eor( const long long time, const long long finished_size, const char * const percent_rescued, const long long current_pos, const char * const current_status_name, const char * const a_rate, const unsigned long read_errors ); }; extern Event_logger event_logger; class Rate_logger : public Logger { long long last_time; public: Rate_logger() : last_time( -1 ) {} bool open_file(); bool print_line( const long long time, const long long ipos, const long long a_rate, const long long c_rate, const unsigned long bad_areas, const long long bad_size ); }; extern Rate_logger rate_logger; class Read_logger : public Logger { bool prev_is_msg; public: Read_logger() : prev_is_msg( true ) {} bool open_file(); bool print_line( const long long ipos, const long long size, const int copied_size, const int error_size, const int errcode ); bool print_msg( const long long time, const char * const msg ); bool print_time( const long long time ); }; extern Read_logger read_logger; gddrescue-1.30/main.cc000066400000000000000000001265761512716454500146700ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid input file, 3 for an internal consistency error (e.g., bug) which caused ddrescue to panic. */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include // SIZE_MAX #include #include #include "mapfile.h" #include "arg_parser.h" #include "loggers.h" #include "mapbook.h" #include "non_posix.h" #include "rational.h" #include "rescuebook.h" #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef O_DIRECT #define O_DIRECT 0 #endif #if CHAR_BIT != 8 #error "Environments where CHAR_BIT != 8 are not supported." #endif #if ( defined SIZE_MAX && SIZE_MAX < UINT_MAX ) || \ ( defined SSIZE_MAX && SSIZE_MAX < INT_MAX ) #error "Environments where 'size_t' is narrower than 'int' are not supported." #endif namespace { const char * const Program_name = "GNU ddrescue"; const char * const program_name = "ddrescue"; const char * invocation_name = program_name; // default value enum Mode { m_none, m_command, m_fill, m_generate }; const mode_t outmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; void show_help( const int cluster, const int hardbs ) { std::fputs( "GNU ddrescue is a data recovery tool. It copies data from one file or block\n" "device (hard disc, cdrom, etc) to another, trying to rescue the good parts\n" "first in case of read errors.\n" "\nAlways use a mapfile unless you know you won't need it. Without a mapfile,\n" "ddrescue can't resume a rescue, only reinitiate it. Be careful to not\n" "specify by mistake an old mapfile from an unrelated rescue.\n" "\nNOTE: In versions of ddrescue prior to 1.20 the mapfile was called\n" "'logfile'. The format is the same; only the name has changed.\n" "\nIf you reboot, check the device names before restarting ddrescue.\n" "Don't use options '-F' or '-G' without reading the manual first.\n", stdout ); std::printf( "\nUsage: %s [options] infile outfile [mapfile]\n", invocation_name ); std::printf( "\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-trimmed, non-scraped 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::fputs( " -C, --complete-only don't read new data beyond mapfile limits\n" " -d, --idirect use direct disc access for input file\n" " -D, --odirect use direct disc access for output file\n" " -e, --max-bad-areas=[+] maximum number of [new] bad 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 blocks of given types with data (?*/-+l)\n" " -G, --generate-mode generate approximate mapfile from partial copy\n" " -H, --test-mode= set map of good/bad blocks from given mapfile\n" " -i, --input-position= starting position of domain in input file [0]\n" " -I, --check-input-size compare input file size with size in mapfile\n" " -J, --check-on-error reread latest good sector after every error\n" " -K, --skip-size=[][,] initial,maximum size to skip on read error\n" " -L, --loose-domain accept unordered domain mapfile with gaps\n" " -m, --domain-mapfile= restrict domain to finished blocks in \n" " -M, --retrim mark some failed blocks as non-trimmed\n" " -n, --no-scrape skip the scraping phase\n" " -N, --no-sweep skip the sweeping phase\n" " --no-trim skip the trimming phase\n" " -o, --output-position= starting position in output file [ipos]\n" " -O, --reopen-on-error reopen input file after every read error\n" " -p, --preallocate preallocate space on disc for output file\n" " -P, --data-preview[=] show some lines of the latest data read [3]\n" " -q, --quiet suppress all messages\n" " -r, --retry-passes= exit after retry passes (-1=infinity) [0]\n" " -R, --reverse reverse the direction of all passes\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" " -u, --unidirectional run all passes in the same direction\n" " -v, --verbose be verbose (a 2nd -v gives more)\n" " -w, --ignore-write-errors make fill mode ignore write errors\n" " -W, --compare-before-write omit superfluous writes in rescue mode\n" " -x, --extend-outfile= extend outfile size to be at least this long\n" " -X, --max-read-errors= maximum number of read errors allowed\n" " -y, --synchronous use synchronous writes for output file\n" " -Z, --max-read-rate= maximum read rate in bytes/s\n" " --ask ask for confirmation before starting the copy\n" " --bad-sector-data= treat sectors with data as read errors\n" " --command-mode execute commands from standard input\n" " --continue-on-errno=[,] treat errno code as non-fatal\n" " --cpass= select what copying pass(es) to run\n" " --delay-slow= initial delay before checking slow reads [30]\n" " --log-events= log significant events in \n" " --log-rates= log rates and error sizes in \n" " --log-reads= log all read operations in \n" " --mapfile-interval=[i][,i] save/sync mapfile at given interval [auto]\n" " --max-slow-reads= maximum number of slow reads allowed\n" " --pause-on-error= time to wait after each read error [0]\n" " --pause-on-pass= time to wait between passes [0]\n" " --reset-slow reset slow reads if rate rises above min\n" " --same-file allow infile and outfile to be the same file\n" "\nNumbers may be in decimal, hexadecimal, or octal, may contain underscore\n" "separators between groups of digits, and may be followed by a SI or binary\n" "multiplier and 's' for 'sectors': 1_234_567kB, 4Kis, 0x1234_5678, 07_777.\n" "In rescue mode, '--size=output' uses the size of the output file or device.\n" "Time intervals have the format 1[.5][smhd] or 1/2[smhd].\n" "\n*Exit status*\n" "0 for a normal exit, 1 for environmental problems (file not found, invalid\n" "command-line options, I/O errors, etc), 2 to indicate a corrupt or invalid\n" "input file, 3 for an internal consistency error (e.g., bug) which caused\n" "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", stdout ); } } // end namespace #include "main_common.cc" namespace { const char * const inoseek_msg = "Input file is not seekable."; const char * const onoseek_msg = "Output file is not seekable."; /* Recognized formats: [unit] Where the optional "unit" is one of 's', 'm', 'h', or 'd'. Return the number of seconds, or exit with status 1 if error. */ Rational parse_rational_time( const char * const arg, const char * const pn, const bool comma = false, const int max_den = 100 ) { Rational r; int c = r.parse( arg ); if( c > 0 ) { switch( arg[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; case ',': if( comma ) break; // fall through default: show_option_error( arg, "Bad unit in time interval argument of", pn ); std::exit( 1 ); } if( !comma && arg[c] != 0 && arg[c] != ',' && arg[c+1] == ',' ) { show_option_error( arg, "Extra characters in argument of", pn ); std::exit( 1 ); } if( !r.error() && r >= 0 && r.denominator() <= max_den ) return r; } show_option_error( arg, "Bad value in time interval argument of", pn ); std::exit( 1 ); } int parse_time_interval( const char * const arg, const char * const pn, const bool comma = false ) { return parse_rational_time( arg, pn, comma, 1 ).trunc(); } bool check_files( const char * const iname, const char * const oname, const char * const mapname, const Rb_options & rb_opts, const bool force, const bool generate, const bool preallocate ) { if( !iname || !oname ) { show_error( "Both input and output files must be specified.", 0, true ); return false; } struct stat istat, ostat; bool iexists = false, oexists = 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 && !rb_opts.same_file ) { show_file_error( oname, "Infile and outfile are the same." ); return false; } if( mapname ) { struct stat mapstat; bool mapexists = false; same = std::strcmp( iname, mapname ) == 0; if( !same ) { mapexists = stat( mapname, &mapstat ) == 0; if( mapexists && !S_ISREG( mapstat.st_mode ) ) { show_file_error( mapname, "Mapfile exists and is not a regular file." ); return false; } if( iexists && mapexists && istat.st_ino == mapstat.st_ino && istat.st_dev == mapstat.st_dev ) same = true; } if( same ) { show_file_error( mapname, "Infile and mapfile are the same." ); return false; } if( std::strcmp( oname, mapname ) == 0 || ( oexists && mapexists && ostat.st_ino == mapstat.st_ino && ostat.st_dev == mapstat.st_dev ) ) { show_file_error( mapname, "Outfile and mapfile are the same." ); return false; } // just compare names because std::remove will break existing links std::string mapname_bak( mapname ); mapname_bak += ".bak"; if( mapname_bak == iname ) { show_file_error( iname, "Infile and mapfile backup are the same." ); return false; } if( mapname_bak == oname ) { show_file_error( oname, "Outfile and mapfile backup are the same." ); return false; } struct stat st; if( stat( mapname_bak.c_str(), &st ) == 0 && !S_ISREG( st.st_mode ) ) { show_file_error( mapname_bak.c_str(), "Mapfile backup exists and is not a regular file." ); return false; } } if( !generate && ( rb_opts.min_outfile_size >= 0 || !force || preallocate || rb_opts.sparse ) ) { struct stat st; if( stat( oname, &st ) == 0 && !S_ISREG( st.st_mode ) ) { show_file_error( oname, "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( preallocate ) show_error( "Only regular files can be preallocated.", 0, true ); else if( rb_opts.sparse ) show_error( "Only regular files can be sparse.", 0, true ); else if( rb_opts.min_outfile_size >= 0 ) show_error( "Only regular files can be extended.", 0, true ); return false; } } return true; } int do_fill( const long long offset, Domain & domain, const Fb_options & fb_opts, const Mb_options & mb_opts, const char * const iname, const char * const oname, const char * const mapname, const int cluster, const int hardbs, const int o_direct_out, const bool synchronous ) { if( !mapname ) { show_error( "Mapfile required in fill mode.", 0, true ); return 1; } Fillbook fillbook( offset, domain, fb_opts, mb_opts, oname, mapname, cluster, hardbs, synchronous ); if( !fillbook.mapfile_exists() ) return not_readable( fillbook.pname() ); if( fillbook.domain().empty() ) return empty_domain(); if( fillbook.read_only() ) return not_writable( fillbook.pname( false ) ); const int ides = open( iname, O_RDONLY | O_BINARY ); if( ides < 0 ) { show_file_error( iname, "Can't open input file", errno ); return 1; } if( !fillbook.read_buffer( ides ) ) { show_file_error( iname, "Error reading fill data from input file", errno ); return 1; } if( close( ides ) != 0 ) { show_file_error( iname, "Error closing infile", errno ); return 1; } const int odes = open( oname, O_WRONLY | O_CREAT | o_direct_out | O_BINARY, outmode ); if( odes < 0 ) { show_file_error( oname, "Can't open output file", errno ); return 1; } if( lseek( odes, 0, SEEK_SET ) ) { show_file_error( oname, onoseek_msg ); return 1; } if( verbosity >= 0 ) std::printf( "%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, fb_opts.filltypes.c_str() ); std::printf( " Maximum size to fill: %sBytes\n", format_num( fillbook.domain().in_size() ) ); std::printf( " Starting positions: infile = %sB, outfile = %sB\n", format_num( fillbook.domain().pos() ), format_num( fillbook.domain().pos() + fillbook.offset() ) ); std::printf( " Copy block size: %3d sectors\n", cluster ); std::printf( "Sector size: %sBytes\n", format_num( hardbs, 99999 ) ); std::printf( "Direct out: %s\n\n", o_direct_out ? "yes" : "no" ); } return fillbook.do_fill( odes ); } int do_generate( const long long offset, Domain & domain, const Mb_options & mb_opts, const char * const iname, const char * const oname, const char * const mapname, const int cluster, const int hardbs ) { if( !mapname ) { show_error( "Mapfile must be specified in generate mode.", 0, true ); return 1; } const int ides = open( iname, O_RDONLY | O_BINARY ); if( ides < 0 ) { show_file_error( iname, "Can't open input file", errno ); return 1; } const long long insize = lseek( ides, 0, SEEK_END ); if( insize < 0 ) { show_file_error( iname, inoseek_msg ); return 1; } Genbook genbook( offset, insize, domain, mb_opts, iname, mapname, cluster, hardbs ); if( genbook.domain().empty() ) return empty_domain(); if( !genbook.blank() && genbook.current_status() != Mapfile::generating ) { show_file_error( mapname, "Mapfile alredy exists and is not empty." ); return 1; } if( genbook.read_only() ) return not_writable( genbook.pname( false ) ); const int odes = open( oname, O_RDONLY | O_BINARY ); if( odes < 0 ) { show_file_error( oname, "Can't open output file", errno ); return 1; } if( lseek( odes, 0, SEEK_SET ) ) { show_file_error( oname, onoseek_msg ); return 1; } if( verbosity >= 0 ) std::printf( "%s %s\n", Program_name, PROGVERSION ); if( verbosity >= 1 ) { std::printf( "About to generate an approximate mapfile for '%s' and '%s'\n", iname, oname ); std::printf( " Starting positions: infile = %sB, outfile = %sB\n", format_num( genbook.domain().pos() ), 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 ); } void device_id_and_size( const long long size, const int fd, std::string & id_str ) { struct stat st; if( fstat( fd, &st ) == 0 && S_ISBLK( st.st_mode ) ) { if( device_id( fd, id_str ) ) { id_str.insert( 0, " [" ); id_str += ']'; } else id_str = " [UNKNOWN]"; } id_str += " ("; id_str += format_num3( size ); id_str += ')'; } bool about_to_copy( const Rescuebook & rescuebook, const char * const iname, const char * const oname, const long long insize, const int cluster, const int ides, const int o_direct_out, const int o_trunc, const bool ask ) { if( ask || verbosity >= 0 ) std::printf( "%s %s\n", Program_name, PROGVERSION ); if( ask || verbosity >= 1 ) { std::string iid, oid; char c = ' '; const char * p = " "; // show on one line if( ask || verbosity >= 2 ) { device_id_and_size( insize, ides, iid ); const int odes = open( oname, O_RDONLY ); if( odes >= 0 ) { device_id_and_size( lseek( odes, 0, SEEK_END ), odes, oid ); close( odes ); } if( ask ) { c = '\n'; p = "\n "; } // show on separate lines } std::printf( "About to copy %sBytes%cfrom '%s'%s%sto '%s'%s\n", rescuebook.domain().full() ? "an unknown number of " : format_num( rescuebook.domain().in_size() ), c, iname, iid.c_str(), p, oname, oid.c_str() ); } if( verbosity >= 1 ) { std::printf( " Starting positions: infile = %sB, outfile = %sB\n", format_num( rescuebook.domain().pos() ), format_num( rescuebook.domain().pos() + rescuebook.offset() ) ); std::printf( " Copy block size: %3d sectors", cluster ); if( rescuebook.skipbs > 0 ) std::printf( " Initial skip size: %s sectors\n", format_num3( rescuebook.skipbs / rescuebook.hardbs() ) ); else std::fputs( " Skipping disabled\n", stdout ); std::printf( "Sector size: %sBytes\n", format_num( rescuebook.hardbs(), 99999 ) ); if( verbosity >= 2 ) { bool nl = false; if( rescuebook.max_error_rate >= 0 ) { nl = true; std::printf( "Max error rate: %6sB/s ", format_num( rescuebook.max_error_rate, 99999 ) ); } if( rescuebook.max_bad_areas < ULONG_MAX ) { nl = true; std::printf( "Max %sbad areas: %s ", rescuebook.new_bad_areas_only ? "new " : "", format_num3( rescuebook.max_bad_areas ) ); } if( nl ) { nl = false; std::fputc( '\n', stdout ); } if( rescuebook.max_read_rate > 0 ) { nl = true; std::printf( "Max read rate: %6sB/s ", format_num( rescuebook.max_read_rate, 99999 ) ); } if( rescuebook.min_read_rate == 0 ) { nl = true; std::fputs( "Min read rate: auto ", stdout ); } else if( rescuebook.min_read_rate > 0 ) { nl = true; std::printf( "Min read rate: %6sB/s ", format_num( rescuebook.min_read_rate, 99999 ) ); } if( nl ) { nl = false; std::fputc( '\n', stdout ); } if( rescuebook.timeout >= 0 ) { nl = true; std::printf( "Timeout: %-7s ", format_time( rescuebook.timeout ) ); } if( rescuebook.pause_on_error > 0 ) { nl = true; std::printf( "Pause on error: %ss ", rescuebook.pause_on_error.to_decimal().c_str() ); } if( rescuebook.pause_on_pass > 0 ) { nl = true; std::printf( "Pause on pass: %s", format_time( rescuebook.pause_on_pass ) ); } if( nl ) { nl = false; std::fputc( '\n', stdout ); } std::printf( "Direct in: %s ", rescuebook.o_direct_in ? "yes" : "no " ); std::printf( "Direct out: %s ", o_direct_out ? "yes" : "no " ); std::printf( "Sparse: %s ", rescuebook.sparse ? "yes" : "no " ); std::printf( "Truncate: %s ", o_trunc ? "yes" : "no " ); std::fputc( '\n', stdout ); std::printf( "Trim: %s ", !rescuebook.notrim ? "yes" : "no " ); std::printf( "Sweep: %s ", !rescuebook.nosweep ? "yes" : "no " ); std::printf( "Scrape: %s ", !rescuebook.noscrape ? "yes" : "no " ); if( rescuebook.max_retries >= 0 ) std::printf( "Max retry passes: %s", format_num3( rescuebook.max_retries ) ); std::fputc( '\n', stdout ); if( rescuebook.complete_only ) { nl = true; std::fputs( "Complete only ", stdout ); } if( rescuebook.reverse ) { nl = true; std::fputs( "Reverse mode", stdout ); } if( nl ) { nl = false; std::fputc( '\n', stdout ); } } } if( ask ) { std::fputs( "Proceed (y/N)? ", stdout ); if( !safe_fflush( stdout ) || std::tolower( std::fgetc( stdin ) ) != 'y' ) return false; } if( ask || verbosity >= 1 ) std::fputc( '\n', stdout ); return true; } long long adjusted_insize( const int ides, const Domain * const test_domainp, const char * const oname, const bool use_output_size ) { const int odes = use_output_size ? open( oname, O_RDONLY ) : -1; long long insize = lseek( ( odes >= 0 ) ? odes : ides, 0, SEEK_END ); if( odes >= 0 ) close( odes ); if( insize >= 0 && test_domainp ) { const long long size = test_domainp->end(); if( insize <= 0 || insize > size ) insize = size; } return insize; } int do_rescue( const long long offset, Domain & domain, const Domain * const test_domainp, const Mb_options & mb_opts, Rb_options & rb_opts, const char * const iname, const char * const oname, const char * const mapname, const char * const bad_sector_data_name, const int cluster, const int hardbs, const int o_direct_out, const int o_trunc, const bool ask, const bool command_mode, const bool preallocate, const bool synchronous, const bool check_input_size, const bool use_output_size ) { if( rb_opts.same_file && o_trunc ) { show_error( "Option '--same-file' is incompatible with '--truncate'.", 0, true ); return 1; } // use same flags as reopen_infile const int ides = open( iname, O_RDONLY | rb_opts.o_direct_in | O_BINARY ); if( ides < 0 ) { show_file_error( iname, "Can't open input file", errno ); return 1; } const long long insize = adjusted_insize( ides, test_domainp, oname, use_output_size ); if( insize < 0 ) { show_file_error( iname, inoseek_msg ); return 1; } if( rb_opts.min_outfile_size == 0 ) rb_opts.min_outfile_size = insize; Rescuebook rescuebook( offset, insize, domain, test_domainp, mb_opts, rb_opts, iname, oname, mapname, cluster, hardbs, synchronous ); if( check_input_size ) { if( !rescuebook.mapfile_exists() || insize <= 0 || rescuebook.mapfile_insize() <= 0 || rescuebook.mapfile_insize() >= LLONG_MAX ) { show_error( "Can't check input file size.\n Mapfile is " "unfinished or missing, or size is invalid." ); return 1; } if( rescuebook.mapfile_insize() != insize ) { show_error( "Input file size differs from size calculated from mapfile." ); return 1; } } if( rescuebook.domain().empty() ) { if( rescuebook.complete_only && !rescuebook.mapfile_exists() ) { show_error( "Nothing to complete; mapfile is missing or empty.", 0, true ); return 1; } return empty_domain(); } if( o_trunc && !rescuebook.blank() ) { show_error( "Outfile truncation and mapfile input are incompatible.", 0, true ); return 1; } if( rescuebook.read_only() ) return not_writable( rescuebook.pname( false ) ); if( bad_sector_data_name ) { const int fd = open( bad_sector_data_name, O_RDONLY | O_BINARY ); if( fd < 0 ) { show_file_error( bad_sector_data_name, "Can't open bad-sector-data file for reading", errno ); return 1; } if( !rescuebook.read_bad_sector_data( fd ) ) { show_file_error( bad_sector_data_name, "Error reading bad-sector-data file", errno ); return 1; } if( close( fd ) != 0 ) { show_file_error( bad_sector_data_name, "Error closing bad-sector-data file", errno ); return 1; } } if( !about_to_copy( rescuebook, iname, oname, insize, cluster, ides, o_direct_out, o_trunc, ask ) ) return 1; const int odes = open( oname, ( rescuebook.compare_before_write ? O_RDWR : O_WRONLY ) | O_CREAT | o_direct_out | o_trunc | O_BINARY, outmode ); if( odes < 0 ) { show_file_error( oname, "Can't open output file", errno ); return 1; } if( lseek( odes, 0, SEEK_SET ) ) { show_file_error( oname, onoseek_msg ); return 1; } if( preallocate && lseek( odes, 0, SEEK_END ) - rescuebook.offset() < rescuebook.domain().end() ) { #if defined _POSIX_ADVISORY_INFO && _POSIX_ADVISORY_INFO > 0 while( true ) { int ret = posix_fallocate( odes, rescuebook.domain().pos() + rescuebook.offset(), rescuebook.domain().size() ); if( ret == 0 ) break; else if( ret == EINTR ) continue; show_file_error( oname, "Can't preallocate output file", errno ); return 1; } #else show_file_error( oname, "warning: preallocation not available." ); #endif } if( rescuebook.filename() && !rescuebook.mapfile_exists() && !rescuebook.write_mapfile( 0, true ) ) { show_file_error( mapname, "Can't create mapfile", errno ); return 1; } if( command_mode ) return rescuebook.do_commands( ides, odes ); if( !event_logger.open_file() ) { show_file_error( event_logger.filename(), "Can't open file for logging events", errno ); return 1; } if( !rate_logger.open_file() ) { show_file_error( rate_logger.filename(), "Can't open file for logging rates", errno ); return 1; } if( !read_logger.open_file() ) { show_file_error( read_logger.filename(), "Can't open file for logging reads", errno ); return 1; } return rescuebook.do_rescue( ides, odes ); } void parse_cpass( const char * const arg, const char * const pn, Rb_options & rb_opts ) { const char * p = arg; rb_opts.cpass_bitset = 0; if( *p == '0' ) { if( p[1] == 0 ) return; } else while( true ) { const unsigned char ch1 = *p++; if( ch1 < '1' || ch1 > '4' ) break; if( *p != '-' ) rb_opts.cpass_bitset |= 1 << ( ch1 - '1' ); else { ++p; if( *p < '1' || *p > '4' || ch1 > *p ) break; for( int c = ch1; c <= *p; ++c ) rb_opts.cpass_bitset |= 1 << ( c - '1' ); ++p; } if( *p == 0 ) return; if( *p == ',' ) ++p; else break; } show_option_error( arg, "Invalid pass or range of passes in", pn ); std::exit( 1 ); } void parse_mapfile_intervals( const char * const arg, const char * const pn, Mb_options & mb_opts ) { const char * const ptr2 = std::strchr( arg, ',' ); if( !ptr2 || ptr2 != arg ) { if( arg[0] == '-' && arg[1] == '1' && ( arg[2] == 0 || arg[2] == ',' ) ) mb_opts.mapfile_save_interval = -1; else mb_opts.mapfile_save_interval = parse_time_interval( arg, pn, true ); } if( ptr2 ) mb_opts.mapfile_sync_interval = parse_time_interval( ptr2 + 1, pn ); if( mb_opts.mapfile_sync_interval < 5 ) { show_option_error( arg, "Sync interval must be >= 5 seconds in", pn ); std::exit( 1 ); } if( mb_opts.mapfile_save_interval > mb_opts.mapfile_sync_interval ) { show_option_error( arg, "Save interval must be <= sync interval in", pn ); std::exit( 1 ); } } void parse_errno_vector( const char * const arg, const char * const pn, Rb_options & rb_opts ) { const char * p = arg; while( std::isdigit( *(const unsigned char *)p ) ) { const char * tail; rb_opts.errno_vector.push_back( getnum( p, pn, 0, 1, INT_MAX, &tail ) ); if( *tail == 0 ) return; if( *tail == ',' ) p = tail + 1; else break; } show_option_error( arg, "Invalid errno value in", pn ); std::exit( 1 ); } void parse_pause_on_error( const char * const arg, const char * const pn, Rb_options & rb_opts ) { rb_opts.simulated_poe = *arg == 's'; if( rb_opts.simulated_poe ) rb_opts.pause_on_error = parse_rational_time( arg + 1, pn ); else rb_opts.pause_on_error = parse_time_interval( arg, pn ); } void parse_skipbs( const char * const arg, const char * const pn, Rb_options & rb_opts, const int hardbs ) { const char * tail = arg; if( *tail != ',' ) rb_opts.skipbs = getnum( arg, pn, hardbs, 0, rb_opts.max_max_skipbs, &tail ); if( *tail == ',' ) { rb_opts.max_skipbs = getnum( tail + 1, pn, hardbs, rb_opts.min_skipbs, rb_opts.max_max_skipbs, &tail ); if( *tail ) { show_option_error( arg, "Extra characters in argument of", pn ); std::exit( 1 ); } } else if( *tail ) { show_option_error( arg, "Bad separator in argument of", pn ); std::exit( 1 ); } if( rb_opts.skipbs > 0 && rb_opts.skipbs < rb_opts.min_skipbs ) { show_option_error( arg, "Initial skip size must be 0 or >= 64KiB in", pn ); std::exit( 1 ); } if( rb_opts.skipbs > rb_opts.max_skipbs ) { show_option_error( arg, "Initial skip size must be <= max skip size in", pn ); std::exit( 1 ); } } void check_o_direct() { if( O_DIRECT == 0 ) { show_error( "Direct disc access not available." ); std::exit( 1 ); } } } // end namespace void show_final_msg( const char * const msg, const int errcode ) { if( verbosity < 0 ) return; if( errcode > 0 ) std::fprintf( stderr, "%s: %s: %s (errno=%u)\n", program_name, msg, std::strerror( errcode ), errcode ); else std::fprintf( stderr, "%s: %s\n", program_name, msg ); } bool Rescuebook::reopen_infile() { if( ides_ >= 0 ) close( ides_ ); // use same flags as do_rescue ides_ = open( iname_, O_RDONLY | o_direct_in | O_BINARY ); if( ides_ < 0 ) { final_msg( iname_, "Can't reopen input file", errno ); return false; } const long long insize = lseek( ides_, 0, SEEK_END ); if( insize < 0 ) { final_msg( iname_, "Input file has become not seekable", errno ); return false; } return true; } int main( const int argc, const char * const argv[] ) { long long ipos = 0; long long opos = -1; long long max_size = -1; const char * bad_sector_data_name = 0; const char * domain_mapfile_name = 0; const char * test_mode_mapfile_name = 0; const int cluster_bytes = 65536; const int default_hardbs = 512; const int max_hardbs = 1 << 28; int cluster = 0; int hardbs = default_hardbs; int o_direct_out = 0; // O_DIRECT or 0 int o_trunc = 0; // O_TRUNC or 0 Mode program_mode = m_none; Fb_options fb_opts; Mb_options mb_opts; Rb_options rb_opts; bool ask = false; bool force = false; bool loose = false; bool preallocate = false; bool synchronous = false; bool check_input_size = false; bool use_output_size = false; if( argc > 0 ) invocation_name = argv[0]; command_line = invocation_name; for( int i = 1; i < argc; ++i ) { command_line += ' '; command_line += argv[i]; } enum { opt_ask = 256, opt_bsd, opt_cm, opt_con, opt_cpa, opt_ds, opt_eve, opt_mi, opt_msr, opt_ntr, opt_poe, opt_pop, opt_rat, opt_rea, opt_rs, opt_sf }; const Arg_parser::Option options[] = { { 'a', "min-read-rate", Arg_parser::yes }, { 'A', "try-again", Arg_parser::no }, { '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', "idirect", Arg_parser::no }, { 'D', "odirect", Arg_parser::no }, { 'e', "max-bad-areas", Arg_parser::yes }, { '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 }, { 'H', "test-mode", Arg_parser::yes }, { 'i', "input-position", Arg_parser::yes }, { 'I', "check-input-size", Arg_parser::no }, { 'I', "verify-input-size", Arg_parser::no }, { 'J', "check-on-error", Arg_parser::no }, { 'J', "verify-on-error", Arg_parser::no }, { 'K', "skip-size", Arg_parser::yes }, { 'L', "loose-domain", Arg_parser::no }, { 'm', "domain-mapfile", Arg_parser::yes }, { 'M', "retrim", Arg_parser::no }, { 'n', "no-scrape", Arg_parser::no }, { 'N', "no-sweep", Arg_parser::no }, { 'o', "output-position", Arg_parser::yes }, { 'O', "reopen-on-error", Arg_parser::no }, { 'p', "preallocate", Arg_parser::no }, { 'P', "data-preview", Arg_parser::maybe }, { 'q', "quiet", Arg_parser::no }, { 'r', "retry-passes", Arg_parser::yes }, { 'R', "reverse", Arg_parser::no }, { 's', "size", Arg_parser::yes }, { 'S', "sparse", Arg_parser::no }, { 't', "truncate", Arg_parser::no }, { 'T', "timeout", Arg_parser::yes }, { 'u', "unidirectional", Arg_parser::no }, { 'v', "verbose", Arg_parser::no }, { 'V', "version", Arg_parser::no }, { 'w', "ignore-write-errors", Arg_parser::no }, { 'W', "compare-before-write", Arg_parser::no }, { 'x', "extend-outfile", Arg_parser::yes }, { 'X', "max-read-errors", Arg_parser::yes }, { 'y', "synchronous", Arg_parser::no }, { 'Z', "max-read-rate", Arg_parser::yes }, { opt_ask, "ask", Arg_parser::no }, { opt_bsd, "bad-sector-data", Arg_parser::yes }, { opt_cm, "command-mode", Arg_parser::no }, { opt_con, "continue-on-errno", Arg_parser::yes }, { opt_cpa, "cpass", Arg_parser::yes }, { opt_ds, "delay-slow", Arg_parser::yes }, { opt_eve, "log-events", Arg_parser::yes }, { opt_mi, "mapfile-interval", Arg_parser::yes }, { opt_msr, "max-slow-reads", Arg_parser::yes }, { opt_ntr, "no-trim", Arg_parser::no }, { opt_poe, "pause-on-error", Arg_parser::yes }, { opt_pop, "pause-on-pass", Arg_parser::yes }, { opt_rat, "log-rates", Arg_parser::yes }, { opt_rea, "log-reads", Arg_parser::yes }, { opt_rs, "reset-slow", Arg_parser::no }, { opt_sf, "same-file", Arg_parser::no }, { 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 pn = parser.parsed_name( argind ).c_str(); const std::string & sarg = parser.argument( argind ); const char * const arg = sarg.c_str(); switch( code ) { case 'a': rb_opts.min_read_rate = getnum( arg, pn, hardbs, 0 ); break; case 'A': rb_opts.try_again = true; break; case 'b': hardbs = getnum( arg, pn, 0, 1, max_hardbs ); break; case 'B': format_num( 0, 0, -1 ); break; // set binary prefixes case 'c': cluster = getnum( arg, pn, 0, 1, INT_MAX ); break; case 'C': rb_opts.complete_only = true; break; case 'd': rb_opts.o_direct_in = O_DIRECT; check_o_direct(); break; case 'D': o_direct_out = O_DIRECT; check_o_direct(); break; case 'e': rb_opts.new_bad_areas_only = *arg == '+'; rb_opts.max_bad_areas = getnum( arg, pn, 0, 0, LONG_MAX ); break; case 'E': rb_opts.max_error_rate = getnum( arg, pn, hardbs, 0 ); break; case 'f': force = true; break; case 'F': set_mode( program_mode, m_fill ); fb_opts.filltypes = sarg; fb_opts.write_location_data = check_types( arg, fb_opts.filltypes, pn, true ); break; case 'G': set_mode( program_mode, m_generate ); break; case 'h': show_help( cluster_bytes / default_hardbs, default_hardbs ); return 0; case 'H': set_name( &test_mode_mapfile_name, arg, pn ); break; case 'i': ipos = getnum( arg, pn, hardbs, 0 ); break; case 'I': check_input_size = true; break; case 'J': rb_opts.check_on_error = true; break; case 'K': parse_skipbs( arg, pn, rb_opts, hardbs ); break; case 'L': loose = true; break; case 'm': set_name( &domain_mapfile_name, arg, pn ); break; case 'M': rb_opts.retrim = true; break; case 'n': rb_opts.noscrape = true; break; case 'N': rb_opts.nosweep = true; break; case 'o': opos = getnum( arg, pn, hardbs, 0 ); break; case 'O': rb_opts.reopen_on_error = true; break; case 'p': preallocate = true; break; case 'P': rb_opts.preview_lines = *arg ? getnum( arg, pn, 0, 1, 32 ) : 3; break; case 'q': verbosity = -1; break; case 'r': rb_opts.max_retries = getnum( arg, pn, 0, -1, 1000000 ); break; case 'R': rb_opts.reverse = true; break; case 's': if( sarg == "output" ) use_output_size = true; else { max_size = getnum( arg, pn, 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, pn ); break; case 'u': rb_opts.unidirectional = true; break; case 'v': if( verbosity < 4 ) ++verbosity; break; case 'V': show_version(); return 0; case 'w': fb_opts.ignore_write_errors = true; break; case 'W': rb_opts.compare_before_write = true; break; case 'x': rb_opts.min_outfile_size = getnum( arg, pn, hardbs, 0 ); break; case 'X': rb_opts.max_read_errors = getnum( arg, pn, 0, 0, LONG_MAX ); break; case 'y': synchronous = true; break; case 'Z': rb_opts.max_read_rate = getnum( arg, pn, hardbs, 1 ); break; case opt_ask: ask = true; break; case opt_bsd: set_name( &bad_sector_data_name, arg, pn ); break; case opt_cm: set_mode( program_mode, m_command ); break; case opt_con: parse_errno_vector( arg, pn, rb_opts ); break; case opt_cpa: parse_cpass( arg, pn, rb_opts ); break; case opt_ds: rb_opts.delay_slow = parse_time_interval( arg, pn ); break; case opt_eve: event_logger.set_filename( arg ); break; case opt_mi: parse_mapfile_intervals( arg, pn, mb_opts ); break; case opt_msr: rb_opts.max_slow_reads = getnum( arg, pn, 0, 0, LONG_MAX ); break; case opt_ntr: rb_opts.notrim = true; break; case opt_poe: parse_pause_on_error( arg, pn, rb_opts ); break; case opt_pop: rb_opts.pause_on_pass = parse_time_interval( arg, pn ); break; case opt_rat: rate_logger.set_filename( arg ); break; case opt_rea: read_logger.set_filename( arg ); break; case opt_rs: rb_opts.reset_slow = true; break; case opt_sf: rb_opts.same_file = true; 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; const char *iname = 0, *oname = 0, *mapname = 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() ) mapname = 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, mapname, rb_opts, force, program_mode == m_generate, preallocate ) ) return 1; Domain domain( ipos, max_size, domain_mapfile_name, loose ); switch( program_mode ) { case m_fill: if( ask ) { show_error( "Option '--ask' is incompatible with fill mode.", 0, true ); return 1; } if( rb_opts.same_file ) { show_error( "Option '--same-file' is incompatible with fill mode.", 0, true ); return 1; } if( rb_opts != Rb_options() || test_mode_mapfile_name || check_input_size || preallocate || o_trunc ) show_error( "warning: options -aACdeEHIJKlMnOpPrRStTuWxX are ignored in fill mode." ); return do_fill( opos - ipos, domain, fb_opts, mb_opts, iname, oname, mapname, cluster, hardbs, o_direct_out, synchronous ); case m_generate: if( ask ) { show_error( "Option '--ask' is incompatible with generate mode.", 0, true ); return 1; } if( fb_opts != Fb_options() || rb_opts != Rb_options() || synchronous || test_mode_mapfile_name || check_input_size || preallocate || o_direct_out || o_trunc ) show_error( "warning: options -aACdDeEHIJKlMnOpPrRStTuwWxXy are ignored in generate mode." ); return do_generate( opos - ipos, domain, mb_opts, iname, oname, mapname, cluster, hardbs ); case m_command: case m_none: { if( fb_opts != Fb_options() ) { show_error( "Option '-w' is incompatible with rescue mode.", 0, true ); return 1; } const Domain test_domain( 0, -1, test_mode_mapfile_name, loose ); const Domain * test_domainp = test_mode_mapfile_name ? &test_domain : 0; return do_rescue( opos - ipos, domain, test_domainp, mb_opts, rb_opts, iname, oname, mapname, bad_sector_data_name, cluster, hardbs, o_direct_out, o_trunc, ask, program_mode == m_command, preallocate, synchronous, check_input_size, use_output_size ); } } } gddrescue-1.30/main_common.cc000066400000000000000000000351411512716454500162230ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 . */ int verbosity = 0; namespace { const char * const program_year = "2026"; std::string command_line; const char * const inval_t_msg = "Invalid type in argument of"; void show_version() { std::printf( "GNU %s %s\n", program_name, PROGVERSION ); std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year ); std::fputs( "License GPLv2+: GNU GPL version 2 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", stdout ); } bool check_types( const char * const arg, std::string & types, const char * const option_name, const bool allow_l ) { bool write_location_data = false; for( int i = types.size(); i > 0; ) { if( types[--i] == 'l' && allow_l ) { write_location_data = true; types.erase( i, 1 ); continue; } if( !Sblock::isstatus( types[i] ) ) { show_option_error( arg, inval_t_msg, option_name ); std::exit( 1 ); } } if( types.empty() ) // types must not be empty { show_option_error( arg, "Missing type in argument of", option_name ); std::exit( 1 ); } return write_location_data; } 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 ** name, const char * new_name, const char * const option_name ) { if( !*name ) { *name = new_name; return; } if( verbosity >= 0 ) std::fprintf( stderr, "%s: Option '%s' can be specified only once.\n", program_name, option_name ); std::exit( 1 ); } const char * format_timestamp( const long long t = 0 ) { static char buf[64]; const time_t tt = t ? t : std::time( 0 ); const struct tm * const tm = std::localtime( &tt ); if( !tm || std::strftime( buf, sizeof buf, "%Y-%m-%d %H:%M:%S", tm ) == 0 ) buf[0] = 0; return buf; } } // end namespace void show_option_error( const char * const arg, const char * const msg, const char * const option_name ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s: '%s': %s option '%s'.\n", program_name, arg, msg, option_name ); } void show_error( const char * const msg, const int errcode, const bool help ) { if( verbosity < 0 ) return; if( msg && *msg ) std::fprintf( stderr, "%s: %s%s%s\n", program_name, msg, ( errcode > 0 ) ? ": " : "", ( errcode > 0 ) ? std::strerror( errcode ) : "" ); if( help ) std::fprintf( stderr, "Try '%s --help' for more information.\n", invocation_name ); } void show_file_error( const char * const filename, const char * const msg, const int errcode ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s: %s: %s%s%s\n", program_name, filename, msg, ( errcode > 0 ) ? ": " : "", ( errcode > 0 ) ? std::strerror( errcode ) : "" ); } void internal_error( const char * const msg ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s: internal error: %s\n", program_name, msg ); std::exit( 3 ); } int empty_domain() { show_error( "Nothing to do; domain is empty." ); return 0; } int not_readable( const char * const mapname ) { show_file_error( mapname, "Mapfile does not exist or is not readable." ); return 1; } int not_writable( const char * const mapname ) { show_file_error( mapname, "Mapfile is not writable." ); return 1; } long long initial_time() { static long long initial_time_ = 0; if( initial_time_ == 0 ) initial_time_ = std::time( 0 ); return initial_time_; } bool write_file_header( FILE * const f, const char * const filetype ) { static std::string timestamp; // same inital timestamp on all files if( timestamp.empty() ) timestamp = format_timestamp( initial_time() ); return ( std::fprintf( f, "# %s. Created by %s version %s\n" "# Command line: %s\n" "# Start time: %s\n", filetype, Program_name, PROGVERSION, command_line.c_str(), timestamp.c_str() ) >= 0 ); } bool write_timestamp( FILE * const f ) { const char * const timestamp = format_timestamp(); return ( !timestamp || !*timestamp || std::fprintf( f, "# Current time: %s\n", timestamp ) >= 0 ); } bool write_final_timestamp( FILE * const f ) { static std::string timestamp; // same final timestamp on all files if( timestamp.empty() ) timestamp = format_timestamp(); return ( std::fprintf( f, "# End time: %s\n", timestamp.c_str() ) >= 0 ); } int chvalue( const unsigned char ch ) { if( ch >= '0' && ch <= '9' ) return ch - '0'; if( ch >= 'A' && ch <= 'Z' ) return ch - 'A' + 10; if( ch >= 'a' && ch <= 'z' ) return ch - 'a' + 10; return 255; } long long strtoll_( const char * const ptr, const char ** tail, int base ) { if( tail ) *tail = ptr; // error value int i = 0; while( std::isspace( ptr[i] ) || (unsigned char)ptr[i] == 0xA0 ) ++i; const bool minus = ptr[i] == '-'; if( minus || ptr[i] == '+' ) ++i; if( base < 0 || base > 36 || base == 1 || ( base == 0 && !std::isdigit( ptr[i] ) ) || ( base != 0 && chvalue( ptr[i] ) >= base ) ) { errno = EINVAL; return 0; } if( base == 0 ) { if( ptr[i] != '0' ) base = 10; // decimal else if( ptr[i+1] == 'x' || ptr[i+1] == 'X' ) { base = 16; i += 2; } else base = 8; // octal or 0 } const int dpg = ( base != 16 ) ? 3 : 2; // min digits per group int dig = dpg - 1; // digits in current group, first may have 1 digit const unsigned long long limit = minus ? LLONG_MAX + 1ULL : LLONG_MAX; unsigned long long result = 0; bool erange = false; for( ; ptr[i]; ++i ) { if( ptr[i] == '_' ) { if( dig < dpg ) break; else { dig = 0; continue; } } const int val = chvalue( ptr[i] ); if( val >= base ) break; else ++dig; if( !erange && ( limit - val ) / base >= result ) result = result * base + val; else erange = true; } if( dig < dpg ) { errno = EINVAL; return 0; } if( tail ) *tail = ptr + i; if( erange ) { errno = ERANGE; return minus ? LLONG_MIN : LLONG_MAX; } return minus ? 0LL - result : result; } const char * format_num( long long num, int limit, const int set_prefix ) { enum { buffers = 8, bufsize = 16 }; const char * const si_prefix[] = { "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", 0 }; const char * const binary_prefix[] = { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi", "Ri", "Qi", 0 }; static char buffer[buffers][bufsize]; // circle of buffers for printf static int current = 0; static bool si = true; if( set_prefix ) si = set_prefix > 0; const int factor = si ? 1000 : 1024; char * const buf = buffer[current++]; current %= buffers; const char * const * prefix = si ? si_prefix : binary_prefix; const char * p = ""; limit = std::max( 999, std::min( 999999, limit ) ); for( int i = 0; llabs( num ) > limit && prefix[i]; ++i ) { num /= factor; p = prefix[i]; } snprintf( buf, bufsize, "%d %s", (int)num, p ); // 6 digits or less return buf; } // separate numbers of 5 or more digits in groups of 3 digits using '_' const char * format_num3p( long long num, const bool space ) { enum { buffers = 8, bufsize = 4 * sizeof num }; const char * const si_prefix = "kMGTPEZYRQ"; const char * const binary_prefix = "KMGTPEZYRQ"; static char buffer[buffers][bufsize]; // circle of buffers for printf static int current = 0; char * const buf = buffer[current++]; current %= buffers; char * p = buf + bufsize - 1; // fill the buffer backwards *p = 0; // terminator const bool negative = num < 0; if( num >= 10000 || num <= -10000 ) { char prefix = 0; // try binary first, then si for( int i = 0; num != 0 && num % 1024 == 0 && binary_prefix[i]; ++i ) { num /= 1024; prefix = binary_prefix[i]; } if( prefix ) *(--p) = 'i'; else for( int i = 0; num != 0 && num % 1000 == 0 && si_prefix[i]; ++i ) { num /= 1000; prefix = si_prefix[i]; } if( prefix ) *(--p) = prefix; } const bool split = num >= 10000 || num <= -10000; if( space ) *(--p) = ' '; for( int i = 0; ; ) { const long long onum = num; num /= 10; *(--p) = llabs( onum - ( 10 * num ) ) + '0'; if( num == 0 ) break; if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; } } if( negative ) *(--p) = '-'; return p; } // separate numbers of 5 or more digits in groups of 3 digits using '_' const char * format_num3( unsigned long long num, const bool negative ) { enum { buffers = 8, bufsize = 4 * sizeof num }; static char buffer[buffers][bufsize]; // circle of buffers for printf static int current = 0; char * const buf = buffer[current++]; current %= buffers; char * p = buf + bufsize - 1; // fill the buffer backwards *p = 0; // terminator const bool split = num >= 10000; for( int i = 0; ; ) { *(--p) = num % 10 + '0'; num /= 10; if( num == 0 ) break; if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; } } if( negative ) *(--p) = '-'; return p; } // Recognized formats: k[Bs], Ki[Bs], [MGTPEZYRQ][i][Bs] long long getnum( const char * const arg, const char * const option_name, const int hardbs, const long long llimit, const long long ulimit, const char ** const tailp ) { const char * tail; errno = 0; long long result = strtoll_( arg, &tail, 0 ); if( tail == arg ) { show_option_error( arg, "Bad or missing numerical argument in", option_name ); std::exit( 1 ); } if( !errno && *tail ) { const char * const p = tail++; int factor = 1000; // default factor int exponent = -1; // -1 = bad multiplier char usuf = 0; // 'B' or 's' unit suffix is present switch( *p ) { case 'Q': exponent = 10; break; case 'R': exponent = 9; 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( *tail == 'i' ) { ++tail; factor = 1024; exponent = 1; } break; case 'k': if( *tail != 'i' ) exponent = 1; break; case 'B': case 's': usuf = *p; exponent = 0; break; default: if( tailp ) { tail = p; exponent = 0; } } if( exponent > 1 && *tail == 'i' ) { ++tail; factor = 1024; } if( exponent > 0 && usuf == 0 && ( *tail == 'B' || *tail == 's' ) ) { usuf = *tail; ++tail; } if( exponent < 0 || ( usuf == 's' && hardbs <= 0 ) || ( !tailp && *tail != 0 ) ) { show_option_error( arg, "Bad multiplier in numerical argument of", option_name ); std::exit( 1 ); } for( int i = 0; i < exponent; ++i ) { if( ( result >= 0 && LLONG_MAX / factor >= result ) || ( result < 0 && LLONG_MIN / factor <= result ) ) result *= factor; else { errno = ERANGE; break; } } if( usuf == 's' ) { if( ( result >= 0 && LLONG_MAX / hardbs >= result ) || ( result < 0 && LLONG_MIN / hardbs <= result ) ) result *= hardbs; else errno = ERANGE; } } if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE; if( errno ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s: '%s': Value out of limits [%s,%s] in " "option '%s'.\n", program_name, arg, format_num3p( llimit ), format_num3p( ulimit ), option_name ); std::exit( 1 ); } if( tailp ) *tailp = tail; return result; } /* Return a string representing the fraction 'num/den' as a percentage with 'prec' decimals. 'iwidth' is the minimum width of the integer part, prefixed with spaces if needed. If 'prec' is negative, produce only the decimals needed. If 'rounding', round up the last digit if the next one would be >= 5. */ const char * format_percentage( long long num, long long den, const int iwidth, int prec, const bool rounding ) { enum { bufsize = 80 }; static char buf[bufsize]; 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 ) // negative but > -1.0 i = snprintf( buf, bufsize, "%*s", iwidth, "-0" ); else i = snprintf( buf, bufsize, "%*lld", iwidth, num / den ); if( i < bufsize - 2 ) { long long rest = llabs( num ) % den; if( prec > 0 && ( rest > 0 || !trunc ) ) { buf[i++] = '.'; while( prec > 0 && ( rest > 0 || !trunc ) && i < bufsize - 2 ) { rest *= 10; buf[i++] = rest / den + '0'; rest %= den; --prec; } } if( rounding && rest * 2 >= den ) // round last decimal up for( int j = i - 1; j >= 0; --j ) { if( buf[j] == '.' ) continue; if( buf[j] >= '0' && buf[j] < '9' ) { ++buf[j]; break; } if( buf[j] == '9' ) buf[j] = '0'; if( j > 0 && buf[j-1] == '.' ) continue; if( j > 0 && buf[j-1] == ' ' ) { buf[j-1] = '1'; break; } if( j > 1 && buf[j-2] == ' ' && buf[j-1] == '-' ) { buf[j-2] = '-'; buf[j-1] = '1'; break; } if( j == 0 || buf[j-1] < '0' || buf[j-1] > '9' ) // no prev digit { for( int k = i - 1; k > j; --k ) buf[k] = buf[k-1]; buf[j] = '1'; break; // prepend '1' to the first digit } } } else i = bufsize - 2; buf[i++] = '%'; buf[i] = 0; return buf; } gddrescue-1.30/make_test.cc000066400000000000000000000111721512716454500157010ustar00rootroot00000000000000/* GNU ddrescuelog - Tool for ddrescue mapfiles Copyright (C) 2011-2026 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 2 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 . */ /* This option is a work in progress. The geometries implemented so far are some of those described in the following article: H. Wong, "Discovering Hard Disk Physical Geometry through Microbenchmarking", Sept., 2019. Available online at */ #include #include #include #include #include "mapfile.h" #include "ddrescuelog.h" namespace { struct CHS { enum Track_order{ F, FF }; int cylinders; int heads; int first_track_sectors; int last_track_sectors; int tracks_zone; Track_order track_order; int bad_head; }; CHS * chsp = 0; } // end namespace // cylinders:heads:sectors1[-sectors2[,tracks_zone]]:track_order:bad_head void parse_chs( const char * const arg, const char * const pn ) { const char * tail; if( chsp == 0 ) chsp = new CHS; CHS & chs = *chsp; chs.cylinders = getnum( arg, pn, 0, 40, 1000000, &tail ); if( *tail != ':' ) err: { show_option_error( arg, "Invalid 'C:H:S:order:head' description in", pn ); std::exit( 1 ); } chs.heads = getnum( tail + 1, pn, 0, 1, 256, &tail ); if( *tail != ':' ) goto err; chs.first_track_sectors = getnum( tail + 1, pn, 0, 8, 10000, &tail ); if( *tail == '-' ) { chs.last_track_sectors = getnum( tail + 1, pn, 0, 8, 10000, &tail ); if( chs.last_track_sectors == chs.first_track_sectors ) goto err; if( *tail == ',' ) chs.tracks_zone = getnum( tail + 1, pn, 0, 8, chs.cylinders, &tail ); else chs.tracks_zone = chs.cylinders / std::min( 24, std::abs( chs.last_track_sectors - chs.first_track_sectors ) ); } else { chs.last_track_sectors = chs.first_track_sectors; chs.tracks_zone = chs.cylinders; } if( *tail++ != ':' ) goto err; if( *tail == 'F' ) { if( tail[1] == 'F' ) { chs.track_order = chs.FF; tail += 2; } else { chs.track_order = chs.F; ++tail; } } else goto err; if( *tail != ':' ) goto err; chs.bad_head = getnum( tail + 1, pn, 0, 0, chs.heads - 1, &tail ); if( *tail != 0 ) goto err; if( ( chs.track_order == chs.F ) != ( chs.last_track_sectors == chs.first_track_sectors ) ) goto err; } int make_test( const char * const mapname, const int hardbs, const bool force ) { Mapfile mapfile( mapname ); const bool to_stdout = std::strcmp( mapname, "-" ) == 0; if( !to_stdout && !force && mapfile.read_mapfile( 0, false ) ) { show_file_error( mapname, "Mapfile exists. Use '--force' to overwrite it." ); return 1; } mapfile.current_status( mapfile.finished ); const CHS & chs = *chsp; const int zones = chs.cylinders / chs.tracks_zone + ( chs.cylinders % chs.tracks_zone != 0 ); switch( chs.track_order ) { case CHS::F: for( int c = 0; c < chs.cylinders; ++c ) for( int h = 0; h < chs.heads; ++h ) for( int s = 0; s < chs.first_track_sectors; ++s ) mapfile.append_sblock( hardbs, ( chs.bad_head == h ) ? Sblock::bad_sector : Sblock::finished ); break; case CHS::FF: for( int z = 0; z * chs.tracks_zone < chs.cylinders; ++z ) { const int climit = std::min( chs.cylinders, (z+1) * chs.tracks_zone ); const int sectors = ( chs.first_track_sectors * ( zones - 1 - z ) + chs.last_track_sectors * z ) / ( zones - 1 ); for( int h = 0; h < chs.heads; ++h ) for( int c = z * chs.tracks_zone; c < climit; ++c ) for( int s = 0; s < sectors; ++s ) mapfile.append_sblock( hardbs, ( chs.bad_head == h ) ? Sblock::bad_sector : Sblock::finished ); } } mapfile.compact_sblock_vector(); if( !mapfile.write_mapfile( to_stdout ? stdout : 0 ) || ( to_stdout && std::fclose( stdout ) != 0 ) ) { show_file_error( mapfile.pname( false ), "Error writing mapfile", errno ); return 1; } return 0; } gddrescue-1.30/mapbook.cc000066400000000000000000000141631512716454500153600ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" #include "mapbook.h" namespace { void input_pos_error( const long long pos, const long long insize ) { char buf[160]; const char * const p = format_num3( pos ); const int len = std::strlen( p ); snprintf( buf, sizeof buf, "Can't start reading at pos %s.\n" " Size of input file is only %*s bytes.", p, len, format_num3( insize ) ); show_error( buf ); } } // end namespace bool safe_fflush( FILE * const f ) { while( true ) { const int ret = std::fflush( f ); if( ret == 0 ) return true; if( ret == EOF && errno == EINTR ) continue; return false; } } bool Mapbook::save_mapfile( const char * const name ) { std::remove( name ); FILE * const f = std::fopen( name, "w" ); if( f && write_mapfile( f, true, true ) && std::fclose( f ) == 0 ) { char buf[80]; snprintf( buf, sizeof buf, "Mapfile saved in '%s'", name ); final_msg( buf ); return true; } return false; } bool Mapbook::emergency_save() { static bool first_time = true; static std::string home_name; const std::string dead_name( "ddrescue.map" ); if( filename() != dead_name && save_mapfile( dead_name.c_str() ) ) return true; if( first_time ) { first_time = false; const char * const p = std::getenv( "HOME" ); if( p ) { home_name = p; home_name += '/'; home_name += dead_name; } } if( home_name.size() && filename() != home_name && save_mapfile( home_name.c_str() ) ) return true; show_file_error( dead_name.c_str(), "Emergency save failed." ); return false; } Mapbook::Mapbook( const long long offset, const long long insize, Domain & dom, const Mb_options & mb_opts, const char * const mapname, const int cluster, const int hardbs, const bool complete_only, const bool rescue ) : Mapfile( mapname ), Mb_options( mb_opts ), offset_( offset ), mapfile_insize_( 0 ), domain_( dom ), hardbs_( hardbs ), softbs_( cluster * hardbs_ ), iobuf_size_( softbs_ + hardbs_ ), // +hardbs for direct unaligned reads final_errno_( 0 ), um_t1( 0 ), um_t1s( 0 ), um_prev_mf_sync( false ), mapfile_exists_( false ) { long alignment = sysconf( _SC_PAGESIZE ); if( alignment < hardbs_ || alignment % hardbs_ ) alignment = hardbs_; if( alignment < 2 ) alignment = 0; iobuf_ = iobuf_base = new uint8_t[ alignment + ( 2 * iobuf_size_ ) ]; if( alignment > 1 ) // align iobuf for direct disc access { const int disp = alignment - ( reinterpret_cast (iobuf_) % alignment ); if( disp > 0 && disp < alignment ) iobuf_ += disp; } if( insize > 0 ) { if( domain_.pos() >= insize ) { input_pos_error( domain_.pos(), insize ); std::exit( 1 ); } domain_.crop_by_file_size( insize ); } if( filename() ) { mapfile_exists_ = read_mapfile( 0, false ); if( mapfile_exists_ ) mapfile_insize_ = extent().end(); } if( !complete_only ) extend_sblock_vector( insize ); else domain_.crop( extent() ); // limit domain to blocks read from mapfile compact_sblock_vector(); if( rescue ) join_subsectors( hardbs_ ); split_by_domain_borders( domain_ ); if( sblocks() == 0 ) domain_.clear(); } /* Write periodically the mapfile to disc. Return false only if update is attempted and fails. */ bool Mapbook::update_mapfile( const int odes, const bool force ) { if( !filename() ) return true; const int interval = ( mapfile_save_interval >= 0 ) ? mapfile_save_interval : 30 + std::min( 270L, sblocks() / 38 ); // auto, 30s to 5m const long long t2 = std::time( 0 ); if( um_t1 == 0 || um_t1 > t2 ) um_t1 = um_t1s = t2; // initialize if( !force && t2 - um_t1 < interval ) return true; const bool mf_sync = force || t2 - um_t1s >= mapfile_sync_interval; if( odes >= 0 ) fsync( odes ); if( um_prev_mf_sync ) { std::string mapname_bak( filename() ); mapname_bak += ".bak"; std::remove( mapname_bak.c_str() ); // break possible hard link std::rename( filename(), mapname_bak.c_str() ); } um_prev_mf_sync = mf_sync; for( bool first_post = true; ; first_post = false ) { errno = 0; if( write_mapfile( 0, true, mf_sync ) ) // update times here to exclude writing time from intervals { um_t1 = std::time( 0 ); if( mf_sync ) um_t1s = um_t1; return true; } if( verbosity < 0 ) return false; const int saved_errno = errno; if( first_post ) std::fputc( '\n', stderr ); show_file_error( filename(), "Error writing mapfile", saved_errno ); std::fputs( "Fix the problem and press ENTER to retry,\n" " or E+ENTER for an emergency save and exit,\n" " or Q+ENTER to abort.\n", stderr ); safe_fflush( stderr ); while( true ) { tcflush( STDIN_FILENO, TCIFLUSH ); const int c = std::tolower( std::fgetc( stdin ) ); int tmp = c; while( tmp != '\n' && tmp != EOF ) tmp = std::fgetc( stdin ); if( c == '\r' || c == '\n' || c == 'e' || c == 'q' ) { if( c == 'q' || ( c == 'e' && emergency_save() ) ) { if( !force ) std::fputs( "\n\n\n\n\n", stdout ); return false; } break; } } } } gddrescue-1.30/mapbook.h000066400000000000000000000153731512716454500152260ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 . */ struct Mb_options { int mapfile_save_interval; // default -1 = auto int mapfile_sync_interval; // default 300s (5m) Mb_options() : mapfile_save_interval( -1 ), mapfile_sync_interval( 300 ) {} }; class Mapbook : public Mapfile, public Mb_options { const long long offset_; // outfile offset (opos - ipos); long long mapfile_insize_; Domain & domain_; // rescue domain uint8_t *iobuf_base; // alignment + iobuf + iobuf2 uint8_t *iobuf_; // buffer aligned to page and hardbs const int hardbs_, softbs_; const int iobuf_size_; std::string final_msg_; int final_errno_; long long um_t1, um_t1s; // variables for update_mapfile bool um_prev_mf_sync; bool mapfile_exists_; bool save_mapfile( const char * const name ); Mapbook( const Mapbook & ); // declared as private void operator=( const Mapbook & ); // declared as private protected: bool emergency_save(); public: Mapbook( const long long offset, const long long insize, Domain & dom, const Mb_options & mb_opts, const char * const mapname, const int cluster, const int hardbs, const bool complete_only, const bool rescue ); ~Mapbook() { delete[] iobuf_base; } bool update_mapfile( const int odes = -1, const bool force = false ); const Domain & domain() const { return domain_; } uint8_t * iobuf() const { return iobuf_; } // main I/O buffer // second buffer for compare_before_write and check_on_error uint8_t * iobuf2() const { return iobuf_ + iobuf_size_; } int iobuf_size() const { return iobuf_size_; } int hardbs() const { return hardbs_; } int softbs() const { return softbs_; } long long offset() const { return offset_; } const std::string & final_msg() const { return final_msg_; } int final_errno() const { return final_errno_; } bool mapfile_exists() const { return mapfile_exists_; } long long mapfile_insize() const { return mapfile_insize_; } void final_msg( const char * const filename, const char * const msg, const int e = 0 ) { final_msg_ = filename; final_msg_ += ": "; final_msg_ += msg; final_errno_ = e; } void final_msg( const char * const msg, const int e = 0 ) { final_msg_ = msg; final_errno_ = e; } void truncate_domain( const long long end ) { domain_.crop_by_file_size( end ); } }; struct Fb_options { std::string filltypes; bool ignore_write_errors; bool write_location_data; Fb_options() : ignore_write_errors( false ), write_location_data( false ) {} bool operator==( const Fb_options & o ) const { return ( filltypes == o.filltypes && ignore_write_errors == o.ignore_write_errors && write_location_data == o.write_location_data ); } bool operator!=( const Fb_options & o ) const { return !( *this == o ); } }; class Fillbook : public Mapbook, public Fb_options { long long filled_size; // size already filled long long remaining_size; // size to be filled const char * const oname_; unsigned long filled_areas; // areas already filled unsigned long remaining_areas; // areas to be filled int odes_; // output file descriptor const bool synchronous_; // variables for show_status long long a_rate, c_rate, first_size, last_size; long long last_ipos; long long t0, t1; // start, current times int oldlen; int fill_block( const Sblock & sb ); int fill_areas(); void show_status( const long long ipos, const char * const msg = 0, bool force = false ); public: Fillbook( const long long offset, Domain & dom, const Fb_options & fb_opts, const Mb_options & mb_opts, const char * const oname, const char * const mapname, const int cluster, const int hardbs, const bool synchronous ) : Mapbook( offset, 0, dom, mb_opts, mapname, cluster, hardbs, true, false ), Fb_options( fb_opts ), oname_( oname ), synchronous_( synchronous ), a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ), last_ipos( 0 ), t0( 0 ), t1( 0 ), oldlen( 0 ) {} int do_fill( const int odes ); bool read_buffer( const int ides ); }; class Genbook : public Mapbook { long long finished_size, gensize; // total recovered and generated sizes const char * const iname_; int odes_; // output file descriptor // variables for show_status long long a_rate, c_rate, first_size, last_size; long long last_ipos; long long t0, t1; // start, current times 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 insize, Domain & dom, const Mb_options & mb_opts, const char * const iname, const char * const mapname, const int cluster, const int hardbs ) : Mapbook( offset, insize, dom, mb_opts, mapname, cluster, hardbs, false, false ), iname_( iname ), 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 ); }; inline 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; } const char * const ctrlc_msg = "Press Ctrl-C to interrupt\n"; const char * const early_eof_msg = "EOF found below the size calculated from mapfile."; const char * const initial_msg = "Initial status (read from mapfile)\n"; const char * const wr_err_msg = "Write error"; bool safe_fflush( FILE * const f ); // Defined in genbook.cc const char * format_time( const long long t, const bool low_prec = false ); // Defined in io.cc int readblock( const int fd, uint8_t * const buf, const int size ); int readblockp( const int fd, uint8_t * const buf, const int size, const long long pos ); int writeblockp( const int fd, const uint8_t * const buf, const int size, const long long pos ); bool interrupted(); void set_signals(); int signaled_exit(); gddrescue-1.30/mapfile.cc000066400000000000000000000563441512716454500153540ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" namespace { int my_fgetc( FILE * const f, const bool allow_comment = true ) { int ch = std::fgetc( f ); if( ch == '#' && allow_comment ) // comment { do ch = std::fgetc( f ); while( ch != '\n' && ch != EOF ); } return ch; } /* Read a line discarding comments, leading whitespace, and blank lines. Return 0 if at EOF. */ const char * my_fgets( FILE * const f, unsigned & 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, std::isspace( ch ) ); } } if( len > 0 ) { buf[len] = 0; return buf; } else return 0; } void show_mapfile_error( const char * const pname, const char * const msg, const unsigned linenum ) { char buf[80]; snprintf( buf, sizeof buf, "Error in mapfile, line %u: %s", linenum, msg ); show_file_error( pname, buf ); } /* Insert sb in its place or merge it with overlapping blocks of same status. Return false if sb overlaps with blocks of different status. */ bool insert_sblock_sorted( std::vector< Sblock > & sblock_vector, const Sblock & sb ) { if( sblock_vector.empty() || sb.pos() >= sblock_vector.back().end() ) { sblock_vector.push_back( sb ); return true; } // append at the end const long long pos = sb.pos(); const long long end = sb.end(); for( unsigned long i = 0; i < sblock_vector.size(); ++i ) if( end <= sblock_vector[i].pos() ) // maybe insert sb before i { if( i == 0 || pos >= sblock_vector[i-1].end() ) { sblock_vector.insert( sblock_vector.begin() + i, sb ); return true; } break; } for( unsigned long i = 0; i < sblock_vector.size(); ++i ) if( sblock_vector[i].overlaps( sb ) ) { unsigned long j = i; // indexes of first/last overlapping blocks while( j + 1 < sblock_vector.size() && sblock_vector[j+1].overlaps( sb ) ) ++j; for( unsigned long k = i; k <= j; ++k ) if( sblock_vector[k].status() != sb.status() ) goto fail; const long long new_pos = std::min( pos, sblock_vector[i].pos() ); const long long new_end = std::max( end, sblock_vector[j].end() ); sblock_vector[i].assign( new_pos, new_end - new_pos ); if( i < j ) sblock_vector.erase( sblock_vector.begin() + i + 1, sblock_vector.begin() + j + 1 ); return true; // sb successfully merged with overlapping blocks } fail: return false; } void fill_gaps_in_sblock_vector( std::vector< Sblock > & sblock_vector, const Sblock::Status st ) { if( sblock_vector.empty() ) return; std::vector< Sblock > new_vector; bool gap = sblock_vector[0].pos() > 0; if( gap ) new_vector.push_back( Sblock( 0, sblock_vector[0].pos(), st ) ); else for( unsigned long i = 1; i < sblock_vector.size(); ++i ) if( sblock_vector[i-1].end() != sblock_vector[i].pos() ) { gap = true; break; } if( gap ) { new_vector.push_back( sblock_vector[0] ); for( unsigned long i = 1; i < sblock_vector.size(); ++i ) { if( sblock_vector[i].pos() > new_vector.back().end() ) new_vector.push_back( Sblock( new_vector.back().end(), sblock_vector[i].pos() - new_vector.back().end(), st ) ); new_vector.push_back( sblock_vector[i] ); } sblock_vector.swap( new_vector ); } /* Enlarge mapfile to maximum size to ease comparison with other mapfile. Maybe this should be done only if requested. */ if( !sblock_vector.back().full() ) { Sblock & back = sblock_vector.back(); if( back.status() == st ) back.size( -1 ); // set size to max // else sblock_vector.push_back( Sblock( back.end(), -1, st ) ); } } } // end namespace void Mapfile::compact_sblock_vector() { unsigned long l; for( l = 1; l < sblock_vector.size(); ++l ) if( sblock_vector[l-1].status() == sblock_vector[l].status() ) break; if( l >= sblock_vector.size() ) return; // already compacted std::vector< Sblock > new_vector; for( l = 0; l < sblock_vector.size(); ) { Sblock run( sblock_vector[l] ); unsigned long r = l + 1; while( r < sblock_vector.size() && sblock_vector[r].status() == run.status() ) ++r; if( r > l + 1 ) run.size( sblock_vector[r-1].end() - run.pos() ); new_vector.push_back( run ); l = r; } sblock_vector.swap( new_vector ); } void Mapfile::join_subsectors( const int hardbs ) { for( unsigned long i = 0; i + 1 < sblock_vector.size(); ) { const long long boundary = sblock_vector[i].end(); const int rest = boundary % hardbs; // size of subsector in sb1 if( rest <= 0 ) { ++i; continue; } Sblock & sb1 = sblock_vector[i]; Sblock & sb2 = sblock_vector[i+1]; const Sblock::Status st1 = sb1.status(); const Sblock::Status st2 = sb2.status(); if( st1 == sb1.finished || st2 == sb1.finished ) { ++i; continue; } // move subsector to the block with the less processed state if( Sblock::processed_state( st1 ) <= Sblock::processed_state( st2 ) ) { if( sb2.size() > hardbs - rest ) // move subsector to sb1 { sb1.move_boundary( sb2, boundary + hardbs - rest ); ++i; continue; } } else { if( sb1.size() > rest ) // move subsector to sb2 { sb1.move_boundary( sb2, boundary - rest ); ++i; continue; } sb1.status( st2 ); // keep status of sb2 } sb1.enlarge( sb2.size() ); // join both blocks sblock_vector.erase( sblock_vector.begin() + i + 1 ); } } void Mapfile::extend_sblock_vector( const long long insize ) { if( sblock_vector.empty() ) { const Sblock sb( 0, ( insize > 0 ) ? insize : -1, Sblock::non_tried ); 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( insize > 0 ) { if( back.pos() >= insize ) { if( back.pos() == insize && back.status() != back.finished ) { sblock_vector.pop_back(); return; } show_error( "Last block in mapfile begins past end of input file.\n" " Use '-C' if you are reading from a partial copy.", 0, true ); std::exit( 1 ); } if( end > insize ) { if( back.status() != back.finished ) { back.size( insize - back.pos() ); return; } show_error( "Rescued data in mapfile 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 < insize ) sblock_vector.push_back( Sblock( end, insize - end, Sblock::non_tried ) ); } else if( end >= 0 ) { const Sblock sb( end, -1, Sblock::non_tried ); if( sb.size() > 0 ) sblock_vector.push_back( sb ); } } void Mapfile::shift_blocks( const long long offset, const Sblock::Status st ) { if( sblock_vector.empty() ) return; if( offset > 0 ) { if( sblock_vector.front().status() == st ) sblock_vector.front().enlarge( offset ); else insert_sblock( 0, Sblock( 0, offset, st ) ); for( unsigned long i = 1; i < sblock_vector.size(); ++i ) { sblock_vector[i].shift( offset ); if( sblock_vector[i].size() <= 0 ) // remove blocks past new end { sblock_vector.erase( sblock_vector.begin() + i, sblock_vector.end() ); break; } } } else if( offset < 0 ) { for( unsigned long i = 0; i < sblock_vector.size(); ++i ) if( sblock_vector[i].end() + offset > 0 ) { if( i > 0 ) // remove blocks before new beginning sblock_vector.erase( sblock_vector.begin(), sblock_vector.begin() + i ); break; } for( unsigned long i = 0; i < sblock_vector.size(); ++i ) sblock_vector[i].shift( offset ); } } /* Return false only if truncation would remove finished blocks and force is false. */ bool Mapfile::truncate_vector( const long long end, const bool force ) { unsigned long i = sblock_vector.size(); while( i > 0 && sblock_vector[i-1].pos() >= end ) --i; if( !force ) for( unsigned long j = i; j < sblock_vector.size(); ++j ) if( sblock_vector[j].status() == Sblock::finished ) return false; if( i == 0 ) { sblock_vector.clear(); sblock_vector.push_back( Sblock( 0, 0, Sblock::non_tried ) ); } else { Sblock & sb = sblock_vector[i-1]; if( sb.includes( end ) ) { if( !force && sb.status() == sb.finished ) return false; sb.size( end - sb.pos() ); } if( i < sblock_vector.size() ) sblock_vector.erase( sblock_vector.begin() + i, sblock_vector.end() ); } return true; } /* Return true if mapfile exists and is readable. Sort the blocks and fill the gaps if 'default_sblock_status' is a valid status character. */ bool Mapfile::read_mapfile( const int default_sblock_status, const bool ro ) { FILE * f = 0; errno = 0; read_only_ = ro; if( std::strcmp( filename_, "-" ) == 0 ) { f = stdin; read_only_ = true; } else if( ro || ( !(f = std::fopen( filename_, "r+" )) && errno != ENOENT ) ) { f = std::fopen( filename_, "r" ); read_only_ = true; } if( !f ) return false; unsigned linenum = 0; const bool loose = Sblock::isstatus( default_sblock_status ); sblock_vector.clear(); const char * line = my_fgets( f, linenum ); if( line ) // status line { char ch; current_pass_ = 1; // default value const int n = std::sscanf( line, "%lli %c %d\n", ¤t_pos_, &ch, ¤t_pass_ ); if( ( n == 3 || n == 2 ) && current_pos_ >= 0 && isstatus( ch ) && current_pass_ >= 1 ) current_status_ = Status( ch ); else { show_mapfile_error( pname(), "Bad or missing status line.", linenum ); std::exit( 2 ); } while( true ) { line = my_fgets( f, linenum ); if( !line ) break; long long pos, size; const int n = std::sscanf( line, "%lli %lli %c\n", &pos, &size, &ch ); if( n == 3 && pos >= 0 && Sblock::isstatus( ch ) && ( size > 0 || ( size == 0 && pos == 0 ) ) ) { const Sblock sb( pos, size, Sblock::Status( ch ) ); if( sblock_vector.empty() || sb.pos() == sblock_vector.back().end() ) { sblock_vector.push_back( sb ); continue; } if( loose ) { if( insert_sblock_sorted( sblock_vector, sb ) ) continue; show_mapfile_error( pname(), "Blocks of different status overlap.", linenum ); } else show_mapfile_error( pname(), "Blocks are not contiguous.", linenum ); } else show_mapfile_error( pname(), "Bad block line in list.", linenum ); std::exit( 2 ); } if( loose ) fill_gaps_in_sblock_vector( sblock_vector, Sblock::Status( default_sblock_status ) ); } if( std::ferror( f ) || !std::feof( f ) || std::fclose( f ) != 0 ) { show_mapfile_error( pname(), "Read error.", linenum ); std::exit( 1 ); } return true; } bool Mapfile::write_mapfile( FILE * f, const bool timestamp, const bool mf_sync, const Domain * const annotate_domainp ) const { const bool f_given = f != 0; bool error = false; if( !f && !filename_ ) return false; if( !f ) { f = std::fopen( filename_, "w" ); if( !f ) return false; } if( !write_file_header( f, "Mapfile" ) ) error = true; if( timestamp && !write_timestamp( f ) ) error = true; if( current_msg.size() && std::fprintf( f, "# %s\n", current_msg.c_str() ) < 0 ) error = true; char buf[80] = { 0 }; // comment if( annotate_domainp && snprintf( buf, sizeof buf, "\t# %sB", format_num( current_pos_ ) ) < 0 ) error = true; if( std::fprintf( f, "# current_pos current_status current_pass\n" "0x%08llX %c %d%s\n" "# pos size status\n", current_pos_, current_status_, current_pass_, buf ) < 0 ) error = true; for( unsigned long i = 0; i < sblock_vector.size(); ++i ) { const Sblock & sb = sblock_vector[i]; if( !annotate_domainp || !annotate_domainp->includes( sb ) ) buf[0] = 0; else if( snprintf( buf, sizeof buf, "\t# %9sB %9s%s", format_num( sb.pos() ), format_num( sb.size() ), ( sb.size() > 999999 ) ? "B" : "" ) < 0 ) error = true; if( std::fprintf( f, "0x%08llX 0x%08llX %c%s\n", sb.pos(), sb.size(), sb.status(), buf ) < 0 ) error = true; } if( mf_sync ) fsync( fileno( f ) ); return ( f_given || std::fclose( f ) == 0 ) && !error; } bool Mapfile::blank() const { for( unsigned long i = 0; i < sblock_vector.size(); ++i ) if( sblock_vector[i].status() != Sblock::non_tried ) return false; return true; } const char * Mapfile::pname( const bool in ) const { if( !filename_ || !*filename_ || std::strcmp( filename_, "-" ) == 0 ) return in ? "(stdin)" : "(stdout)"; return filename_; } void Mapfile::split_by_domain_borders( const Domain & domain ) { if( domain.blocks() == 1 ) { const Block & db = domain.block( 0 ); unsigned long i = 0; while( i < sblock_vector.size() && sblock_vector[i] < db ) ++i; if( i < sblock_vector.size() ) try_split_sblock_by( db.pos(), i ); i = sblock_vector.size(); while( i > 0 && db < sblock_vector[i-1] ) --i; if( i > 0 ) try_split_sblock_by( db.end(), i - 1 ); } else { std::vector< Sblock > new_vector; long j = 0; for( unsigned long i = 0; i < sblock_vector.size(); ) { Sblock & sb = sblock_vector[i]; while( j < domain.blocks() && domain.block( j ) < sb ) ++j; if( j >= domain.blocks() ) // end of domain tail copy { new_vector.insert( new_vector.end(), sblock_vector.begin() + i, sblock_vector.end() ); break; } const Block & db = domain.block( j ); if( sb.strictly_includes( db.pos() ) ) new_vector.push_back( sb.split( db.pos() ) ); if( sb.strictly_includes( db.end() ) ) new_vector.push_back( sb.split( db.end() ) ); if( sb.pos() < db.end() ) { new_vector.push_back( sb ); ++i; } } sblock_vector.swap( new_vector ); } } void Mapfile::split_by_mapfile_borders( const Mapfile & mapfile ) { std::vector< Sblock > new_vector; long j = 0; for( unsigned long i = 0; i < sblock_vector.size(); ) { Sblock & sb = sblock_vector[i]; while( j < mapfile.sblocks() && mapfile.sblock( j ) < sb ) ++j; if( j >= mapfile.sblocks() ) // end of mapfile tail copy { new_vector.insert( new_vector.end(), sblock_vector.begin() + i, sblock_vector.end() ); break; } const Sblock & db = mapfile.sblock( j ); if( sb.strictly_includes( db.pos() ) ) new_vector.push_back( sb.split( db.pos() ) ); if( sb.strictly_includes( db.end() ) ) new_vector.push_back( sb.split( db.end() ) ); if( sb.pos() < db.end() ) { new_vector.push_back( sb ); ++i; } } sblock_vector.swap( new_vector ); } long Mapfile::find_index( const long long pos ) const { if( index_ < 0 || index_ >= sblocks() ) index_ = sblocks() / 2; while( index_ + 1 < sblocks() && pos >= sblock_vector[index_+1].pos() ) ++index_; while( index_ > 0 && pos < sblock_vector[index_].pos() ) --index_; if( !sblock_vector[index_].includes( pos ) ) index_ = -1; return index_; } /* Find chunk from b.pos forwards of size <= b.size and status st. if unfinished is true, find also any chunk not marked as finished. If not found, or if after_finished is true and none of the blocks found follows a finished block, set b.size to 0. If at least one block of status st is found, return true. */ bool Mapfile::find_chunk( Block & b, const Sblock::Status st, const Domain & domain, const int alignment, const bool after_finished, const bool unfinished ) const { if( b.size() <= 0 ) return false; if( b.pos() < sblock_vector.front().pos() ) b.pos( sblock_vector.front().pos() ); if( find_index( b.pos() ) < 0 ) { b.size( 0 ); return false; } long i; bool block_found = false; for( i = index_; i < sblocks(); ++i ) { const Sblock::Status ist = sblock_vector[i].status(); if( ( ist == st || ( unfinished && ist != Sblock::finished ) ) && domain.includes( sblock_vector[i] ) ) { block_found = true; if( !after_finished || i <= 0 || sblock_vector[i-1].status() == Sblock::finished ) { index_ = i; break; } } } if( i >= sblocks() ) { b.size( 0 ); return block_found; } if( b.pos() < sblock_vector[index_].pos() ) b.pos( sblock_vector[index_].pos() ); if( !sblock_vector[index_].includes( b ) ) b.crop( sblock_vector[index_] ); if( b.end() != sblock_vector[index_].end() ) b.align_end( alignment ); return block_found; } /* Find chunk from b.end backwards of size <= b.size and status st. If not found, or if before_finished is true and none of the blocks found precedes a finished block, set b.size to 0. If at least one block of status st is found, return true. */ bool Mapfile::rfind_chunk( Block & b, const Sblock::Status st, const Domain & domain, const int alignment, const bool before_finished ) const { if( b.size() <= 0 ) return false; if( b.end() > sblock_vector.back().end() ) b.end( sblock_vector.back().end() ); if( find_index( b.end() - 1 ) < 0 ) { b.size( 0 ); return false; } long i; bool block_found = false; for( i = index_; i >= 0; --i ) if( sblock_vector[i].status() == st && domain.includes( sblock_vector[i] ) ) { block_found = true; if( !before_finished || i + 1 >= sblocks() || sblock_vector[i+1].status() == Sblock::finished ) { index_ = i; break; } } if( i < 0 ) { b.size( 0 ); return block_found; } 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 ); return block_found; } /* Return an adjust value (-1, 0, +1) to keep 'bad_areas' updated. - - - --> - + - return +1 - - + --> - + + return 0 - + - --> - - - return -1 - + + --> - - + return 0 + - - --> + + - return 0 + - + --> + + + return -1 + + - --> + - - return 0 + + + --> + - + return +1 */ int Mapfile::change_chunk_status( const Block & b, const Sblock::Status st, const Domain & domain, Sblock::Status * const old_stp ) { 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." ); const Sblock::Status old_st = sblock_vector[index_].status(); if( old_stp ) *old_stp = old_st; if( st == old_st ) return 0; const bool old_st_good = Sblock::is_good_status( old_st ); const bool new_st_good = Sblock::is_good_status( st ); bool bl_st_good = index_ <= 0 || Sblock::is_good_status( sblock_vector[index_-1].status() ) || !domain.includes( sblock_vector[index_-1] ); bool br_st_good = index_ + 1 >= sblocks() || Sblock::is_good_status( sblock_vector[index_+1].status() ) || !domain.includes( sblock_vector[index_+1] ); 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_].move_boundary( sblock_vector[index_+1], b.pos() ); 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() ) { if( index_ > 0 && sblock_vector[index_-1].status() == st && domain.includes( sblock_vector[index_-1] ) ) sblock_vector[index_-1].move_boundary( sblock_vector[index_], b.end() ); else insert_sblock( index_, Sblock( sblock_vector[index_].split( b.end() ), st ) ); br_st_good = old_st_good; } else { sblock_vector[index_].status( st ); const bool bl_join = index_ > 0 && sblock_vector[index_-1].status() == st && domain.includes( sblock_vector[index_-1] ); const bool br_join = index_ + 1 < sblocks() && sblock_vector[index_+1].status() == st && domain.includes( sblock_vector[index_+1] ); if( bl_join || br_join ) { if( br_join ) sblock_vector[index_].join( sblock_vector[index_+1] ); if( bl_join ) { --index_; sblock_vector[index_].join( sblock_vector[index_+1] ); } sblock_vector.erase( sblock_vector.begin() + ( index_ + 1 ), sblock_vector.begin() + ( index_ + 1 + bl_join + br_join ) ); } } 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 * Mapfile::status_name( const Mapfile::Status st ) { switch( st ) { case copying: return "copying"; case trimming: return "trimming"; case sweeping: return "sweeping"; case scraping: return "scraping"; case retrying: return "retrying"; case filling: return "filling"; case generating: return "generating"; case finished: return "finished"; } return "unknown"; // should not be reached } gddrescue-1.30/mapfile.h000066400000000000000000000321201512716454500152000ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 . */ #include #include #include // FILE #include #include #ifndef LLONG_MAX #define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL #endif class Block { long long pos_, size_; // pos >= 0 && size >= 0 && pos + size <= LLONG_MAX void fix_size() // limit size_ to largest possible value { if( size_ < 0 || size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; } public: Block() {} // default constructor Block( const long long p, const long long s ) : pos_( p ), size_( s ) { if( p < 0 ) { pos_ = 0; if( s > 0 ) size_ -= std::min( s, -p ); } fix_size(); } long long pos() const { return pos_; } long long size() const { return size_; } long long end() const { return pos_ + size_; } bool full() const { return ( end() >= LLONG_MAX ); } void pos( const long long p ) { pos_ = std::max( p, 0LL ); if( size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; } void shift( const long long offset ) { if( offset >= 0 ) { pos_ += std::min( offset, LLONG_MAX - pos_ ); if( size_ > LLONG_MAX - pos_ ) size_ = LLONG_MAX - pos_; } else if( ( pos_ += offset ) < 0 ) { size_ = std::max( size_ + pos_, 0LL ); pos_ = 0; } } void size( const long long s ) { size_ = s; fix_size(); } void enlarge( long long s ) { if( s < 0 ) s = LLONG_MAX; if( s > LLONG_MAX - end() ) s = LLONG_MAX - end(); size_ += s; } void end( long long e ) // also moves pos { if( e < 0 ) e = LLONG_MAX; if( size_ <= e ) pos_ = e - size_; else { pos_ = 0; size_ = e; } } Block & assign( const long long p, const long long s ) { pos_ = p; size_ = s; if( p < 0 ) { pos_ = 0; if( s > 0 ) size_ -= std::min( s, -p ); } // keep end fix_size(); return *this; } void align_pos( const int alignment ); void align_end( const int alignment ); 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 operator<( const Block & b ) const { return ( end() <= b.pos_ ); } 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 ); } bool strictly_includes( const long long pos ) const { return ( pos_ < pos && end() > pos ); } bool overlaps( const Block & b ) const { return ( pos_ < b.end() && b.pos_ < end() ); } void crop( const Block & b ) { const long long p = std::max( pos_, b.pos_ ); size_ = std::max( 0LL, std::min( end(), b.end() ) - p ); pos_ = p; } bool join( const Block & b ); // join contiguous blocks void move_boundary( Block & b, const long long pos ); Block split( long long pos, const int hardbs = 1 ); }; class Sblock : public Block { public: enum Status // ordered from less to more processed state { non_tried = '?', non_trimmed = '*', non_scraped = '/', bad_sector = '-', finished = '+' }; private: Status status_; public: Sblock() {} // default constructor 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_scraped || st == bad_sector || st == finished ); } static bool is_good_status( const Status st ) { return st != bad_sector; } static int processed_state( const Status st ) { switch( st ) { case non_tried: return 0; case non_trimmed: return 1; case non_scraped: return 2; case bad_sector: return 3; default: return 4; } } }; class Domain { std::vector< Block > block_vector; // blocks are ordered and don't overlap mutable long long cached_in_size; void reset_cached_in_size() { cached_in_size = -1; } public: Domain( const long long p, const long long s, const char * const mapname = 0, const bool loose = false ); long long pos() const { return block_vector.front().pos(); } long long end() const { return block_vector.back().end(); } long long size() const { return end() - pos(); } const Block & block( const long i ) const { return block_vector[i]; } long blocks() const { return block_vector.size(); } bool empty() const { return ( end() <= pos() ); } bool full() const { return ( !empty() && end() >= LLONG_MAX ); } long long in_size() const { if( cached_in_size < 0 ) { cached_in_size = 0; for( unsigned long i = 0; i < block_vector.size(); ++i ) cached_in_size += block_vector[i].size(); } return cached_in_size; } bool operator!=( const Domain & d ) const { if( block_vector.size() != d.block_vector.size() ) return true; for( unsigned long 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 ( end() <= b.pos() ); } bool operator>( const Block & b ) const { return ( pos() >= b.end() ); } bool includes( const Block & b ) const { unsigned long l = 0, r = block_vector.size(); while( l < r ) { const long m = ( l + r ) / 2; const Block & db = block_vector[m]; if( db.includes( b ) ) return true; if( db < b ) l = m + 1; else if( b < db ) r = m; else break; } return false; } bool includes( const long long pos ) const { for( unsigned long i = 0; i < block_vector.size(); ++i ) if( block_vector[i].includes( pos ) ) return true; return false; } bool overlaps( const Block & b ) const { unsigned long l = 0, r = block_vector.size(); while( l < r ) { const long m = ( l + r ) / 2; const Block & db = block_vector[m]; if( db.overlaps( b ) ) return true; if( db < b ) l = m + 1; else if( b < db ) r = m; else break; } return false; } void clear() { block_vector.clear(); block_vector.push_back( Block( 0, 0 ) ); cached_in_size = 0; } void crop( const Block & b ); void crop_by_file_size( const long long size ) { crop( Block( 0, size ) ); } }; class Mapfile { public: enum Status { copying = '?', trimming = '*', sweeping = '%', scraping = '/', retrying = '-', filling = 'F', generating = 'G', finished = '+' }; private: long long current_pos_; const char * const filename_; std::string current_msg; Status current_status_; int current_pass_; mutable long index_; // cached index of last find or change bool read_only_; std::vector< Sblock > sblock_vector; // note: blocks are consecutive void insert_sblock( const long i, const Sblock & sb ) // insert before i { sblock_vector.insert( sblock_vector.begin() + i, sb ); } public: explicit Mapfile( const char * const mapname ) : current_pos_( 0 ), filename_( mapname ), current_status_( copying ), current_pass_( 1 ), index_( 0 ), read_only_( false ) {} void compact_sblock_vector(); void join_subsectors( const int hardbs ); void extend_sblock_vector( const long long insize ); void shift_blocks( const long long offset, const Sblock::Status st ); bool truncate_vector( const long long end, const bool force = false ); void set_to_status( const Sblock::Status st ) { sblock_vector.assign( 1, Sblock( 0, -1, st ) ); } bool read_mapfile( const int default_sblock_status = 0, const bool ro = true ); bool write_mapfile( FILE * f = 0, const bool timestamp = false, const bool mf_sync = false, const Domain * const annotate_domainp = 0 ) const; bool blank() const; // empty or all blocks non_tried long long current_pos() const { return current_pos_; } Status current_status() const { return current_status_; } int current_pass() const { return current_pass_; } const char * filename() const { return filename_; } const char * pname( const bool in = true ) const; // printable name bool read_only() const { return read_only_; } void current_pos( const long long pos ) { current_pos_ = pos; } void current_status( const Status st, const char * const msg = "" ) { current_status_ = st; current_msg = ( st == finished ) ? "Finished" : msg; } void current_pass( const int pass ) { current_pass_ = pass; } Block extent() const // pos of first block may be > 0 { if( sblock_vector.empty() ) return Block( 0, 0 ); return Block( sblock_vector.front().pos(), sblock_vector.back().end() - sblock_vector.front().pos() ); } const Sblock & sblock( const long i ) const { return sblock_vector[i]; } long sblocks() const { return sblock_vector.size(); } void change_sblock_status( const long i, const Sblock::Status st ) { sblock_vector[i].status( st ); } void append_sblock( long long size, const Sblock::Status st ) { if( !sblock_vector.empty() && sblock_vector.back().status() == st ) { sblock_vector.back().enlarge( size ); return; } const long long pos = sblock_vector.empty() ? 0 : sblock_vector.back().end(); if( size > LLONG_MAX - pos ) size = LLONG_MAX - pos; sblock_vector.push_back( Sblock( pos, size, st ) ); } void split_by_domain_borders( const Domain & domain ); void split_by_mapfile_borders( const Mapfile & mapfile ); bool try_split_sblock_by( const long long pos, const long i ) { if( sblock_vector[i].strictly_includes( pos ) ) { insert_sblock( i, sblock_vector[i].split( pos ) ); return true; } return false; } long find_index( const long long pos ) const; bool find_chunk( Block & b, const Sblock::Status st, const Domain & domain, const int alignment, const bool after_finished = false, const bool unfinished = false ) const; bool rfind_chunk( Block & b, const Sblock::Status st, const Domain & domain, const int alignment, const bool before_finished = false ) const; int change_chunk_status( const Block & b, const Sblock::Status st, const Domain & domain, Sblock::Status * const old_stp = 0 ); static bool isstatus( const int st ) { return ( st == copying || st == trimming || st == sweeping || st == scraping || st == retrying || st == filling || st == generating || st == finished ); } static const char * status_name( const Status st ); }; // Defined in main_common.cc extern int verbosity; void show_option_error( const char * const arg, const char * const msg, const char * const option_name ); void show_error( const char * const msg, const int errcode = 0, const bool help = false ); void show_file_error( const char * const filename, const char * const msg, const int errcode = 0 ); void internal_error( const char * const msg ); int empty_domain(); int not_readable( const char * const mapname ); int not_writable( const char * const mapname ); long long initial_time(); bool write_file_header( FILE * const f, const char * const filetype ); bool write_timestamp( FILE * const f ); bool write_final_timestamp( FILE * const f ); const char * format_num( long long num, int limit = 999999, const int set_prefix = 0 ); const char * format_num3p( long long num, const bool space = false ); const char * format_num3( unsigned long long num, const bool negative = false ); long long getnum( const char * const arg, const char * const option_name, const int hardbs, const long long llimit = -LLONG_MAX, const long long ulimit = LLONG_MAX, const char ** const tailp = 0 ); const char * format_percentage( long long num, long long den, const int iwidth = 3, int prec = -2, const bool rounding = true ); gddrescue-1.30/non_posix.cc000066400000000000000000000071051512716454500157420ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2014-2026 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 2 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 "non_posix.h" #ifdef USE_NON_POSIX #include #include namespace { void sanitize_string( std::string & str ) { for( unsigned i = str.size(); i > 0; --i ) // remove non-printable chars { const unsigned char ch = str[i-1]; if( std::isspace( ch ) ) str[i-1] = ' '; else if( ch < 32 || ch > 126 ) str.erase( i - 1, 1 ); } for( unsigned i = str.size(); i > 0; --i ) // remove duplicate spaces if( str[i-1] == ' ' && ( i <= 1 || i >= str.size() || str[i-2] == ' ' ) ) str.erase( i - 1, 1 ); } } // end namespace #ifdef __HAIKU__ #include bool device_id( const int fd, std::string & id_str ) { char buf[256]; if( ioctl( fd, B_GET_DEVICE_NAME, buf, sizeof buf ) != 0 ) return false; buf[(sizeof buf)-1] = 0; // make sure it is null-terminated id_str = (const char *)buf; sanitize_string( id_str ); return true; } #elif defined __CYGWIN__ // Cygwin code based on a patch written by Christian Franke. #include #define _WIN32_WINNT 0x0600 // >= Vista, for BusTypeSata #include bool device_id( const int fd, std::string & id_str ) { HANDLE h = (HANDLE) _get_osfhandle( fd ); if( h == INVALID_HANDLE_VALUE ) return false; STORAGE_PROPERTY_QUERY query = { StorageDeviceProperty, PropertyStandardQuery, { 0 } }; union { char raw[1024]; STORAGE_DEVICE_DESCRIPTOR desc; } data = { { 0, } }; DWORD nout = 0; if( !DeviceIoControl( h, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &data, sizeof(data), &nout, (LPOVERLAPPED)0 ) ) return false; if( data.desc.VendorIdOffset ) id_str = &data.raw[data.desc.VendorIdOffset]; else id_str = ""; if( data.desc.ProductIdOffset ) { if( data.desc.BusType != BusTypeAta && data.desc.BusType != BusTypeSata ) id_str += ' '; id_str += &data.raw[data.desc.ProductIdOffset]; } sanitize_string( id_str ); if( id_str.empty() ) return false; if( data.desc.SerialNumberOffset ) { std::string id_serial( &data.raw[data.desc.SerialNumberOffset] ); sanitize_string( id_serial ); if( !id_serial.empty() ) { id_str += "::"; id_str += id_serial; } } return true; } #else // use linux by default #include bool device_id( const int fd, std::string & id_str ) { struct hd_driveid id; if( ioctl( fd, HDIO_GET_IDENTITY, &id ) != 0 ) return false; id_str = (const char *)id.model; std::string id_serial( (const char *)id.serial_no ); sanitize_string( id_str ); sanitize_string( id_serial ); if( !id_str.empty() || !id_serial.empty() ) { id_str += "::"; id_str += id_serial; return true; } return false; } #endif #else // USE_NON_POSIX bool device_id( const int, std::string & ) { return false; } #endif gddrescue-1.30/non_posix.h000066400000000000000000000014201512716454500155760ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2014-2026 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 2 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 . */ bool device_id( const int fd, std::string & id_str ); gddrescue-1.30/rational.cc000066400000000000000000000176501512716454500155450ustar00rootroot00000000000000/* Rational - Rational number class with overflow detection Copyright (C) 2005-2026 Antonio Diaz Diaz. This library is free software. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 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 { long long gcd( 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; } } std::string overflow_string( const int n ) { if( n > 0 ) return "+INF"; if( n < 0 ) return "-INF"; return "NAN"; } int overflow_value( const long long n, const bool negate = false ) { if( negate ) { if( n > 0 ) return -INT_MAX; if( n < 0 ) return INT_MAX; return 0; } else { 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 = overflow_value( n ); den = 0; return; } // set error if( n == 0 ) { num = 0; den = 1; return; } if( d < 0 ) { n = -n; d = -d; } // just in case if( d != 1 ) { const long long tmp = gcd( n, d ); n /= tmp; d /= tmp; } if( n <= INT_MAX && n >= -INT_MAX && d <= INT_MAX && d > 0 ) { num = n; den = d; return; } // n / d is in range within precision num = overflow_value( n, d < 0 ); den = 0; } void Rational::normalize() { if( den == 0 ) { num = overflow_value( num ); return; } if( num == 0 ) { den = 1; return; } if( den != 1 ) { const int tmp = gcd( num, den ); num /= tmp; den /= tmp; } if( num < -INT_MAX ) { num = overflow_value( den, true ); den = 0; return; } if( den < 0 ) { if( den < -INT_MAX ) { num = overflow_value( num, true ); den = 0; return; } num = -num; den = -den; } } 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 long long new_den = den; new_den *= r.den; long long new_num1 = num; new_num1 *= r.den; long long new_num2 = r.num; new_num2 *= den; normalize( new_num1 + new_num2, 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 long long new_num = num; new_num *= r.num; long long new_den = den; new_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. Return 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; while( std::isspace( s[c] ) ) ++c; const bool minus = s[c] == '-'; if( minus || s[c] == '+' ) ++c; if( !std::isdigit( s[c] ) && s[c] != '.' ) return 0; while( std::isdigit( s[c] ) ) // integer part or numerator { if( ( LLONG_MAX - (s[c] - '0') ) / 10 < n ) return 0; n = (n * 10) + (s[c] - '0'); ++c; if( s[c] == '_' && std::isdigit( s[c+1] ) ) ++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; if( s[c] == '_' && std::isdigit( s[c+1] ) ) ++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( s[c] == '_' && std::isdigit( s[c+1] ) ) ++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( s[c] == '_' ) return 0; // trailing underscore if( minus ) n = -n; Rational tmp; tmp.normalize( n, d ); if( tmp.error() ) return 0; *this = tmp; return c; } /* Return 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, produce only the decimals needed. If 'rounding', round up the last digit if the next one would be >= 5. */ std::string Rational::to_decimal( const unsigned iwidth, int prec, const bool rounding ) 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 += ( ipart % 10 ) + '0'; 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 += ( rest / den ) + '0'; rest %= den; --prec; } } if( rounding && rest * 2 >= den ) // round last decimal up for( int j = s.size() - 1; j >= 0; --j ) { if( s[j] == '.' ) continue; if( s[j] >= '0' && s[j] < '9' ) { ++s[j]; break; } if( s[j] == '9' ) s[j] = '0'; if( j > 0 && s[j-1] == '.' ) continue; if( j > 0 && s[j-1] == ' ' ) { s[j-1] = '1'; break; } if( j > 1 && s[j-2] == ' ' && s[j-1] == '-' ) { s[j-2] = '-'; s[j-1] = '1'; break; } // no prev digit, prepend '1' to the first digit if( j == 0 || s[j-1] < '0' || s[j-1] > '9' ) { s.insert( s.begin() + j, '1' ); break; } } return s; } /* Return a string representing the value 'num/den' in fractional form. 'width' is the minimum width to be produced, prefixed with spaces if needed. If den == 1, print num alone. */ 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; if( d > 1 ) { do { s += ( d % 10 ) + '0'; d /= 10; } while( d > 0 ); s += '/'; } do { s += ( n % 10 ) + '0'; 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.30/rational.h000066400000000000000000000152501512716454500154010ustar00rootroot00000000000000/* Rational - Rational number class with overflow detection Copyright (C) 2005-2026 Antonio Diaz Diaz. This library is free software. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 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 function 'error', and can only be cleared by 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 { return ( num > 0 ) - ( num < 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 ) // postfix { Rational tmp( *this ); operator+=( 1 ); return tmp; } Rational & operator--() { return operator-=( 1 ); } // prefix Rational operator--( int ) // postfix { 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 ( den > 0 && r.den > 0 && (long long)num * r.den <= (long long)r.num * den ); } 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 ( den > 0 && r.den > 0 && (long long)num * r.den >= (long long)r.num * den ); } 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 ); // return parsed length std::string to_decimal( const unsigned iwidth = 1, int prec = -2, const bool rounding = false ) 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.30/rescuebook.cc000066400000000000000000001164231512716454500160730ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 "mapfile.h" #include "loggers.h" #include "mapbook.h" #include "rational.h" #include "rescuebook.h" namespace { // Round "size" to the next multiple of sector size (hardbs). // long long round_up( long long size, const int hardbs ) { if( size % hardbs ) { size -= size % hardbs; if( LLONG_MAX - size >= hardbs ) size += hardbs; } return size; } } // end namespace void Rescuebook::change_chunk_status( const Block & b, const Sblock::Status st ) { Sblock::Status old_st = st; bad_areas += Mapfile::change_chunk_status( b, st, domain(), &old_st ); if( st == old_st ) return; switch( old_st ) { case Sblock::non_tried: non_tried_size -= b.size(); break; case Sblock::non_trimmed: non_trimmed_size -= b.size(); break; case Sblock::non_scraped: non_scraped_size -= b.size(); break; case Sblock::bad_sector: bad_size -= b.size(); break; case Sblock::finished: finished_size -= b.size(); break; } switch( st ) { case Sblock::non_tried: non_tried_size += b.size(); break; case Sblock::non_trimmed: non_trimmed_size += b.size(); break; case Sblock::non_scraped: non_scraped_size += b.size(); break; case Sblock::bad_sector: bad_size += b.size(); break; case Sblock::finished: finished_size += b.size(); break; } } void Rescuebook::do_pause_on_error() { if( simulated_poe ) tp += pause_on_error; else if( pause_on_error >= 1 ) sleep( pause_on_error.trunc() ); } 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 ) { int ret; do ret = ftruncate( odes_, min_size ); while( ret != 0 && errno == EINTR ); if( ret != 0 || lseek( odes_, 0, SEEK_END ) != min_size ) { const uint8_t zero = 0; // if ftruncate fails, write a zero if( writeblockp( odes_, &zero, 1, min_size - 1 ) != 1 ) return false; } fsync( odes_ ); } } return true; } /* Return values: 1 fatal error, 0 OK (I/O errors are ignored). 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 block size in copy_block." ); int saved_errno; // for read_logger if( !test_domainp || test_domainp->includes( b ) ) { if( o_direct_in || bsd_buf ) // read whole sectors, write requested part { const int pre = b.pos() % hardbs(); const int rest = b.end() % hardbs(); const int post = ( rest > 0 ) ? hardbs() - rest : 0; const int size = pre + b.size() + post; if( size > iobuf_size() ) internal_error( "(size > iobuf_size) copying a Block." ); copied_size = readblockp( ides_, iobuf(), size, b.pos() - pre ); adjust_copied_size( copied_size ); // discard bad_sector_data copied_size -= std::min( pre, copied_size ); if( copied_size > b.size() ) copied_size = b.size(); if( pre > 0 && copied_size > 0 ) std::memmove( iobuf(), iobuf() + pre, copied_size ); } else copied_size = readblockp( ides_, iobuf(), b.size(), b.pos() ); saved_errno = errno; error_size = errno ? b.size() - copied_size : 0; if( copied_size <= 0 ) switch( errno ) { case EACCES: case EBADF: case EBUSY: case EISDIR: case ENOBUFS: case ENODEV: case ENOENT: case ENOMEM: case ENOSYS: case ENXIO: case EPERM: case ESPIPE: for( unsigned i = 0; i < errno_vector.size(); ++i ) if( errno_vector[i] == errno ) goto non_fatal; final_msg( iname_, "Fatal error reading the input file", errno ); return 1; case EINVAL: final_msg( iname_, "Unaligned read error. Is sector size correct?" ); return 1; } non_fatal: ; } else { copied_size = 0; error_size = b.size(); saved_errno = EIO; } if( copied_size > 0 ) { iobuf_ipos = b.pos(); 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( !compare_before_write || readblockp( odes_, iobuf2(), copied_size, pos ) != copied_size || std::memcmp( iobuf(), iobuf2(), copied_size ) != 0 ) if( writeblockp( odes_, iobuf(), copied_size, pos ) != copied_size || ( synchronous_ && fsync( odes_ ) != 0 && errno != EINVAL ) ) { final_msg( oname_, wr_err_msg, errno ); return 1; } } else iobuf_ipos = -1; read_logger.print_line( b.pos(), b.size(), copied_size, error_size, saved_errno ); if( check_on_error ) { if( copied_size >= hardbs() && b.pos() % hardbs() == 0 ) { coe_ipos = b.pos(); std::memcpy( coe_buf, iobuf(), hardbs() ); } if( error_size > 0 ) { if( coe_ipos >= 0 ) { const int size = readblockp( ides_, iobuf2(), hardbs(), coe_ipos ); if( size != hardbs() ) { final_msg( iname_, "Input file no longer returns data", errno ); e_code |= 8; } else if( std::memcmp( coe_buf, iobuf2(), hardbs() ) != 0 ) { final_msg( iname_, "Input file returns inconsistent data." ); e_code |= 8; } } else { final_msg( iname_, "Read error found before the first good read." ); e_code |= 8; } } } return 0; } void Rescuebook::initialize_sizes() { bool good = true; non_tried_size = non_trimmed_size = non_scraped_size = 0; bad_size = finished_size = 0; bad_areas = 0; for( long 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: non_tried_size += sb.size(); good = true; break; case Sblock::non_trimmed: non_trimmed_size += sb.size(); good = true; break; case Sblock::non_scraped: non_scraped_size += sb.size(); good = true; break; case Sblock::bad_sector: bad_size += sb.size(); if( good ) { good = false; ++bad_areas; } break; case Sblock::finished: finished_size += sb.size(); good = true; break; } } } // Return values: 1 error, 0 OK, -1 interrupted. // int Rescuebook::copy_and_update( const Block & b, int & copied_size, int & error_size, const char * const msg, const Status curr_st, const int curr_pass, const bool forward, const Sblock::Status st ) { if( first_post ) { if( !first_read && pause_on_pass > 0 ) { show_status( -1, "Paused", true ); sleep( pause_on_pass ); const long long t2 = std::time( 0 ); if( t1 < t2 ) t1 = t2; // clock may have jumped back ts = std::min( ts + pause_on_pass, t2 ); // avoid spurious timeout } current_status( curr_st, msg ); current_pass( curr_pass ); event_logger.print_msg( t1 - t0, finished_size, percent_rescued(), msg, format_num( a_rate, 99999 ), read_errors ); read_logger.print_msg( t1 - t0, msg ); } current_pos( forward ? b.pos() : b.end() ); show_status( b.pos(), msg ); if( errors_or_timeout() ) return 1; if( interrupted() ) return -1; int retval = copy_block( b, copied_size, error_size ); if( retval == 0 ) { 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( iname_, early_eof_msg ); retval = 1; } initialize_sizes(); } if( copied_size > 0 ) change_chunk_status( Block( b.pos(), copied_size ), Sblock::finished ); if( error_size > 0 ) { error_sum += error_size; ++read_errors; if( read_errors > max_read_errors ) { e_code |= 16; retval = 1; } const Sblock::Status st2 = ( error_size > hardbs() ) ? st : Sblock::bad_sector; change_chunk_status( Block( b.pos() + copied_size, error_size ), st2 ); struct stat istat; if( stat( iname_, &istat ) != 0 ) { final_msg( iname_, disap_msg, errno ); retval = 1; } } } return retval; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Read the non-tried part of the domain, skipping over the damaged areas. */ int Rescuebook::copy_non_tried() { char msgbuf[80] = "Copying non-tried blocks... Pass "; const int msglen = std::strlen( msgbuf ); const bool cpass_given = cpass_bitset != 15; bool resume = !cpass_given && current_status() == copying && current_pass() <= 4; if( !resume ) current_pass( 1 ); // reset pass const int first_pass = current_pass(); bool forward = !reverse; for( int pass = 1; pass <= 4; ++pass ) { if( pass >= first_pass && cpass_bitset & ( 1 << ( pass - 1 ) ) ) { if( pass != first_pass ) resume = false; first_post = true; snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%u %s", pass, forward ? "(forwards)" : "(backwards)" ); const int retval = forward ? fcopy_non_tried( msgbuf, pass, resume ) : rcopy_non_tried( msgbuf, pass, resume ); if( retval != -3 ) return retval; } if( pass >= 2 && min_read_rate >= 0 ) min_read_rate = -1; // reset rate if( !unidirectional ) forward = !forward; } return 0; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Read forwards the non-tried part of the domain, skipping over the damaged areas. */ int Rescuebook::fcopy_non_tried( const char * const msg, const int pass, const bool resume ) { long long pos = 0; long long eskip_size = skipbs; // size to skip on error if skipbs > 0 long long sskip_size = 0; // size to skip on slow if skipbs > 0 bool block_found = false; bool block_processed = false; if( resume && domain().includes( current_pos() ) ) { Block b( current_pos(), 1 ); find_chunk( b, Sblock::non_tried, domain(), hardbs() ); if( b.size() > 0 ) pos = b.pos(); // resume } while( pos >= 0 ) { Block b( pos, softbs() ); if( find_chunk( b, Sblock::non_tried, domain(), softbs(), pass >= 2 ) ) block_found = true; if( b.size() <= 0 ) break; block_processed = true; if( pos != b.pos() ) // reset size on block change { eskip_size = skipbs; current_slow = false; } pos = b.end(); int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, copying, pass, true, Sblock::non_trimmed ); if( retval ) return retval; const bool slow = update_rates(); if( slow && ++slow_reads > max_slow_reads ) { e_code |= 32; return 1; } if( ( error_size > 0 || ( slow && pass <= 2 ) ) && pos >= 0 ) { if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); if( skipbs > 0 ) // don't skip if skipbs == 0 { b.pos( pos ); if( error_size > 0 ) { if( pass == 1 ) { b.size( eskip_size ); if( eskip_size <= max_skipbs / 2 ) eskip_size *= 2; else eskip_size = max_skipbs; } else b.size( -1 ); // (max size) skip rest of block at first error } else // slow read { if( !prev_slow ) sskip_size = std::max( skipbs, std::min( c_rate, max_skipbs ) ); else if( sskip_size <= max_skipbs / 2 ) sskip_size *= 2; else sskip_size = max_skipbs; b.size( sskip_size ); } find_chunk( b, Sblock::non_tried, domain(), hardbs() ); if( pos == b.pos() && b.size() > 0 ) pos = b.end(); // skip } } else if( error_size == 0 && copied_size > 0 ) eskip_size = skipbs; // reset if( !update_mapfile( odes_ ) ) return -2; } if( !block_found ) return 0; if( block_processed ) show_status( -1, msg, true ); // update at end of pass return -3; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Read backwards the non-tried part of the domain, skipping over the damaged areas. */ int Rescuebook::rcopy_non_tried( const char * const msg, const int pass, const bool resume ) { long long end = LLONG_MAX; long long eskip_size = skipbs; // size to skip on error if skipbs > 0 long long sskip_size = 0; // size to skip on slow if skipbs > 0 bool block_found = false; bool block_processed = false; if( resume && domain().includes( current_pos() - 1 ) ) { Block b( current_pos() - 1, 1 ); rfind_chunk( b, Sblock::non_tried, domain(), hardbs() ); if( b.size() > 0 ) end = b.end(); // resume } while( end > 0 ) { Block b( end - softbs(), softbs() ); if( rfind_chunk( b, Sblock::non_tried, domain(), softbs(), pass >= 2 ) ) block_found = true; if( b.size() <= 0 ) break; block_processed = true; if( end != b.end() ) // reset size on block change { eskip_size = skipbs; current_slow = false; } end = b.pos(); int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, copying, pass, false, Sblock::non_trimmed ); if( retval ) return retval; const bool slow = update_rates(); if( slow && ++slow_reads > max_slow_reads ) { e_code |= 32; return 1; } if( ( error_size > 0 || ( slow && pass <= 2 ) ) && end > 0 ) { if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); if( skipbs > 0 ) // don't skip if skipbs == 0 { if( error_size > 0 ) { if( pass == 1 ) { b.assign( end - eskip_size, eskip_size ); if( eskip_size <= max_skipbs / 2 ) eskip_size *= 2; else eskip_size = max_skipbs; } else b.assign( 0, end ); // skip rest of block at first error } else // slow read { if( !prev_slow ) sskip_size = std::max( skipbs, std::min( c_rate, max_skipbs ) ); else if( sskip_size <= max_skipbs / 2 ) sskip_size *= 2; else sskip_size = max_skipbs; b.assign( end - sskip_size, sskip_size ); } rfind_chunk( b, Sblock::non_tried, domain(), hardbs() ); if( end == b.end() && b.size() > 0 ) end = b.pos(); // skip } } else if( error_size == 0 && copied_size > 0 ) eskip_size = skipbs; // reset if( !update_mapfile( odes_ ) ) return -2; } if( !block_found ) return 0; if( block_processed ) show_status( -1, msg, true ); // update at end of pass return -3; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Trim each non_trimmed block from the edge(s) adjacent to a finished block. Leave untrimmed the edge(s) adjacent to a non-tried block. If both edges touch tried blocks, mark the rest of the block as non-scraped. */ int Rescuebook::trim_errors( const char * msg ) { if( !msg ) msg = reverse ? "Trimming failed blocks... (backwards)" : "Trimming failed blocks... (forwards)"; const bool sweep = current_status() == sweeping; if( !sweep ) first_post = true; for( long i = 0; i < sblocks(); ) { const long idx = reverse ? sblocks() - 1 - i : i; const Sblock sb( sblock( idx ) ); if( !domain().includes( sb ) ) { if( ( !reverse && domain() < sb ) || ( reverse && domain() > sb ) ) break; ++i; continue; } if( sb.status() != sb.non_trimmed ) { ++i; continue; } const bool lgood = idx <= 0 || sblock( idx - 1 ).status() == sb.finished; const bool rgood = idx + 1 >= sblocks() || sblock( idx + 1 ).status() == sb.finished; const bool untried = idx <= 0 || sblock( idx - 1 ).status() == sb.non_tried || sblock( idx - 1 ).status() == sb.non_trimmed || idx + 1 >= sblocks() || sblock( idx + 1 ).status() == sb.non_tried || sblock( idx + 1 ).status() == sb.non_trimmed; if( !lgood && !rgood ) // leave block for sweeping or scraping { if( !untried ) change_chunk_status( sb, sb.non_scraped ); ++i; continue; } bool error_found = !lgood; long long pos = sb.pos(); long long end = sb.end(); while( pos < end && !error_found ) // trim leading edge { Block b( pos, std::min( (long long)hardbs(), end - pos ) ); if( b.end() != end ) b.align_end( hardbs() ); pos = b.end(); int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, sweep ? sweeping : trimming, 1, true ); if( retval ) return retval; update_rates(); if( error_size > 0 ) { error_found = true; if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); } if( !update_mapfile( odes_ ) ) return -2; } error_found = !rgood; while( pos < end && !error_found ) // trim trailing edge { const int size = std::min( (long long)hardbs(), end - pos ); Block b( end - size, size ); if( b.pos() != pos ) b.align_pos( hardbs() ); end = b.pos(); int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, sweep ? sweeping : trimming, 1, false ); if( retval ) return retval; update_rates(); if( error_size > 0 ) { error_found = true; if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); } if( !update_mapfile( odes_ ) ) return -2; } if( pos < end && !untried ) { const long index = find_index( end - 1 ); if( index >= 0 && domain().includes( sblock( index ) ) && sblock( index ).status() == sb.non_trimmed ) change_chunk_status( sblock( index ), sb.non_scraped ); } } if( !sweep ) show_status( -1, msg, true ); // update at end of pass return 0; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Read the remaining non-tried part of the domain skipped during copying. */ int Rescuebook::sweep_non_tried() { const char * const msg = reverse ? "Sweeping non-tried blocks... (backwards)" : "Sweeping non-tried blocks... (forwards)"; first_post = true; for( long i = 0; i < sblocks(); ) { const long idx = reverse ? sblocks() - 1 - i : i; const Sblock sb( sblock( idx ) ); if( !domain().includes( sb ) ) { if( ( !reverse && domain() < sb ) || ( reverse && domain() > sb ) ) break; ++i; continue; } if( sb.status() != sb.non_tried ) { ++i; continue; } long long pos = (!reverse || sb.size() <= softbs()) ? sb.pos() : sb.end() - 1 - ( sb.size() - 1 ) % softbs(); while( pos >= sb.pos() && pos < sb.end() ) { const Block b( pos, std::min( (long long)softbs(), sb.end() - pos ) ); if( reverse ) pos -= softbs(); else pos += softbs(); int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, sweeping, 1, !reverse, Sblock::non_trimmed ); if( retval ) return retval; update_rates(); if( error_size > 0 && pos >= sb.pos() && pos < sb.end() ) { if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); } if( !update_mapfile( odes_ ) ) return -2; } const int retval = trim_errors( msg ); if( retval ) return retval; } show_status( -1, msg, true ); // update at end of pass return 0; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Scrape the damaged areas sequentially. */ int Rescuebook::scrape_errors() { const char * const msg = reverse ? "Scraping failed blocks... (backwards)" : "Scraping failed blocks... (forwards)"; first_post = true; for( long i = 0; i < sblocks(); ) { const Sblock sb( sblock( reverse ? sblocks() - 1 - i : i ) ); if( !domain().includes( sb ) ) { if( ( !reverse && domain() < sb ) || ( reverse && domain() > sb ) ) break; ++i; continue; } if( sb.status() != sb.non_scraped ) { ++i; continue; } long long pos = sb.pos(); const long long end = sb.end(); while( pos < end ) { Block b( pos, std::min( (long long)hardbs(), end - pos ) ); if( b.end() != end ) b.align_end( hardbs() ); pos = b.end(); int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, scraping, 1, true ); if( retval ) return retval; update_rates(); if( error_size > 0 ) { if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); } if( !update_mapfile( odes_ ) ) return -2; } } show_status( -1, msg, true ); // update at end of pass return 0; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Try to read the damaged areas, one sector at a time. Retry starts at 1, but pass starts at 1 or 2 to resume in the same direction. */ int Rescuebook::copy_errors() { char msgbuf[80] = "Retrying bad sectors... Retry "; const int msglen = std::strlen( msgbuf ); bool resume = current_status() == retrying; const int first_pass = (!resume || unidirectional || current_pass() & 1) ? 1 : 2; // odd:even bool forward = (unidirectional || first_pass == 1) ? !reverse : reverse; for( int pass = first_pass; pass < INT_MAX / 2; ++pass ) { if( max_retries >= 0 && pass - first_pass + 1 > max_retries ) break; first_post = true; snprintf( msgbuf + msglen, ( sizeof msgbuf ) - msglen, "%s %s", format_num3( pass - first_pass + 1 ), forward ? "(forwards)" : "(backwards)" ); const int retval = forward ? fcopy_errors( msgbuf, pass, resume ) : rcopy_errors( msgbuf, pass, resume ); if( retval != -3 ) return retval; resume = false; if( !unidirectional ) forward = !forward; } return 0; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Try to read forwards the damaged areas, one sector at a time. */ int Rescuebook::fcopy_errors( const char * const msg, const int pass, const bool resume ) { long long pos = 0; bool block_found = false; if( resume && domain().includes( current_pos() ) ) { Block b( current_pos(), 1 ); find_chunk( b, Sblock::bad_sector, domain(), hardbs() ); if( b.size() > 0 ) pos = b.pos(); // resume } while( pos >= 0 ) { Block b( pos, hardbs() ); find_chunk( b, Sblock::bad_sector, domain(), hardbs() ); if( b.size() <= 0 ) break; // no more blocks pos = b.end(); block_found = true; int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, retrying, pass, true ); if( retval ) return retval; update_rates(); if( error_size > 0 ) { if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); } if( !update_mapfile( odes_ ) ) return -2; } if( !block_found ) return 0; show_status( -1, msg, true ); // update at end of pass return -3; } /* Return values: 1 error, 0 OK, -1 interrupted, -2 mapfile error. Try to read backwards the damaged areas, one sector at a time. */ int Rescuebook::rcopy_errors( const char * const msg, const int pass, const bool resume ) { long long end = LLONG_MAX; bool block_found = false; if( resume && domain().includes( current_pos() - 1 ) ) { Block b( current_pos() - 1, 1 ); rfind_chunk( b, Sblock::bad_sector, domain(), hardbs() ); if( b.size() > 0 ) end = b.end(); // resume } while( end > 0 ) { Block b( end - hardbs(), hardbs() ); rfind_chunk( b, Sblock::bad_sector, domain(), hardbs() ); if( b.size() <= 0 ) break; // no more blocks end = b.pos(); block_found = true; int copied_size = 0, error_size = 0; const int retval = copy_and_update( b, copied_size, error_size, msg, retrying, pass, false ); if( retval ) return retval; update_rates(); if( error_size > 0 ) { if( reopen_on_error && !reopen_infile() ) return 1; if( pause_on_error > 0 ) do_pause_on_error(); } if( !update_mapfile( odes_ ) ) return -2; } if( !block_found ) return 0; show_status( -1, msg, true ); // update at end of pass return -3; } // Return true if slow read. // bool Rescuebook::update_rates( const bool force ) { if( t0 == 0 ) { t0 = t1 = ts = initial_time(); first_size = last_size = finished_size; rates_updated = true; if( verbosity >= 0 ) { std::fputs( "\n\n\n\n\n\n", stdout ); if( preview_lines > 0 ) for( int i = -2; i < preview_lines; ++i ) std::fputc( '\n', stdout ); } } long long t2 = std::time( 0 ); if( max_read_rate > 0 && finished_size - last_size > max_read_rate && t2 == t1 ) { sleep( 1 ); t2 = std::time( 0 ); } if( t2 < t1 ) // clock jumped back { const long long delta = std::min( t0 - 1, t1 - t2 ); t0 -= delta; ts -= delta; t1 = t2; } const bool force_update = force && t2 <= t1; if( force_update ) t2 = t1 + 1; // force update of e_code if( t2 > t1 ) { if( tp > 0 ) { const long long delta = std::min( t0 - 1, (long long)tp.round() ); t0 -= delta; t1 -= delta; ts -= delta; tp = 0; } if( !force_update || a_rate <= 0 ) a_rate = ( finished_size - first_size ) / ( t2 - t0 ); if( !force_update || c_rate <= 0 ) c_rate = ( finished_size - last_size ) / ( t2 - t1 ); if( !( e_code & 4 ) ) { if( finished_size != last_size ) { last_size = finished_size; if( !force_update ) ts = t2; } else if( !force_update && timeout >= 0 && t2 - ts > timeout && t1 > t0 ) e_code |= 4; } if( !( e_code & 1 ) ) { error_rate = error_sum / ( t2 - t1 ); error_sum = 0; if( max_error_rate >= 0 && error_rate > max_error_rate ) e_code |= 1; } rates_updated = true; if( !force_update ) { t1 = t2; prev_slow = current_slow; current_slow = t1 - t0 > delay_slow && // delay checking slow reads ( ( min_read_rate > 0 && c_rate < min_read_rate ) || ( min_read_rate == 0 && c_rate < a_rate / 10 ) ); if( !current_slow && reset_slow ) slow_reads = 0; return current_slow; } } return false; } 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 || first_post ) { if( verbosity >= 0 ) { if( first_post && !first_read && !rescue_finished() ) std::fputc( '\n', stdout ); // scroll forward after each pass else std::printf( "\r%s%s%s%s%s%s", up, up, up, up, up, up ); if( preview_lines > 0 ) { if( !first_post || first_read ) for( int i = -2; i < preview_lines; ++i ) std::fputs( up, stdout ); std::fputs( "Data preview:\n", stdout ); for( int i = 0; i < preview_lines; ++i ) { if( iobuf_ipos >= 0 ) { const uint8_t * const p = iobuf() + ( 16 * i ); std::printf( "%010llX ", ( iobuf_ipos + ( 16 * i ) ) & 0xFFFFFFFFFFLL ); for( int j = 0; j < 16; ++j ) { std::printf( " %02X", p[j] ); if( j == 7 ) std::fputc( ' ', stdout ); } std::fputs( " ", stdout ); for( int j = 0; j < 16; ++j ) std::fputc( std::isprint( p[j] ) ? p[j] : '.', stdout ); std::fputc( '\n', stdout ); } else if( i == ( preview_lines - 1 ) / 2 ) std::fputs( " No data available \n", stdout ); else std::fputs( " \n", stdout ); } std::fputc( '\n', stdout ); } std::printf( " ipos: %9sB, non-trimmed: %9sB, current rate: %8sB/s\n", format_num( last_ipos ), format_num( non_trimmed_size ), format_num( c_rate, 99999 ) ); std::printf( " opos: %9sB, non-scraped: %9sB, average rate: %8sB/s\n", format_num( last_ipos + offset() ), format_num( non_scraped_size ), format_num( a_rate, 99999 ) ); std::printf( "non-tried: %9sB, bad-sector: %9sB, error rate: %8sB/s\n", format_num( non_tried_size ), format_num( bad_size ), format_num( error_rate, 99999 ) ); std::printf( " rescued: %9sB, bad areas:%11s, run time: %11s\n", format_num( finished_size ), format_num3( bad_areas ), format_time( t1 - t0 ) ); if( t1 - t0 > 1 ) sliding_avg.add_term( c_rate ); const long long s_rate = domain().full() ? 0 : sliding_avg(); // 315_359_999_968_464_000 = seconds in 999_999_999 years const long remaining_time = ( s_rate <= 0 ) ? -1 : std::min( std::min( (long long)LONG_MAX, 315359999968464000LL ), ( non_tried_size + non_trimmed_size + non_scraped_size + ( max_retries ? bad_size : 0 ) + s_rate - 1 ) / s_rate ); std::printf( "pct rescued: %s, read errors:%11s, remaining time: %11s\n", percent_rescued(), format_num3( read_errors ), format_time( remaining_time, remaining_time >= 180 ) ); if( min_read_rate >= -1 ) std::printf( "slow reads:%10s,", format_num3( slow_reads ) ); else std::fputs( " ", stdout ); std::printf( " time since last successful read: %11s\n", format_time( (ts > t0 || finished_size > 0) ? t1 - ts : -1 ) ); if( msg && *msg && !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; } safe_fflush( stdout ); } rate_logger.print_line( t1 - t0, last_ipos, a_rate, c_rate, bad_areas, bad_size ); if( !force && !first_post ) read_logger.print_time( t1 - t0 ); rates_updated = false; first_post = false; first_read = false; } } Rescuebook::Rescuebook( const long long offset, const long long insize, Domain & dom, const Domain * const test_dom, const Mb_options & mb_opts, const Rb_options & rb_opts, const char * const iname, const char * const oname, const char * const mapname, const int cluster, const int hardbs, const bool synchronous ) : Mapbook( offset, insize, dom, mb_opts, mapname, cluster, hardbs, rb_opts.complete_only, true ), Rb_options( rb_opts ), error_rate( 0 ), error_sum( 0 ), sparse_size( sparse ? 0 : -1 ), non_tried_size( 0 ), non_trimmed_size( 0 ), non_scraped_size( 0 ), bad_size( 0 ), finished_size( 0 ), test_domainp( test_dom ), iname_( iname ), oname_( oname ), read_errors( 0 ), slow_reads( 0 ), e_code( 0 ), synchronous_( synchronous ), coe_ipos( -1 ), coe_buf( new uint8_t[hardbs] ), bsd_buf( 0 ), a_rate( 0 ), c_rate( 0 ), first_size( 0 ), last_size( 0 ), iobuf_ipos( -1 ), last_ipos( 0 ), t0( 0 ), t1( 0 ), ts( 0 ), tp( 0 ), oldlen( 0 ), rates_updated( false ), current_slow( false ), prev_slow( false ), sliding_avg( 60 ), first_post( true ), first_read( true ) { if( preview_lines > softbs() / 16 ) preview_lines = softbs() / 16; if( skipbs < 0 ) skipbs = round_up( std::max( insize / 32768, (long long)min_skipbs ), min_skipbs ); const long long csize = insize / 100; if( insize > 0 && skipbs > 0 && max_skipbs == max_max_skipbs && csize < max_skipbs ) max_skipbs = std::max( skipbs, csize ); skipbs = round_up( skipbs, hardbs ); // make multiple of hardbs max_skipbs = round_up( max_skipbs, hardbs ); if( retrim ) for( long index = 0; index < sblocks(); ++index ) { const Sblock & sb = sblock( index ); if( !domain().includes( sb ) ) { if( domain() < sb ) break; else continue; } if( ( sb.status() == sb.non_scraped || sb.status() == sb.bad_sector ) && ( index <= 0 || sblock( index - 1 ).status() == sb.non_tried || sblock( index - 1 ).status() == sb.finished || index + 1 >= sblocks() || sblock( index + 1 ).status() == sb.non_tried || sblock( index + 1 ).status() == sb.finished ) ) change_sblock_status( index, sb.non_trimmed ); } if( try_again ) for( long index = 0; index < sblocks(); ++index ) { const Sblock & sb = sblock( index ); if( !domain().includes( sb ) ) { if( domain() < sb ) break; else continue; } if( sb.status() == sb.non_scraped || sb.status() == sb.non_trimmed ) change_sblock_status( index, sb.non_tried ); } initialize_sizes(); // counts bad_areas if( new_bad_areas_only ) max_bad_areas += bad_areas; } bool Rescuebook::read_bad_sector_data( const int fd ) { if( bsd_buf ) return false; uint8_t * const p = new uint8_t[hardbs()]; bsd_buf = p; const int rd = readblock( fd, p, hardbs() ); return rd == hardbs() && errno == 0; } // Return values: 0 OK, != 0 error. // int Rescuebook::do_rescue( const int ides, const int odes ) { ides_ = ides; odes_ = odes; set_signals(); if( verbosity >= 0 ) { std::fputs( ctrlc_msg, stdout ); if( mapfile_exists() ) { std::fputs( initial_msg, stdout ); if( verbosity >= 3 ) { std::printf( "current position: %9sB, current sector: %7s\n", format_num( current_pos() ), format_num3( current_pos() / hardbs() ) ); if( sblocks() ) std::printf( " last block size: %9sB\n", format_num( sblock( sblocks() - 1 ).size() ) ); } if( domain().pos() > 0 || domain().end() < mapfile_insize() ) std::printf( "(sizes limited to domain from %sB to %sB of %sB)\n", format_num3p( domain().pos(), true ), format_num3p( domain().end(), true ), format_num3p( mapfile_insize(), true ) ); std::printf( "rescued: %sB, tried: %sB, bad-sector: %sB, bad areas: %s\n\n", format_num( finished_size ), format_num( non_trimmed_size + non_scraped_size + bad_size ), format_num( bad_size ), format_num3( bad_areas ) ); std::fputs( "Current status\n", stdout ); } } int retval = 0; update_rates(); // first call // resume a sweeping pass by skipping copying and trimming if( non_tried_size && current_status() != sweeping && !errors_or_timeout() ) retval = copy_non_tried(); if( retval == 0 && non_trimmed_size && current_status() != sweeping && !notrim && !errors_or_timeout() ) retval = trim_errors(); if( retval == 0 && non_tried_size && !nosweep && !errors_or_timeout() ) retval = sweep_non_tried(); if( retval == 0 && non_scraped_size && !noscrape && !errors_or_timeout() ) retval = scrape_errors(); if( retval == 0 && bad_size && max_retries != 0 && !errors_or_timeout() ) retval = copy_errors(); fsync( odes_ ); // prevent early exit if kernel caches writes if( !rates_updated ) update_rates( true ); // force update of e_code show_status( -1, retval ? 0 : "\nFinished", true ); const bool signaled = retval == -1; if( signaled ) retval = 0; if( retval == 0 && errors_or_timeout() ) retval = 1; if( verbosity >= 0 || event_logger.active() ) { if( retval == -2 ) event_logger.echo_msg( "Mapfile error" ); else if( retval == 0 && signaled ) event_logger.echo_msg( "Interrupted by user" ); else { if( e_code & 1 ) { char buf[80]; snprintf( buf, sizeof buf, "Too high error rate reading input file (%sB/s)", format_num( error_rate ) ); event_logger.echo_msg( buf ); } if( e_code & 2 ) event_logger.echo_msg( "Too many bad areas in input file" ); if( e_code & 4 ) event_logger.echo_msg( "Timeout expired" ); if( e_code & 16 ) event_logger.echo_msg( "Too many read errors" ); if( e_code & 32 ) event_logger.echo_msg( "Too many slow reads" ); } if( verbosity >= 0 ) { std::fputc( '\n', stdout ); safe_fflush( stdout ); } } if( retval == -2 ) retval = 1; // mapfile error else { if( retval == 0 && !signaled ) current_status( finished ); if( !extend_outfile_size() ) // sparse or -x option { show_file_error( oname_, "Error extending output file size." ); if( retval == 0 ) retval = 1; } compact_sblock_vector(); if( !update_mapfile( odes_, true ) && retval == 0 ) retval = 1; } if( final_msg().size() ) show_final_msg( final_msg().c_str(), final_errno() ); if( close( odes_ ) != 0 ) { show_file_error( oname_, "Error closing outfile", errno ); if( retval == 0 ) retval = 1; } event_logger.print_eor( t1 - t0, finished_size, percent_rescued(), current_pos(), status_name( current_status() ), format_num( a_rate, 99999 ), read_errors ); if( !event_logger.close_file() ) show_file_error( event_logger.filename(), "warning: error closing the events logging file." ); if( !rate_logger.close_file() ) show_file_error( rate_logger.filename(), "warning: error closing the rates logging file." ); if( !read_logger.close_file() ) show_file_error( read_logger.filename(), "warning: error closing the reads logging file." ); if( retval ) return retval; // errors have priority over signals if( signaled ) return signaled_exit(); return 0; } gddrescue-1.30/rescuebook.h000066400000000000000000000217371512716454500157400ustar00rootroot00000000000000/* GNU ddrescue - Data recovery tool Copyright (C) 2004-2026 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 2 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 Sliding_average // Calculates the average of the last N terms { unsigned long long sum; unsigned index; // one of index or data.size() contains N std::vector< unsigned long long > data; public: explicit Sliding_average( const unsigned terms ) : sum( 0 ), index( terms ) { data.reserve( terms ); } // void reset() // { sum = 0; if( index < data.size() ) index = data.size(); data.clear(); } void add_term( const unsigned long long term ) { if( index < data.size() ) { sum -= data[index]; data[index++] = term; } else if( index > data.size() ) data.push_back( term ); sum += term; if( index == data.size() ) index = 0; } unsigned long long operator()() const { return data.size() ? sum / data.size() : 0; } }; struct Rb_options { enum { min_skipbs = 65536 }; const long long max_max_skipbs; long long max_error_rate; long long min_outfile_size; long long max_read_rate; long long min_read_rate; // -2 = not set, -1 = reset long long skipbs; // initial size to skip on read error long long max_skipbs; // maximum size to skip on read error std::vector< int > errno_vector; // treat these values as non-fatal unsigned long max_bad_areas; unsigned long max_read_errors; unsigned long max_slow_reads; int cpass_bitset; // 1 << ( pass - 1 ) for passes 1 to 4 int delay_slow; int max_retries; int o_direct_in; // O_DIRECT or 0 Rational pause_on_error; int pause_on_pass; int preview_lines; // preview lines to show. 0 = disable int timeout; bool compare_before_write; bool complete_only; bool new_bad_areas_only; bool noscrape; bool nosweep; bool notrim; bool reopen_on_error; bool reset_slow; bool retrim; bool reverse; bool same_file; bool simulated_poe; bool sparse; bool try_again; bool unidirectional; bool check_on_error; Rb_options() : max_max_skipbs( 1LL << 60 ), max_error_rate( -1 ), min_outfile_size( -1 ), max_read_rate( 0 ), min_read_rate( -2 ), skipbs( -1 ), max_skipbs( max_max_skipbs ), max_bad_areas( ULONG_MAX ), max_read_errors( ULONG_MAX ), max_slow_reads( ULONG_MAX ), cpass_bitset( 15 ), delay_slow( 30 ), max_retries( 0 ), o_direct_in( 0 ), pause_on_error( 0 ), pause_on_pass( 0 ), preview_lines( 0 ), timeout( -1 ), compare_before_write( false ), complete_only( false ), new_bad_areas_only( false ), noscrape( false ), nosweep( false ), notrim( false ), reopen_on_error( false ), reset_slow( false ), retrim( false ), reverse( false ), same_file( false ), simulated_poe( false ), sparse( false ), try_again( false ), unidirectional( false ), check_on_error( false ) {} bool operator==( const Rb_options & o ) const { return ( max_error_rate == o.max_error_rate && min_outfile_size == o.min_outfile_size && max_read_rate == o.max_read_rate && min_read_rate == o.min_read_rate && skipbs == o.skipbs && max_skipbs == o.max_skipbs && errno_vector == o.errno_vector && max_bad_areas == o.max_bad_areas && max_read_errors == o.max_read_errors && max_slow_reads == o.max_slow_reads && cpass_bitset == o.cpass_bitset && delay_slow == o.delay_slow && max_retries == o.max_retries && o_direct_in == o.o_direct_in && pause_on_error == o.pause_on_error && pause_on_pass == o.pause_on_pass && preview_lines == o.preview_lines && timeout == o.timeout && compare_before_write == o.compare_before_write && complete_only == o.complete_only && new_bad_areas_only == o.new_bad_areas_only && noscrape == o.noscrape && nosweep == o.nosweep && notrim == o.notrim && reopen_on_error == o.reopen_on_error && reset_slow == o.reset_slow && retrim == o.retrim && reverse == o.reverse && same_file == o.same_file && simulated_poe == o.simulated_poe && sparse == o.sparse && try_again == o.try_again && unidirectional == o.unidirectional && check_on_error == o.check_on_error ); } bool operator!=( const Rb_options & o ) const { return !( *this == o ); } }; class Rescuebook : public Mapbook, public Rb_options { long long error_rate, error_sum; long long sparse_size; // end position of pending writes long long non_tried_size, non_trimmed_size, non_scraped_size; long long bad_size, finished_size; const Domain * const test_domainp; // good/bad map for test mode const char * const iname_, * const oname_; unsigned long bad_areas; // bad areas found so far unsigned long read_errors, slow_reads; int ides_, odes_; // input and output file descriptors int e_code; // error code for errors_or_timeout // 1 rate, 2 bad_areas, 4 timeout, // 8 other (explained in final_msg), // 16 read_errors, 32 slow_reads const bool synchronous_; long long coe_ipos; // pos of last good sector read, or -1 uint8_t * const coe_buf; // copy of last good sector read const uint8_t * bsd_buf; // bad_sector_data buffer // variables for update_rates long long a_rate, c_rate, first_size, last_size; long long iobuf_ipos; // last pos read in iobuf, or -1 long long last_ipos; long long t0, t1, ts; // start, current, last successful Rational tp; // cumulated pause_on_error int oldlen; bool rates_updated, current_slow, prev_slow; Sliding_average sliding_avg; // variables for show_status bool first_post; // first read in current pass bool first_read; // first read overall void adjust_copied_size( int & copied_size ) const { if( bsd_buf ) for( int i = 0; i + hardbs() <= copied_size; i += hardbs() ) if( std::memcmp( iobuf() + i, bsd_buf, hardbs() ) == 0 ) { copied_size = i; errno = EIO; break; } } void change_chunk_status( const Block & b, const Sblock::Status st ); void do_pause_on_error(); bool extend_outfile_size(); int copy_block( const Block & b, int & copied_size, int & error_size ); void initialize_sizes(); bool errors_or_timeout() { if( bad_areas > max_bad_areas ) e_code |= 2; return ( e_code != 0 ); } const char * percent_rescued() const { return format_percentage( finished_size, domain().in_size(), 3, 2, false ); } bool rescue_finished() const { return finished_size >= domain().in_size(); } int copy_and_update( const Block & b, int & copied_size, int & error_size, const char * const msg, const Status curr_st, const int curr_pass, const bool forward, const Sblock::Status st = Sblock::bad_sector ); bool reopen_infile(); int copy_non_tried(); int fcopy_non_tried( const char * const msg, const int pass, const bool resume ); int rcopy_non_tried( const char * const msg, const int pass, const bool resume ); int trim_errors( const char * msg = 0 ); int sweep_non_tried(); int scrape_errors(); int copy_errors(); int fcopy_errors( const char * const msg, const int pass, const bool resume ); int rcopy_errors( const char * const msg, const int pass, const bool resume ); bool update_rates( const bool force = false ); void show_status( const long long ipos, const char * const msg = 0, const bool force = false ); int copy_command( const char * const command ); int status_command( const char * const command ) const; public: Rescuebook( const long long offset, const long long insize, Domain & dom, const Domain * const test_dom, const Mb_options & mb_opts, const Rb_options & rb_opts, const char * const iname, const char * const oname, const char * const mapname, const int cluster, const int hardbs, const bool synchronous ); ~Rescuebook() { delete[] coe_buf; if( bsd_buf ) delete[] bsd_buf; } bool read_bad_sector_data( const int fd ); int do_commands( const int ides, const int odes ); int do_rescue( const int ides, const int odes ); }; const char * const disap_msg = "Input file disappeared"; // defined in main.cc void show_final_msg( const char * const msg, const int errcode ); gddrescue-1.30/testsuite/000077500000000000000000000000001512716454500154455ustar00rootroot00000000000000gddrescue-1.30/testsuite/check.sh000077500000000000000000000774341512716454500171000ustar00rootroot00000000000000#! /bin/sh # check script for GNU ddrescue - Data recovery tool # Copyright (C) 2009-2026 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 [ ! -f "${DDRESCUE}" ] || [ ! -x "${DDRESCUE}" ] ; then echo "${DDRESCUE}: cannot execute" exit 1 fi if [ ! -f "${DDRESCUELOG}" ] || [ ! -x "${DDRESCUELOG}" ] ; then echo "${DDRESCUELOG}: cannot execute" exit 1 fi [ -e "${DDRESCUE}" ] 2> /dev/null || { echo "$0: a POSIX shell is required to run the tests" echo "Try bash -c \"$0 $1 $2\"" exit 1 } if [ -d tmp ] ; then rm -rf tmp ; fi mkdir tmp cd "${objdir}"/tmp || framework_failure fox="${testdir}"/fox in="${testdir}"/test.txt in1="${testdir}"/test1.txt in2="${testdir}"/test2.txt in3="${testdir}"/test3.txt in4="${testdir}"/test4.txt in5="${testdir}"/test5.txt blank="${testdir}"/mapfile_blank map1="${testdir}"/mapfile1 map2="${testdir}"/mapfile2 map2i="${testdir}"/mapfile2i map2ui="${testdir}"/mapfile2ui map3="${testdir}"/mapfile3 map4="${testdir}"/mapfile4 map5="${testdir}"/mapfile5 map6="${testdir}"/mapfile6 map6j="${testdir}"/mapfile6j fail=0 test_failed() { fail=1 ; printf " $1" ; [ -z "$2" ] || printf "($2)" ; } # Description of test files for ddrescue: # fox : "The quick brown fox jumps over the lazy dog.\n" # test.txt : 4 copies of the GPLv2, alternating LF and CRLF line ends # test[1-5].txt: partial copies of test.txt as recorded in mapfile[1-5] # mapfile1 : Alternating finished/non-tried blocks of 0x800 bytes each # mapfile2 : mapfile1 inverted (non-tried/finished) # mapfile2i : mapfile2 without the non-tried blocks # mapfile2ui : mapfile2 unordered and without the non-tried blocks # mapfile3 : Alternating finished/non-tried blocks of 0x800/0x1000 bytes # mapfile[45] : Triphasic complement to mapfile3 # mapfile6 : mapfile1 with non-finished subsectors smaller than 512 bytes # mapfile6j : mapfile6 with the subsectors joined to the right blocks # mapfile_blank: non-tried mapfile cut to the lenght of test.txt (72602) printf "testing ddrescue-%s..." "$2" "${DDRESCUE}" -q "${in}" [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q "${in}" out mapfile extra [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q "${in}" "${in}" mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q "${in}" out "${in}" [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q "${in}".bak out "${in}" [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q "${in}" out out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q "${in}" out.bak out [ $? = 1 ] || test_failed $LINENO for i in 1ki 1K 1BB 1Bi 1Bk 1Bs 1iB 1ii 1ik 1is 1kk 1sB 1si 1sk 1ss ; do "${DDRESCUE}" -q -a $i "${in}" out [ $? = 1 ] || test_failed $LINENO $i done "${DDRESCUE}" -q -F- "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -Fi "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -F- --ask "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -F- --same-file "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -G --ask "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -G "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -F- -G "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -G --command-mode "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -H "${map2i}" "${in}" out mapfile [ $? = 2 ] || test_failed $LINENO "${DDRESCUE}" -q -K "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -K, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -K0, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -K0,65535 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -K0,65536, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -i 0, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -i -1 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -m "${map1}" -m "${map2}" "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q -m "${map2i}" "${in}" out mapfile [ $? = 2 ] || test_failed $LINENO "${DDRESCUE}" -q -w "${in}" out mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=1, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=-1 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=1- "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=5 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=1,5 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=1-5 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --cpass=3-2 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --continue-on-errno=-1 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --continue-on-errno=0 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --continue-on-errno=5,0 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --continue-on-errno=5, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --continue-on-errno=EIO "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --log-events=- "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=-2 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=30, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=,4s "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=3,4s "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=30,10 "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=30,60, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=30,60s, "${in}" out [ $? = 1 ] || test_failed $LINENO "${DDRESCUE}" -q --same-file -t "${in}" out [ $? = 1 ] || test_failed $LINENO rm -f out mapfile || framework_failure "${DDRESCUE}" -q -t -p -J -b1024 -i15kB "${in}" out mapfile || test_failed $LINENO "${DDRESCUE}" -q -A -y -e0 -f -n -s15k "${in}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out mapfile || framework_failure "${DDRESCUE}" -q -R -i15_000 -a 1ks -E 1Kis "${in}" out mapfile || test_failed $LINENO "${DDRESCUE}" -q -R -s15000 --cpass=0 "${in}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out mapfile || framework_failure "${DDRESCUE}" -q -s8000 -x0 "${in}" out mapfile || test_failed $LINENO sizei=`cat "${in}" | wc -c` || test_failed $LINENO sizeo=`cat out | wc -c` || test_failed $LINENO [ "${sizei}" = "${sizeo}" ] || { printf "%s != %s\n" "${sizei}" "${sizeo}" ; test_failed $LINENO ; } cmp -s "${in}" out && test_failed $LINENO "${DDRESCUE}" -q "${in}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure "${DDRESCUE}" -q -F+ -o15000 -c143 "${in}" out2 mapfile || test_failed $LINENO "${DDRESCUE}" -q -R -S -i15000 -o0 -u -Z1Mis out2 out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO printf "garbage" >> out || framework_failure "${DDRESCUE}" -q -N -R -t -i15000 -o0 --cpass=1-4 --pause-on-pass=0 out2 out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out2 || framework_failure rm -f out || framework_failure "${DDRESCUE}" -q -O -r1 -H - --pause-on-error=s0 "${in}" out < "${map1}" || test_failed $LINENO cmp "${in1}" out || test_failed $LINENO "${DDRESCUE}" -q -L -K0 -c1 -H "${map2ui}" --pause-on-error=0 "${in2}" out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out mapfile || framework_failure "${DDRESCUE}" -q -c1 -H "${map3}" --delay-slow=0 "${in3}" out mapfile || test_failed $LINENO "${DDRESCUE}" -q -c1 -M -H "${map4}" "${in4}" out mapfile || test_failed $LINENO "${DDRESCUE}" -q -c1 -A -M -N --cpass=0 -H "${map5}" "${in5}" out mapfile || test_failed $LINENO cmp -s "${in}" out && test_failed $LINENO "${DDRESCUE}" -q -c1 -n -N -H "${map5}" "${in5}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure "${DDRESCUE}" -q -X0 -m - "${in}" out < "${map1}" || test_failed $LINENO cmp "${in1}" out || test_failed $LINENO "${DDRESCUE}" -q -X0 -L -K0,64Ki -m "${map2i}" "${in2}" out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure "${DDRESCUE}" -q -R -B -K,64KiB -m "${map2}" "${in}" out || test_failed $LINENO cmp "${in2}" out || test_failed $LINENO "${DDRESCUE}" -q -R -K65536,65536 -m "${map1}" "${in1}" out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure "${DDRESCUE}" -q --mapfile-interval=5m -m "${map5}" "${in5}" out || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=5,5 -m "${map4}" "${in4}" out || test_failed $LINENO "${DDRESCUE}" -q --mapfile-interval=,5s -m "${map3}" "${in3}" out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure cp "${map1}" mapfile || framework_failure "${DDRESCUE}" -q -I --cpass=1,2 "${in2}" out mapfile || test_failed $LINENO cp "${map2}" mapfile || framework_failure "${DDRESCUE}" -q -I "${in}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure cp "${map1}" mapfile || framework_failure "${DDRESCUE}" -q -R --cpass=1,2-4 "${in2}" out mapfile || test_failed $LINENO cp "${map2}" mapfile || framework_failure "${DDRESCUE}" -q -R -C "${in1}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO # test joining non-finished subsectors rm -f out || framework_failure cp "${map2}" mapfile || framework_failure "${DDRESCUE}" -q --cpass=1-2,4 "${in}" out mapfile || test_failed $LINENO cmp "${in1}" out || test_failed $LINENO cp "${map6}" mapfile || framework_failure "${DDRESCUE}" -q -s0x800 "${in2}" out mapfile || test_failed $LINENO "${DDRESCUELOG}" -p "${map6j}" mapfile || test_failed $LINENO cmp "${in1}" out || test_failed $LINENO "${DDRESCUE}" -q "${in2}" out mapfile || test_failed $LINENO cmp -s "${in}" out && test_failed $LINENO "${DDRESCUELOG}" -d mapfile && test_failed $LINENO "${DDRESCUE}" -q -r1 "${in2}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO cp "${in1}" out || framework_failure cp "${map6}" mapfile || framework_failure "${DDRESCUE}" -q -b0x80 "${in2}" out mapfile || test_failed $LINENO cmp -s "${in}" out && test_failed $LINENO "${DDRESCUELOG}" -d mapfile && test_failed $LINENO "${DDRESCUE}" -q -b0200 -r1 "${in2}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO cp "${in1}" out || framework_failure cp "${map6}" mapfile || framework_failure "${DDRESCUE}" -q -b4096 -s0x800 "${in2}" out mapfile || test_failed $LINENO "${DDRESCUELOG}" -P "${map1}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -q -p "${map1}" mapfile && test_failed $LINENO cmp "${in1}" out || test_failed $LINENO "${DDRESCUE}" -q -b4096 "${in2}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO rm -f out || framework_failure for i in 0 8000 16000 24000 32000 40000 48000 56000 64000 72000 ; do "${DDRESCUE}" -q -i$i -s4000 -m "${map1}" "${in}" out || test_failed $LINENO $i done cmp -s "${in}" out && test_failed $LINENO for i in 4000 12000 20000 28000 36000 44000 52000 60000 68000 ; do "${DDRESCUE}" -q -i$i -s4000 -m "${map1}" "${in}" out || test_failed $LINENO $i done cmp "${in1}" out || test_failed $LINENO for i in 0 8000 16000 24000 32000 40000 48000 56000 64000 72000 ; do "${DDRESCUE}" -q -i$i -s4000 -m "${map2}" "${in2}" out || test_failed $LINENO $i done cmp -s "${in}" out && test_failed $LINENO for i in 4000 12000 20000 28000 36000 44000 52000 60000 68000 ; do "${DDRESCUE}" -q -i$i -s4000 -m "${map2}" "${in2}" out || test_failed $LINENO $i done cmp "${in}" out || test_failed $LINENO rm -f mapfile || framework_failure cp "${in1}" out || framework_failure "${DDRESCUE}" -q -G "${in}" out mapfile || test_failed $LINENO "${DDRESCUE}" -q "${in2}" out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f mapfile || framework_failure cp "${in}" copy || framework_failure printf "garbage" >> copy || framework_failure cp "${in2}" out || framework_failure "${DDRESCUE}" -q -t -x 72602 "${in1}" copy || test_failed $LINENO "${DDRESCUE}" -q -G "${in}" out mapfile || test_failed $LINENO "${DDRESCUE}" -q -R -T2_160.500_0m copy out mapfile || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUE}" -q --same-file out out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUE}" -q -t "${in}" out || test_failed $LINENO "${DDRESCUE}" -q --same-file -o 72602 out out || test_failed $LINENO cat "${in}" "${in}" | cmp out - || test_failed $LINENO rm -f out || framework_failure "${DDRESCUE}" -q --continue-on-errno=5,1,6 "${in}" out || test_failed $LINENO "${DDRESCUE}" -q --same-file -o 145204 -S out out || test_failed $LINENO "${DDRESCUE}" -q --same-file -i 145204 -o 72602 out out || test_failed $LINENO cat "${in}" "${in}" "${in}" | cmp out - || test_failed $LINENO rm -f out || framework_failure printf "c 0 72602\nq\n" | "${DDRESCUE}" -m "${map1}" --command-mode "${in}" out \ > /dev/null || test_failed $LINENO cmp "${in1}" out || test_failed $LINENO printf "c 0 72602\nu\n" | "${DDRESCUE}" -m "${map2}" --command-mode "${in2}" out \ > /dev/null || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure cp "${map1}" mapfile || framework_failure printf "c 0 72602\ns0 1\n" | "${DDRESCUE}" --command-mode "${in}" out mapfile \ > /dev/null || test_failed $LINENO cmp "${in2}" out || test_failed $LINENO cp "${map2}" mapfile || framework_failure printf "c 0 72602\n" | "${DDRESCUE}" -C --command-mode "${in1}" out mapfile \ > /dev/null || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO rm -f out mapfile || framework_failure printf "c 0 0x800\nc 0x1800 0x800\nc 0x3000 0x800\nc 0x4800 0x800\n\ c 0x6000 0x800\nc 0x7800 0x800\nc 0x9000 0x800\nc 0xA800 0x800\n\ c 0xC000 0x800\nc 0xD800 0x800\nc 0xF000 0x800\nc 0x10800 0x800\n" | \ "${DDRESCUE}" --command-mode "${in}" out mapfile > /dev/null || test_failed $LINENO cmp "${in3}" out || test_failed $LINENO printf "c 0x800 0x800\nc 0x2000 0x800\nc 0x3800 0x800\nc 0x5000 0x800\n\ c 0x6800 0x800\nc 0x8000 0x800\nc 0x9800 0x800\nc 0xB000 0x800\n\ c 0xC800 0x800\nc 0xE000 0x800\nc 0xF800 0x800\nc 0x11000 0x800\n" | \ "${DDRESCUE}" -C --command-mode "${in4}" out mapfile > /dev/null || test_failed $LINENO printf "c 0 72602\nf\n" | "${DDRESCUE}" --command-mode "${in5}" out mapfile \ > /dev/null || test_failed $LINENO cmp "${in}" out || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUE}" -q "${in}" out --compare-before-write || test_failed $LINENO cmp "${in}" out || test_failed $LINENO cp "${in2}" out || framework_failure "${DDRESCUE}" -q "${in}" out --compare-before-write || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure "${DDRESCUE}" -q "${in}" out --compare-before-write || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure # aligned read "${DDRESCUE}" -q -i4s -s1s -o0 "${in}" bsd || test_failed $LINENO "${DDRESCUE}" -q "${in}" out --bad-sector-data=bsd || test_failed $LINENO cmp -s "${in}" out && test_failed $LINENO "${DDRESCUE}" -q -i4s -s1s "${in}" out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO rm -f out || framework_failure # unaligned read "${DDRESCUE}" -q -s256 "${in}" out || test_failed $LINENO "${DDRESCUE}" -q -i256 "${in}" out --bad-sector-data=bsd || test_failed $LINENO rm -f bsd || framework_failure cmp -s "${in}" out && test_failed $LINENO "${DDRESCUE}" -q -i4s -s1s "${in}" out || test_failed $LINENO cmp "${in}" out || test_failed $LINENO printf "\ntesting ddrescuelog-%s..." "$2" "${DDRESCUELOG}" -q mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -q -d [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -q -l+l "${map1}" [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -q -t -d mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -q -m "${map2i}" -t mapfile [ $? = 2 ] || test_failed $LINENO "${DDRESCUELOG}" -q --shift -i20 mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -a '?,+' -i3072 - < "${map1}" > mapfile "${DDRESCUELOG}" -D - < mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -D mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -a '?,+' -i2048 -s1024 mapfile > mapfile2 "${DDRESCUELOG}" -d - < mapfile2 || test_failed $LINENO "${DDRESCUELOG}" -d mapfile2 || test_failed $LINENO [ ! -e mapfile2 ] || test_failed $LINENO # testing --create-mapfile and --list-blocks "${DDRESCUELOG}" -b2048 -l+ - < "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" -b2048 -c - < out > mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l+ mapfile > copy || test_failed $LINENO cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -q -p "${map1}" mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -P "${map1}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -s72602 -f '-c?+' mapfile < out || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" - < mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -f '-c?+' mapfile < out || test_failed $LINENO "${DDRESCUELOG}" -s72_602 -p "${map2}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -q -s72603 -p "${map2}" mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -l+ -Flist - < "${map1}" | "${DDRESCUELOG}" '-c+?' out1 || test_failed $LINENO "${DDRESCUELOG}" -l+ -Fbitmap-le - < "${map1}" | \ "${DDRESCUELOG}" '-c+?' -Fbitmap-le out2 || test_failed $LINENO "${DDRESCUELOG}" -p out1 out2 || test_failed $LINENO "${DDRESCUELOG}" -l+ -Fbitmap-be - < "${map1}" | \ "${DDRESCUELOG}" '-c+?' -Fbitmap-be - > out2 || test_failed $LINENO "${DDRESCUELOG}" -p out1 out2 || test_failed $LINENO "${DDRESCUELOG}" -l+ -Fbitmap -o1s - < "${map1}" | \ "${DDRESCUELOG}" '-c+?' -Fbitmap -i1s -o0 - > out2 || test_failed $LINENO "${DDRESCUELOG}" -P out1 out2 || test_failed $LINENO "${DDRESCUELOG}" -C out2 > out3 || test_failed $LINENO "${DDRESCUELOG}" -p out1 out3 || test_failed $LINENO "${DDRESCUELOG}" -l+ -Fbitmap -b8 - < "${map1}" | \ "${DDRESCUELOG}" '-c+?' -Fbitmap -b8 - > out2 || test_failed $LINENO "${DDRESCUELOG}" -P "${map1}" out2 || test_failed $LINENO rm -f out1 out2 out3 || framework_failure printf "10\n12\n14\n16\n" | "${DDRESCUELOG}" -b2048 -f '-c+?' mapfile || test_failed $LINENO "${DDRESCUELOG}" -q -p mapfile "${map1}" [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -q -i0x5000 -p mapfile "${map1}" [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -i0x5000 -s0x3800 -p mapfile "${map1}" || test_failed $LINENO "${DDRESCUELOG}" -C "${map2i}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -C "${map2ui}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" mapfile || test_failed $LINENO cp "${map1}" mapfile || framework_failure "${DDRESCUELOG}" -i1024 -s2048 -d mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -i1024 -s1024 -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -q -i1024 -s1024 -d mapfile [ $? = 1 ] || test_failed $LINENO cp "${map2}" mapfile || framework_failure "${DDRESCUELOG}" -m "${map1}" -D mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -L -m - -D mapfile < "${map2i}" || test_failed $LINENO "${DDRESCUELOG}" -i1024 -s2048 -d mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -i2048 -s2048 -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l+ "${map1}" > out || test_failed $LINENO printf "0\n2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n22\n24\n26\n28\n30\n32\n34\n" > copy || framework_failure cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -b2048 '-l?-' "${map1}" > out || test_failed $LINENO printf "1\n3\n5\n7\n9\n11\n13\n15\n17\n19\n21\n23\n25\n27\n29\n31\n33\n35\n" > copy || framework_failure cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l+ -i0x1800 -o0 -s0x4000 "${map1}" > out || test_failed $LINENO printf "1\n3\n5\n7\n" > copy || framework_failure cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -n "${map2}" > mapfile || framework_failure "${DDRESCUELOG}" -b2048 -l+ mapfile > out || test_failed $LINENO printf "0\n2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n22\n24\n26\n28\n30\n32\n34\n" > copy || framework_failure cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -b2048 '-l?-' mapfile > out || test_failed $LINENO printf "1\n3\n5\n7\n9\n11\n13\n15\n17\n19\n21\n23\n25\n27\n29\n31\n33\n35\n" > copy || framework_failure cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l+ -i2048 -o0 -s0x4000 mapfile > out || test_failed $LINENO printf "1\n3\n5\n7\n" > copy || framework_failure cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -q -P "${map2i}" - < "${map2}" [ $? = 2 ] || test_failed $LINENO "${DDRESCUELOG}" -L -P "${map2i}" "${map2}" || test_failed $LINENO "${DDRESCUELOG}" -L -P "${map2ui}" "${map2}" || test_failed $LINENO # test XOR for i in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do for j in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do "${DDRESCUELOG}" -x "$j" "$i" > out || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -x "$i" "$j" > copy || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -P out copy || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -x "$j" out > copy || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -P "$i" copy || test_failed $LINENO "$i $j" done done "${DDRESCUELOG}" -x "${map1}" - < "${map2}" > out || test_failed $LINENO "${DDRESCUELOG}" -x "${map2}" "${map1}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -d out || test_failed $LINENO "${DDRESCUELOG}" -d copy || test_failed $LINENO "${DDRESCUELOG}" -x "${map1}" "${blank}" > out || test_failed $LINENO "${DDRESCUELOG}" -x "${blank}" "${map1}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -p out "${map1}" || test_failed $LINENO "${DDRESCUELOG}" -p "${map1}" copy || test_failed $LINENO "${DDRESCUELOG}" -x "${map2}" "${map2}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -x "${map1}" "${map1}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l+ "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l- mapfile > copy || test_failed $LINENO cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -b2048 -i0x2000 -s0x2800 -l+ "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" -i0x1800 -s0x3800 -x "${map1}" "${map1}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l- mapfile > copy || test_failed $LINENO cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -x "${map3}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -x "${map4}" "${map3}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -x "${map3}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -x "${map5}" "${map3}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -x "${map4}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -x "${map5}" "${map4}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -x "${map3}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -x out "${map5}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -x "${map3}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -x out "${map4}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -x "${map4}" "${map3}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -x out "${map5}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -x "${map4}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -x out "${map3}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -x "${map5}" "${map3}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -x out "${map4}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -x "${map5}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -x out "${map3}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO # test AND for i in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do for j in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do "${DDRESCUELOG}" -y "$j" "$i" > out || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -y "$i" "$j" > copy || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -P out copy || test_failed $LINENO "$i $j" done done "${DDRESCUELOG}" -b2048 -l+ "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" -y "${map1}" - < "${map2}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 '-l?' mapfile > copy || test_failed $LINENO cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -y "${map2}" "${map1}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l- mapfile > copy || test_failed $LINENO cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -b2048 -i0x2000 -s0x2800 -l+ "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" -i0x1800 -s0x3800 -y "${map2}" "${map1}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -b2048 -l- mapfile > copy || test_failed $LINENO cmp out copy || test_failed $LINENO "${DDRESCUELOG}" -y "${map3}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" out || test_failed $LINENO "${DDRESCUELOG}" -y "${map3}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" out || test_failed $LINENO "${DDRESCUELOG}" -y "${map4}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -P "${blank}" out || test_failed $LINENO "${DDRESCUELOG}" -i0x2000 -s0x2800 -z "${map2}" "${map1}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -D mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -i0x1C00 -s0x2C00 -D mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -i0x2000 -s0x2C00 -D mapfile [ $? = 1 ] || test_failed $LINENO "${DDRESCUELOG}" -i0x2000 -s0x2800 -d mapfile || test_failed $LINENO # test OR for i in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do for j in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do "${DDRESCUELOG}" -z "$j" "$i" > out || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -z "$i" "$j" > copy || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -P out copy || test_failed $LINENO "$i $j" done done "${DDRESCUELOG}" -z "${map1}" - < "${map2}" > out || test_failed $LINENO "${DDRESCUELOG}" -z "${map2}" "${map1}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -d out || test_failed $LINENO "${DDRESCUELOG}" -d copy || test_failed $LINENO "${DDRESCUELOG}" -z "${map1}" "${blank}" > out || test_failed $LINENO "${DDRESCUELOG}" -z "${blank}" "${map1}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -p out "${map1}" || test_failed $LINENO "${DDRESCUELOG}" -p "${map1}" copy || test_failed $LINENO "${DDRESCUELOG}" -z "${map3}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -z "${map4}" "${map3}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -z "${map3}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -z "${map5}" "${map3}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -z "${map4}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -z "${map5}" "${map4}" > copy || test_failed $LINENO "${DDRESCUELOG}" -p out copy || test_failed $LINENO "${DDRESCUELOG}" -z "${map3}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -z out "${map5}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -z "${map3}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -z out "${map4}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -z "${map4}" "${map3}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -z out "${map5}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -z "${map4}" "${map5}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -z out "${map3}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -z "${map5}" "${map3}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -z out "${map4}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -z "${map5}" "${map4}" > out || test_failed $LINENO "${DDRESCUELOG}" -D out && test_failed $LINENO "${DDRESCUELOG}" -z out "${map3}" > mapfile || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO # test ( a && b ) == !( !a || !b ) for i in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do for j in "${map1}" "${map2}" "${map3}" "${map4}" "${map5}" ; do "${DDRESCUELOG}" -n "$i" > na || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -n "$j" > nb || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -z nb na > out || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -n out > copy || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -y "$j" "$i" > out || test_failed $LINENO "$i $j" "${DDRESCUELOG}" -P out copy || test_failed $LINENO "$i $j" done done "${DDRESCUELOG}" --shift -o0x800 -s0x1139A "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" out || test_failed $LINENO "${DDRESCUELOG}" --shift -o0x400 "${map1}" > out || test_failed $LINENO "${DDRESCUELOG}" --shift -o0x400 -s0x11_79A out > copy || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" copy || test_failed $LINENO "${DDRESCUELOG}" --shift -o0x400 "${map2}" > out || test_failed $LINENO "${DDRESCUELOG}" --shift -i0x400 -o0 out > copy || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" copy || test_failed $LINENO "${DDRESCUELOG}" --shift -o0x900 "${map1}" > copy || test_failed $LINENO "${DDRESCUELOG}" --shift -i0x300 -o0 copy > out || test_failed $LINENO "${DDRESCUELOG}" --shift -i0x600 -o0 out > copy || test_failed $LINENO "${DDRESCUELOG}" -p "${map1}" copy || test_failed $LINENO "${DDRESCUELOG}" --shift -i0x800 -o0 "${map2}" > copy || test_failed $LINENO "${DDRESCUELOG}" --shift -o0x488 copy > out || test_failed $LINENO "${DDRESCUELOG}" --shift -o0x378 out > copy || test_failed $LINENO "${DDRESCUELOG}" -p "${map2}" copy || test_failed $LINENO printf "\ntesting combined rescue..." rm -f mapfile || framework_failure "${DDRESCUE}" -q "${in}" out mapfile # rescue partition "${DDRESCUELOG}" --shift -o45 mapfile > shifted_mapfile "${DDRESCUE}" -q --same-file -o45 -s72602 --reverse out out "${DDRESCUE}" -q -C "${fox}" out shifted_mapfile # rescue rest of drive cat "${fox}" "${in}" | cmp out - || test_failed $LINENO "${DDRESCUELOG}" -d mapfile || test_failed $LINENO "${DDRESCUELOG}" -d shifted_mapfile || test_failed $LINENO echo if [ ${fail} = 0 ] ; then echo "tests completed successfully." cd "${objdir}" && rm -r tmp else echo "tests failed." fi exit ${fail} gddrescue-1.30/testsuite/fox000066400000000000000000000000551512716454500161640ustar00rootroot00000000000000The quick brown fox jumps over the lazy dog. gddrescue-1.30/testsuite/mapfile1000066400000000000000000000020241512716454500170640ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # 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 0x00000800 ? 0x00009000 0x00000800 + 0x00009800 0x00000800 ? 0x0000A000 0x00000800 + 0x0000A800 0x00000800 ? 0x0000B000 0x00000800 + 0x0000B800 0x00000800 ? 0x0000C000 0x00000800 + 0x0000C800 0x00000800 ? 0x0000D000 0x00000800 + 0x0000D800 0x00000800 ? 0x0000E000 0x00000800 + 0x0000E800 0x00000800 ? 0x0000F000 0x00000800 + 0x0000F800 0x00000800 ? 0x00010000 0x00000800 + 0x00010800 0x00000800 ? 0x00011000 0x00000800 + 0x00011800 0x0000039A ? gddrescue-1.30/testsuite/mapfile2000066400000000000000000000020241512716454500170650ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # 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 0x00000800 + 0x00009000 0x00000800 ? 0x00009800 0x00000800 + 0x0000A000 0x00000800 ? 0x0000A800 0x00000800 + 0x0000B000 0x00000800 ? 0x0000B800 0x00000800 + 0x0000C000 0x00000800 ? 0x0000C800 0x00000800 + 0x0000D000 0x00000800 ? 0x0000D800 0x00000800 + 0x0000E000 0x00000800 ? 0x0000E800 0x00000800 + 0x0000F000 0x00000800 ? 0x0000F800 0x00000800 + 0x00010000 0x00000800 ? 0x00010800 0x00000800 + 0x00011000 0x00000800 ? 0x00011800 0x0000039A + gddrescue-1.30/testsuite/mapfile2i000066400000000000000000000011001512716454500172300ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000800 0x00000800 + 0x00001800 0x00000800 + 0x00002800 0x00000800 + 0x00003800 0x00000800 + 0x00004800 0x00000800 + 0x00005800 0x00000800 + 0x00006800 0x00000800 + 0x00007800 0x00000800 + 0x00008800 0x00000800 + 0x00009800 0x00000800 + 0x0000A800 0x00000800 + 0x0000B800 0x00000800 + 0x0000C800 0x00000800 + 0x0000D800 0x00000800 + 0x0000E800 0x00000800 + 0x0000F800 0x00000800 + 0x00010800 0x00000800 + 0x00011800 0x0000039A + gddrescue-1.30/testsuite/mapfile2ui000066400000000000000000000015641512716454500174330ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00001900 0x00000600 + # merged with block A 0x00001800 0x00000800 + # A 0x00004800 0x00000800 + 0x00000800 0x00000800 + 0x00005800 0x00000800 + 0x0000D800 0x00000700 + # merged with block D 0x00010800 0x00000800 + 0x0000E800 0x00000800 + 0x00006C00 0x00000400 + # merged with block E 0x00011800 0x0000039A + 0x00007800 0x00000800 + 0x00008800 0x00000100 + # merged with block B 0x00008800 0x00000800 + # B 0x00008F00 0x00000100 + # merged with block B 0x00009800 0x00000800 + 0x0000A800 0x00000800 + 0x0000B800 0x00000800 + 0x00002800 0x00000500 + # merged with block C 0x00002A00 0x00000600 + # C 0x0000C800 0x00000800 + 0x00003800 0x00000800 + 0x0000DC00 0x00000400 + # D 0x0000F800 0x00000800 + 0x00006800 0x00000400 + # E gddrescue-1.30/testsuite/mapfile3000066400000000000000000000013341512716454500170710ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000000 0x00000800 + 0x00000800 0x00001000 ? 0x00001800 0x00000800 + 0x00002000 0x00001000 ? 0x00003000 0x00000800 + 0x00003800 0x00001000 ? 0x00004800 0x00000800 + 0x00005000 0x00001000 ? 0x00006000 0x00000800 + 0x00006800 0x00001000 ? 0x00007800 0x00000800 + 0x00008000 0x00001000 ? 0x00009000 0x00000800 + 0x00009800 0x00001000 ? 0x0000A800 0x00000800 + 0x0000B000 0x00001000 ? 0x0000C000 0x00000800 + 0x0000C800 0x00001000 ? 0x0000D800 0x00000800 + 0x0000E000 0x00001000 ? 0x0000F000 0x00000800 + 0x0000F800 0x00001000 ? 0x00010800 0x00000800 + 0x00011000 0x00000B9A ? gddrescue-1.30/testsuite/mapfile4000066400000000000000000000013661512716454500170770ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000000 0x00000800 ? 0x00000800 0x00000800 + 0x00001000 0x00001000 ? 0x00002000 0x00000800 + 0x00002800 0x00001000 ? 0x00003800 0x00000800 + 0x00004000 0x00001000 ? 0x00005000 0x00000800 + 0x00005800 0x00001000 ? 0x00006800 0x00000800 + 0x00007000 0x00001000 ? 0x00008000 0x00000800 + 0x00008800 0x00001000 ? 0x00009800 0x00000800 + 0x0000A000 0x00001000 ? 0x0000B000 0x00000800 + 0x0000B800 0x00001000 ? 0x0000C800 0x00000800 + 0x0000D000 0x00001000 ? 0x0000E000 0x00000800 + 0x0000E800 0x00001000 ? 0x0000F800 0x00000800 + 0x00010000 0x00001000 ? 0x00011000 0x00000800 + 0x00011800 0x0000039A ? gddrescue-1.30/testsuite/mapfile5000066400000000000000000000013341512716454500170730ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000000 0x00001000 ? 0x00001000 0x00000800 + 0x00001800 0x00001000 ? 0x00002800 0x00000800 + 0x00003000 0x00001000 ? 0x00004000 0x00000800 + 0x00004800 0x00001000 ? 0x00005800 0x00000800 + 0x00006000 0x00001000 ? 0x00007000 0x00000800 + 0x00007800 0x00001000 ? 0x00008800 0x00000800 + 0x00009000 0x00001000 ? 0x0000A000 0x00000800 + 0x0000A800 0x00001000 ? 0x0000B800 0x00000800 + 0x0000C000 0x00001000 ? 0x0000D000 0x00000800 + 0x0000D800 0x00001000 ? 0x0000E800 0x00000800 + 0x0000F000 0x00001000 ? 0x00010000 0x00000800 + 0x00010800 0x00001000 ? 0x00011800 0x0000039A + gddrescue-1.30/testsuite/mapfile6000066400000000000000000000035641512716454500171030ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000000 0x00000800 + 0x00000800 0x00000080 - # bad subsector before sector 0x00000880 0x00000780 ? 0x00001000 0x00000800 + 0x00001800 0x00000800 ? 0x00002000 0x00000800 + 0x00002800 0x00000780 ? 0x00002F80 0x00000080 - # bad subsector after sector 0x00003000 0x00000800 + 0x00003800 0x00000800 ? 0x00004000 0x00000800 + 0x00004800 0x00000080 ? 0x00004880 0x00000780 - # bad subsector in block after 0x00005000 0x00000800 + 0x00005800 0x00000800 ? 0x00006000 0x00000800 + 0x00006800 0x00000780 - # bad subsector in block before 0x00006F80 0x00000080 ? 0x00007000 0x00000800 + 0x00007800 0x00000100 ? 0x00007900 0x00000600 - # two bad subsectors in block inside 0x00007F00 0x00000100 ? 0x00008000 0x00000800 + 0x00008800 0x00000800 ? 0x00009000 0x00000800 + 0x00009800 0x00000100 - 0x00009900 0x00000600 ? # two bad subsectors as blocks outside 0x00009F00 0x00000100 - 0x0000A000 0x00000800 + 0x0000A800 0x00000800 ? 0x0000B000 0x00000800 + 0x0000B800 0x00000300 ? 0x0000BB00 0x00000200 - # two bad subsectors as block inside 0x0000BD00 0x00000300 ? 0x0000C000 0x00000800 + 0x0000C800 0x00000800 ? 0x0000D000 0x00000800 + 0x0000D800 0x00000300 - 0x0000DB00 0x00000200 ? # two bad subsectors in blocks outside 0x0000DD00 0x00000300 - 0x0000E000 0x00000800 + 0x0000E800 0x00000800 ? 0x0000F000 0x00000800 + 0x0000F800 0x00000080 ? # four unfinished subsectors 0x0000F880 0x00000080 * 0x0000F900 0x00000080 / 0x0000F980 0x00000080 - 0x0000FA00 0x00000600 ? 0x00010000 0x00000800 + 0x00010800 0x00000100 - # eight unfinished subsectors misblocked 0x00010900 0x00000200 / 0x00010B00 0x00000200 * 0x00010D00 0x00000200 / 0x00010F00 0x00000100 - 0x00011000 0x00000800 + 0x00011800 0x0000039A ? gddrescue-1.30/testsuite/mapfile6j000066400000000000000000000023441512716454500172500ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000000 0x00000800 + 0x00000800 0x00000800 ? 0x00001000 0x00000800 + 0x00001800 0x00000800 ? 0x00002000 0x00000800 + 0x00002800 0x00000800 ? 0x00003000 0x00000800 + 0x00003800 0x00000800 ? 0x00004000 0x00000800 + 0x00004800 0x00000200 ? 0x00004A00 0x00000600 - 0x00005000 0x00000800 + 0x00005800 0x00000800 ? 0x00006000 0x00000800 + 0x00006800 0x00000600 - 0x00006E00 0x00000200 ? 0x00007000 0x00000800 + 0x00007800 0x00000200 ? 0x00007A00 0x00000400 - 0x00007E00 0x00000200 ? 0x00008000 0x00000800 + 0x00008800 0x00000800 ? 0x00009000 0x00000800 + 0x00009800 0x00000800 ? 0x0000A000 0x00000800 + 0x0000A800 0x00000800 ? 0x0000B000 0x00000800 + 0x0000B800 0x00000800 ? 0x0000C000 0x00000800 + 0x0000C800 0x00000800 ? 0x0000D000 0x00000800 + 0x0000D800 0x00000200 - 0x0000DA00 0x00000400 ? 0x0000DE00 0x00000200 - 0x0000E000 0x00000800 + 0x0000E800 0x00000800 ? 0x0000F000 0x00000800 + 0x0000F800 0x00000800 ? 0x00010000 0x00000800 + 0x00010800 0x00000200 / 0x00010A00 0x00000400 * 0x00010E00 0x00000200 / 0x00011000 0x00000800 + 0x00011800 0x0000039A ? gddrescue-1.30/testsuite/mapfile_blank000066400000000000000000000002061512716454500201520ustar00rootroot00000000000000# current_pos current_status current_pass 0x00000000 + 1 # pos size status 0x00000000 0x00011B9A ? gddrescue-1.30/testsuite/test.txt000066400000000000000000002156321512716454500171760ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. gddrescue-1.30/testsuite/test1.txt000066400000000000000000002140001512716454500172430ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, fohat you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when . For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and condither by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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 ceived 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, theatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a t. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distribute patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distributiN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 informationare is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect makam, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based onion of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy s version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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 for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenseram or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along wy all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it anHAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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 cgddrescue-1.30/testsuite/test2.txt000066400000000000000000002156321512716454500172600ustar00rootroot00000000000000r each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided tyou distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to itions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries eitRISK 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 re GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threcopy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote id need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation ofon is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. I on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the softwing the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Progr the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distributimultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the presentDATA 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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' s are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any prog whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on ith the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program bd "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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 ourse, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. gddrescue-1.30/testsuite/test3.txt000066400000000000000000002100001512716454500172410ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, foyou distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to ither by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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 GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is thret. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributeon is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. Iare is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect mak the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribut version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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 s are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any progit, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along wd "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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 gddrescue-1.30/testsuite/test4.txt000066400000000000000000002140001512716454500172460ustar00rootroot00000000000000r each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided t. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditRISK 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 reatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a d need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation ofN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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 informationing the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Progrion of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy sDATA 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. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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' ram or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in ith the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program bHAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 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 convey 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 2 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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 cgddrescue-1.30/testsuite/test5.txt000066400000000000000000002156321512716454500172630ustar00rootroot00000000000000hat you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when ions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries eitceived 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 is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, thecopy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote i patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distributi on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the softwam, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based onimultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the presentfor details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public License whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on y all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it anourse, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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.