From ded8a26aa08aae51e4bae9fe34ccf1410dcb55cb Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 7 Nov 2015 10:30:51 +0100 Subject: Merging upstream version 1.13~rc1. Signed-off-by: Daniel Baumann --- ChangeLog | 31 +- Makefile.in | 24 +- NEWS | 24 +- README | 8 +- configure | 2 +- doc/lzip.1 | 10 +- doc/lzip.info | 252 ++++------------ doc/lzip.texinfo | 234 +++------------ doc/lziprecover.1 | 47 --- encoder.cc | 12 +- encoder.h | 2 +- fast_encoder.cc | 12 +- lzip.h | 2 +- lziprecover.cc | 790 ------------------------------------------------- main.cc | 90 +++--- testsuite/check.sh | 74 +---- testsuite/test_bad1.lz | Bin 11548 -> 0 bytes testsuite/test_bad2.lz | Bin 11548 -> 0 bytes testsuite/test_bad3.lz | Bin 11548 -> 0 bytes testsuite/test_bad4.lz | Bin 11548 -> 0 bytes testsuite/test_bad5.lz | Bin 11548 -> 0 bytes testsuite/unzcrash.cc | 38 +-- 22 files changed, 222 insertions(+), 1430 deletions(-) delete mode 100644 doc/lziprecover.1 delete mode 100644 lziprecover.cc delete mode 100644 testsuite/test_bad1.lz delete mode 100644 testsuite/test_bad2.lz delete mode 100644 testsuite/test_bad3.lz delete mode 100644 testsuite/test_bad4.lz delete mode 100644 testsuite/test_bad5.lz diff --git a/ChangeLog b/ChangeLog index 88accb1..a173610 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-11-12 Antonio Diaz Diaz + + * Version 1.13-rc1 released. + * Lziprecover has been moved to its own package. + * main.cc (close_and_set_permissions): Inability to change output + file attributes has been downgraded from error to warning. + 2011-04-30 Antonio Diaz Diaz * Version 1.12 released. @@ -18,7 +25,9 @@ " and `--stdout' was not specified" for directories, etc. * lziprecover.cc: If `-v' is not specified show errors only. * testsuite/unzcrash.cc: Use Arg_parser. - * testsuite/unzcrash.cc: Added new options `-b', `-p' and `-s'. + * testsuite/unzcrash.cc: Added new option `-b, --bits'. + * testsuite/unzcrash.cc: Added new option `-p, --position'. + * testsuite/unzcrash.cc: Added new option `-s, --size'. 2010-09-16 Antonio Diaz Diaz @@ -31,19 +40,19 @@ compress less but faster. (-1 now takes 43% less time for only 20% larger compressed size). * encoder.cc: Compression of option -9 has been slightly increased. - * lziprecover.cc: Added new option `--merge' which tries to + * lziprecover.cc: Added new option `-m, --merge' which tries to produce a correct file merging the good parts of two or more damaged copies. - * lziprecover.cc: Added new option `--repair' for repairing a - 1-byte error in single-member files. + * lziprecover.cc: Added new option `-R, --repair' for repairing + a 1-byte error in single-member files. * decoder.cc (decode_member): Detect file errors earlier to improve efficiency of lziprecover's new repair capability. This change also prevents (harmless) access to uninitialized memory when decompressing a corrupt file. - * lziprecover.cc: Added new option `--force'. - * lziprecover.cc: Added new option `--output'. - * lziprecover.cc: Added new option `--split' to select the until - now only operation of splitting multimember files. + * lziprecover.cc: Added new option `-f, --force'. + * lziprecover.cc: Added new option `-o, --output'. + * lziprecover.cc: Added new option `-s, --split' to select the + until now only operation of splitting multimember files. * lziprecover.cc: If no operation is specified, warn the user and do nothing. * main.cc: Fixed warning about fchown's return value being ignored. @@ -123,9 +132,9 @@ * Version 1.4 released. * Implemented compression of version 1 files. - * Added new option `--member-size'. - * Added new option `--volume-size'. - * Added new option `--output'. + * Added new option `-b, --member-size'. + * Added new option `-S, --volume-size'. + * Added new option `-o, --output'. * main.cc: Read from non regular files if `--stdout' is specified. * Added `lziprecover', a member recoverer program. * testsuite/unzcrash.cc: Test all 1-byte errors. diff --git a/Makefile.in b/Makefile.in index 30aba74..98a9a98 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,7 +7,6 @@ INSTALL_DIR = $(INSTALL) -d -m 755 SHELL = /bin/sh objs = arg_parser.o decoder.o encoder.o fast_encoder.o main.o -recobjs = arg_parser.o decoder.o lziprecover.o unzobjs = arg_parser.o unzcrash.o @@ -15,7 +14,7 @@ unzobjs = arg_parser.o unzcrash.o uninstall uninstall-info uninstall-man \ doc info man check dist clean distclean -all : $(progname) lziprecover +all : $(progname) $(progname) : $(objs) $(CXX) $(LDFLAGS) -o $@ $(objs) @@ -23,18 +22,12 @@ $(progname) : $(objs) $(progname)_profiled : $(objs) $(CXX) $(LDFLAGS) -pg -o $@ $(objs) -lziprecover : $(recobjs) - $(CXX) $(LDFLAGS) -o $@ $(recobjs) - unzcrash : $(unzobjs) $(CXX) $(LDFLAGS) -o $@ $(unzobjs) main.o : main.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $< -lziprecover.o : lziprecover.cc - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $< - unzcrash.o : testsuite/unzcrash.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $< @@ -47,7 +40,6 @@ decoder.o : lzip.h decoder.h encoder.o : lzip.h encoder.h fast_encoder.o : lzip.h encoder.h fast_encoder.h main.o : arg_parser.h lzip.h decoder.h encoder.h fast_encoder.h -lziprecover.o : arg_parser.h lzip.h decoder.h Makefile unzcrash.o : arg_parser.h Makefile @@ -58,16 +50,12 @@ info : $(VPATH)/doc/$(pkgname).info $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo cd $(VPATH)/doc && makeinfo $(pkgname).texinfo -man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/lziprecover.1 +man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/$(progname).1 : $(progname) help2man -n 'reduces the size of files' \ -o $@ ./$(progname) -$(VPATH)/doc/lziprecover.1 : lziprecover - help2man -n 'recovers data from damaged lzip files' \ - -o $@ --no-info ./lziprecover - Makefile : $(VPATH)/configure $(VPATH)/Makefile.in ./config.status @@ -77,7 +65,6 @@ check : all install : all install-info install-man if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi $(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)" - $(INSTALL_PROGRAM) ./lziprecover "$(DESTDIR)$(bindir)/lziprecover" install-info : if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi @@ -87,14 +74,12 @@ install-info : install-man : if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi $(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1" - $(INSTALL_DATA) $(VPATH)/doc/lziprecover.1 "$(DESTDIR)$(mandir)/man1/lziprecover.1" install-strip : all $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install uninstall : uninstall-info uninstall-man -rm -f "$(DESTDIR)$(bindir)/$(progname)" - -rm -f "$(DESTDIR)$(bindir)/lziprecover" uninstall-info : -install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" @@ -102,7 +87,6 @@ uninstall-info : uninstall-man : -rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1" - -rm -f "$(DESTDIR)$(mandir)/man1/lziprecover.1" dist : doc ln -sf $(VPATH) $(DISTNAME) @@ -116,12 +100,10 @@ dist : doc $(DISTNAME)/README \ $(DISTNAME)/configure \ $(DISTNAME)/doc/$(progname).1 \ - $(DISTNAME)/doc/lziprecover.1 \ $(DISTNAME)/doc/$(pkgname).info \ $(DISTNAME)/doc/$(pkgname).texinfo \ $(DISTNAME)/testsuite/check.sh \ $(DISTNAME)/testsuite/test.txt \ - $(DISTNAME)/testsuite/test_bad[1-5].lz \ $(DISTNAME)/testsuite/test_sync.lz \ $(DISTNAME)/testsuite/test_v[01].lz \ $(DISTNAME)/testsuite/unzcrash.cc \ @@ -132,7 +114,7 @@ dist : doc clean : -rm -f $(progname) $(progname)_profiled $(objs) - -rm -f lziprecover lziprecover.o unzcrash unzcrash.o + -rm -f unzcrash unzcrash.o distclean : clean -rm -f Makefile config.status *.tar *.tar.lz diff --git a/NEWS b/NEWS index affec93..6b4c70d 100644 --- a/NEWS +++ b/NEWS @@ -1,22 +1,6 @@ -Changes in version 1.12: +Changes in version 1.13: -The option "-F, --recompress", which forces recompression of files whose -name already has the ".lz" or ".tlz" suffix, has been added. +Lziprecover has been moved to its own package. -For large values of "--match-length", compression ratio has been -slightly increased and compression time has been reduced by up to 6%. - -Compression time of option "-0" has been reduced by 2%. - -Print only one status line for each multimember file when only one "-v" -is specified. - -Print up to 6 bytes of trailing garbage when "-vvvv" is specified. - -Do not show the message "and `--stdout' was not specified" for file -types that can't be read (directories, etc). - -If "--verbose" is not specified, lziprecover now only shows errors and -warnings. - -Options "--bits", "--position" and "--size" has been added to unzcrash. +Inability to change output file attributes has been downgraded from +error to warning. diff --git a/README b/README index d075ab3..51a03e5 100644 --- a/README +++ b/README @@ -6,12 +6,8 @@ gzip or bzip2. Lzip decompresses almost as fast as gzip and compresses better than bzip2, which makes it well suited for software distribution and data archiving. -Lziprecover is a data recovery tool for lzip compressed files able to -repair slightly damaged files, recover badly damaged files from two or -more copies, and extract undamaged members from multi-member files. If -the cause of file corruption is damaged media, the combination GNU -ddrescue + lziprecover is the best option for recovering data from -multiple damaged copies. +If you ever need to recover data from a damaged lzip file, try the +lziprecover program. Lzip replaces every file given in the command line with a compressed version of itself, with the name "original_name.lz". Each compressed diff --git a/configure b/configure index 8b291a6..f2d87bc 100755 --- a/configure +++ b/configure @@ -8,7 +8,7 @@ args= no_create= pkgname=lzip -pkgversion=1.12 +pkgversion=1.13-rc1 progname=lzip srctrigger=lzip.h diff --git a/doc/lzip.1 b/doc/lzip.1 index b0cf9a5..caac739 100644 --- a/doc/lzip.1 +++ b/doc/lzip.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. -.TH LZIP "1" "April 2011" "Lzip 1.12" "User Commands" +.TH LZIP "1" "November 2011" "Lzip 1.13-rc1" "User Commands" .SH NAME Lzip \- reduces the size of files .SH SYNOPSIS @@ -15,7 +15,7 @@ display this help and exit \fB\-V\fR, \fB\-\-version\fR output version information and exit .TP -\fB\-b\fR, \fB\-\-member\-size=\fR +\fB\-b\fR, \fB\-\-member\-size=\fR set member size limit in bytes .TP \fB\-c\fR, \fB\-\-stdout\fR @@ -33,7 +33,7 @@ force recompression of compressed files \fB\-k\fR, \fB\-\-keep\fR keep (don't delete) input files .TP -\fB\-m\fR, \fB\-\-match\-length=\fR +\fB\-m\fR, \fB\-\-match\-length=\fR set match length limit in bytes [36] .TP \fB\-o\fR, \fB\-\-output=\fR @@ -42,10 +42,10 @@ if reading stdin, place the output into \fB\-q\fR, \fB\-\-quiet\fR suppress all messages .TP -\fB\-s\fR, \fB\-\-dictionary\-size=\fR +\fB\-s\fR, \fB\-\-dictionary\-size=\fR set dictionary size limit in bytes [8MiB] .TP -\fB\-S\fR, \fB\-\-volume\-size=\fR +\fB\-S\fR, \fB\-\-volume\-size=\fR set volume size limit in bytes .TP \fB\-t\fR, \fB\-\-test\fR diff --git a/doc/lzip.info b/doc/lzip.info index fa26348..2981447 100644 --- a/doc/lzip.info +++ b/doc/lzip.info @@ -11,7 +11,7 @@ File: lzip.info, Node: Top, Next: Introduction, Up: (dir) Lzip Manual *********** -This manual is for Lzip (version 1.12, 30 April 2011). +This manual is for Lzip (version 1.13-rc1, 12 November 2011). * Menu: @@ -20,8 +20,6 @@ This manual is for Lzip (version 1.12, 30 April 2011). * Invoking Lzip:: Command line interface * File Format:: Detailed format of the compressed file * Examples:: A small tutorial with examples -* Lziprecover:: Recovering data from damaged compressed files -* Invoking Lziprecover:: Command line interface * Problems:: Reporting bugs * Concept Index:: Index of concepts @@ -43,6 +41,9 @@ gzip or bzip2. Lzip decompresses almost as fast as gzip and compresses better than bzip2, which makes it well suited for software distribution and data archiving. + If you ever need to recover data from a damaged lzip file, try the +lziprecover program. + Lzip replaces every file given in the command line with a compressed version of itself, with the name "original_name.lz". Each compressed file has the same modification date, permissions, and, when possible, @@ -182,12 +183,12 @@ The format for running lzip is: `--version' Print the version number of lzip on the standard output and exit. -`-b SIZE' -`--member-size=SIZE' - Produce a multimember file and set the member size limit to SIZE - bytes. Minimum member size limit is 100kB. Small member size may - degrade compression ratio, so use it only when needed. The default - is to produce single-member files. +`-b BYTES' +`--member-size=BYTES' + Produce a multimember file and set the member size limit to BYTES. + Minimum member size limit is 100kB. Small member size may degrade + compression ratio, so use it only when needed. The default is to + produce single-member files. `-c' `--stdout' @@ -202,7 +203,7 @@ The format for running lzip is: `-f' `--force' - Force overwrite of output file. + Force overwrite of output files. `-F' `--recompress' @@ -214,8 +215,8 @@ The format for running lzip is: Keep (don't delete) input files during compression or decompression. -`-m LENGTH' -`--match-length=LENGTH' +`-m BYTES' +`--match-length=BYTES' Set the match length limit in bytes. After a match this long is found, the search is finished. Valid values range from 5 to 273. Larger values usually give better compression ratios but longer @@ -234,25 +235,25 @@ The format for running lzip is: `--quiet' Quiet operation. Suppress all messages. -`-s SIZE' -`--dictionary-size=SIZE' +`-s BYTES' +`--dictionary-size=BYTES' Set the dictionary size limit in bytes. Valid values range from 4KiB to 512MiB. Lzip will use the smallest possible dictionary size for each member without exceeding this limit. Note that dictionary sizes are quantized. If the specified size does not match one of the valid sizes, it will be rounded upwards by adding - up to (SIZE / 16) to it. + up to (BYTES / 16) to it. For maximum compression you should use a dictionary size limit as large as possible, but keep in mind that the decompression memory requirement is affected at compression time by the choice of dictionary size limit. -`-S SIZE' -`--volume-size=SIZE' +`-S BYTES' +`--volume-size=BYTES' Split the compressed output into several volume files with names `original_name00001.lz', `original_name00002.lz', etc, and set the - volume size limit to SIZE bytes. Each volume is a complete, maybe + volume size limit to BYTES. Each volume is a complete, maybe multimember, lzip file. Minimum volume size limit is 100kB. Small volume size may degrade compression ratio, so use it only when needed. @@ -266,11 +267,13 @@ The format for running lzip is: `-v' `--verbose' - Verbose mode. When compressing, show the compression ratio for - each file processed. When decompressing or testing, further -v's - (up to 4) increase the verbosity level, showing status, dictionary - size, compression ratio, trailer contents (CRC, data size, member - size), and up to 6 bytes of trailing garbage (if any). + Verbose mode. + When compressing, show the compression ratio for each file + processed. + When decompressing or testing, further -v's (up to 4) increase the + verbosity level, showing status, dictionary size, compression + ratio, trailer contents (CRC, data size, member size), and up to 6 + bytes of trailing garbage (if any). `-0 .. -9' Set the compression parameters (dictionary size and match length @@ -379,7 +382,7 @@ additional information before, between, or after them.  -File: lzip.info, Node: Examples, Next: Lziprecover, Prev: File Format, Up: Top +File: lzip.info, Node: Examples, Next: Problems, Prev: File Format, Up: Top 5 A small tutorial with examples ******************************** @@ -392,205 +395,69 @@ verify the compressed file with a command like `lzip -cd file.lz | cmp file -'. -Example 1: Replace a regular file with its compressed version file.lz +Example 1: Replace a regular file with its compressed version `file.lz' and show the compression ratio. lzip -v file -Example 2: Like example 1 but the created file.lz is multimember with a -member size of 1MiB. The compression ratio is not shown. +Example 2: Like example 1 but the created `file.lz' is multimember with +a member size of 1MiB. The compression ratio is not shown. lzip -b 1MiB file -Example 3: Restore a regular file from its compressed version file.lz. -If the operation is successful, file.lz is removed. +Example 3: Restore a regular file from its compressed version +`file.lz'. If the operation is successful, `file.lz' is removed. lzip -d file.lz -Example 4: Verify the integrity of the compressed file file.lz and show -status. +Example 4: Verify the integrity of the compressed file `file.lz' and +show status. lzip -tv file.lz Example 5: Compress a whole floppy in /dev/fd0 and send the output to -file.lz. +`file.lz'. lzip -c /dev/fd0 > file.lz -Example 6: Decompress file.lz partially until 10KiB of decompressed data -are produced. +Example 6: Decompress `file.lz' partially until 10KiB of decompressed +data are produced. lzip -cd file.lz | dd bs=1024 count=10 -Example 7: Create a multivolume compressed tar archive with a volume +Example 7: Decompress `file.lz' partially from decompressed byte 10000 +to decompressed byte 15000 (5000 bytes are produced). + + lzip -cd file.lz | dd bs=1000 skip=10 count=5 + + +Example 8: Create a multivolume compressed tar archive with a volume size of 1440KiB. tar -c some_directory | lzip -S 1440KiB -o volume_name -Example 8: Extract a multivolume compressed tar archive. +Example 9: Extract a multivolume compressed tar archive. lzip -cd volume_name*.lz | tar -xf - -Example 9: Create a multivolume compressed backup of a big database file -with a volume size of 650MB, where each volume is a multimember file -with a member size of 32MiB. +Example 10: Create a multivolume compressed backup of a big database +file with a volume size of 650MB, where each volume is a multimember +file with a member size of 32MiB. lzip -b 32MiB -S 650MB big_db - -Example 10: Recover a compressed backup from two copies on CD-ROM (see -the GNU ddrescue manual for details about ddrescue) - - ddrescue -b2048 /dev/cdrom cdimage1 logfile1 - mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage - cp /mnt/cdimage/backup.tar.lz rescued1.tar.lz - umount /mnt/cdimage - (insert second copy in the CD drive) - ddrescue -b2048 /dev/cdrom cdimage2 logfile2 - mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage - cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz - umount /mnt/cdimage - lziprecover -m -v -o rescued.tar.lz rescued1.tar.lz rescued2.tar.lz - - -Example 11: Recover the first volume of those created in example 9 from -two copies, `big_db1_00001.lz' and `big_db2_00001.lz', with member -00007 damaged in the first copy, member 00018 damaged in the second -copy, and member 00012 damaged in both copies. (Indented lines are -abridged error messages from lzip/lziprecover). Two correct copies are -produced and compared. - - lziprecover -s big_db1_00001.lz - lziprecover -s big_db2_00001.lz - lzip -t rec*big_db1_00001.lz - rec00007big_db1_00001.lz: crc mismatch - rec00012big_db1_00001.lz: crc mismatch - lzip -t rec*big_db2_00001.lz - rec00012big_db2_00001.lz: crc mismatch - rec00018big_db2_00001.lz: crc mismatch - lziprecover -m -v rec00012big_db1_00001.lz rec00012big_db2_00001.lz - Input files merged successfully - cp rec00007big_db2_00001.lz rec00007big_db1_00001.lz - cp rec00012big_db1_00001_fixed.lz rec00012big_db1_00001.lz - cp rec00012big_db1_00001_fixed.lz rec00012big_db2_00001.lz - cp rec00018big_db1_00001.lz rec00018big_db2_00001.lz - cat rec*big_db1_00001.lz > big_db3_00001.lz - cat rec*big_db2_00001.lz > big_db4_00001.lz - zcmp big_db3_00001.lz big_db4_00001.lz - - -File: lzip.info, Node: Lziprecover, Next: Invoking Lziprecover, Prev: Examples, Up: Top - -6 Lziprecover -************* - -Lziprecover is a data recovery tool for lzip compressed files able to -repair slightly damaged files, recover badly damaged files from two or -more copies, and extract undamaged members from multi-member files. - - Lziprecover takes as arguments the names of the damaged files and -writes zero or more recovered files depending on the operation selected -and whether the recovery succeeded or not. The damaged files themselves -are never modified. - - If the files are too damaged for lziprecover to repair them, data -from damaged members can be partially recovered writing it to stdout as -shown in the following example (the resulting file may contain garbage -data at the end): - - lzip -cd rec00001file.lz > rec00001file - - If the cause of file corruption is damaged media, the combination GNU -ddrescue + lziprecover is the best option for recovering data from -multiple damaged copies. *Note ddrescue-example::, for an example. - - -File: lzip.info, Node: Invoking Lziprecover, Next: Problems, Prev: Lziprecover, Up: Top - -7 Invoking Lziprecover -********************** - -The format for running lziprecover is: - - lziprecover [OPTIONS] [FILES] - - Lziprecover supports the following options: - -`-h' -`--help' - Print an informative help message describing the options and exit. - -`-V' -`--version' - Print the version number of lziprecover on the standard output and - exit. - -`-f' -`--force' - Force overwrite of output file. - -`-m' -`--merge' - Try to produce a correct file merging the good parts of two or more - damaged copies. The copies must be single-member files. The merge - will fail if the copies have too many damaged areas or if the same - byte is damaged in all copies. If successful, a repaired copy is - written to the file `FILE_fixed.lz'. - - To give you an idea of its possibilities, when merging two copies - each of them with one damaged area affecting 1 percent of the - copy, the probability of obtaining a correct file is about 98 - percent. With three such copies the probability rises to 99.97 - percent. For large files with small errors, the probability - approaches 100 percent even with only two copies. - -`-o FILE' -`--output=FILE' - Place the output into `FILE' instead of into `FILE_fixed.lz'. - - If splitting, the names of the files produced are in the form - `rec00001FILE', etc. - -`-q' -`--quiet' - Quiet operation. Suppress all messages. - -`-R' -`--repair' - Try to repair a small error, affecting only one byte, in a - single-member FILE. If successful, a repaired copy is written to - the file `FILE_fixed.lz'. `FILE' is not modified at all. - -`-s' -`--split' - Search for members in `FILE' and write each member in its own - `.lz' file. You can then use `lzip -t' to test the integrity of - the resulting files, decompress those which are undamaged, and try - to repair or partially decompress those which are damaged. - - The names of the files produced are in the form `rec00001FILE.lz', - `rec00002FILE.lz', etc, and are designed so that the use of - wildcards in subsequent processing, for example, - `lzip -cd rec*FILE.lz > recovered_data', processes the files in - the correct order. - -`-v' -`--verbose' - Verbose mode. Further -v's increase the verbosity level. - -  -File: lzip.info, Node: Problems, Next: Concept Index, Prev: Invoking Lziprecover, Up: Top +File: lzip.info, Node: Problems, Next: Concept Index, Prev: Examples, Up: Top -8 Reporting Bugs +6 Reporting Bugs **************** There are probably bugs in lzip. There are certainly errors and @@ -618,8 +485,6 @@ Concept Index * getting help: Problems. (line 6) * introduction: Introduction. (line 6) * invoking lzip: Invoking Lzip. (line 6) -* invoking lziprecover: Invoking Lziprecover. (line 6) -* lziprecover: Lziprecover. (line 6) * options: Invoking Lzip. (line 6) * usage: Invoking Lzip. (line 6) * version: Invoking Lzip. (line 6) @@ -628,15 +493,12 @@ Concept Index  Tag Table: Node: Top224 -Node: Introduction1031 -Node: Algorithm4439 -Node: Invoking Lzip6957 -Node: File Format12303 -Node: Examples14295 -Ref: ddrescue-example16049 -Node: Lziprecover17848 -Node: Invoking Lziprecover18901 -Node: Problems21262 -Node: Concept Index21796 +Node: Introduction917 +Node: Algorithm4417 +Node: Invoking Lzip6935 +Node: File Format12285 +Node: Examples14277 +Node: Problems16221 +Node: Concept Index16743  End Tag Table diff --git a/doc/lzip.texinfo b/doc/lzip.texinfo index b86de34..190f20f 100644 --- a/doc/lzip.texinfo +++ b/doc/lzip.texinfo @@ -5,8 +5,8 @@ @finalout @c %**end of header -@set UPDATED 30 April 2011 -@set VERSION 1.12 +@set UPDATED 12 November 2011 +@set VERSION 1.13-rc1 @dircategory Data Compression @direntry @@ -39,8 +39,6 @@ This manual is for Lzip (version @value{VERSION}, @value{UPDATED}). * Invoking Lzip:: Command line interface * File Format:: Detailed format of the compressed file * Examples:: A small tutorial with examples -* Lziprecover:: Recovering data from damaged compressed files -* Invoking Lziprecover:: Command line interface * Problems:: Reporting bugs * Concept Index:: Index of concepts @end menu @@ -62,6 +60,9 @@ gzip or bzip2. Lzip decompresses almost as fast as gzip and compresses better than bzip2, which makes it well suited for software distribution and data archiving. +If you ever need to recover data from a damaged lzip file, try the +lziprecover program. + Lzip replaces every file given in the command line with a compressed version of itself, with the name "original_name.lz". Each compressed file has the same modification date, permissions, and, when possible, @@ -208,10 +209,10 @@ Print an informative help message describing the options and exit. @itemx --version Print the version number of lzip on the standard output and exit. -@item -b @var{size} -@itemx --member-size=@var{size} -Produce a multimember file and set the member size limit to @var{size} -bytes. Minimum member size limit is 100kB. Small member size may degrade +@item -b @var{bytes} +@itemx --member-size=@var{bytes} +Produce a multimember file and set the member size limit to @var{bytes}. +Minimum member size limit is 100kB. Small member size may degrade compression ratio, so use it only when needed. The default is to produce single-member files. @@ -227,7 +228,7 @@ Decompress. @item -f @itemx --force -Force overwrite of output file. +Force overwrite of output files. @item -F @itemx --recompress @@ -238,8 +239,8 @@ Force recompression of files whose name already has the @samp{.lz} or @itemx --keep Keep (don't delete) input files during compression or decompression. -@item -m @var{length} -@itemx --match-length=@var{length} +@item -m @var{bytes} +@itemx --match-length=@var{bytes} Set the match length limit in bytes. After a match this long is found, the search is finished. Valid values range from 5 to 273. Larger values usually give better compression ratios but longer compression times. @@ -257,25 +258,25 @@ compressing and splitting the output in volumes. @itemx --quiet Quiet operation. Suppress all messages. -@item -s @var{size} -@itemx --dictionary-size=@var{size} +@item -s @var{bytes} +@itemx --dictionary-size=@var{bytes} Set the dictionary size limit in bytes. Valid values range from 4KiB to 512MiB. Lzip will use the smallest possible dictionary size for each member without exceeding this limit. Note that dictionary sizes are quantized. If the specified size does not match one of the valid sizes, -it will be rounded upwards by adding up to (@var{size} / 16) to it. +it will be rounded upwards by adding up to (@var{bytes} / 16) to it. For maximum compression you should use a dictionary size limit as large as possible, but keep in mind that the decompression memory requirement is affected at compression time by the choice of dictionary size limit. -@item -S @var{size} -@itemx --volume-size=@var{size} +@item -S @var{bytes} +@itemx --volume-size=@var{bytes} Split the compressed output into several volume files with names @samp{original_name00001.lz}, @samp{original_name00002.lz}, etc, and set -the volume size limit to @var{size} bytes. Each volume is a complete, -maybe multimember, lzip file. Minimum volume size limit is 100kB. Small -volume size may degrade compression ratio, so use it only when needed. +the volume size limit to @var{bytes}. Each volume is a complete, maybe +multimember, lzip file. Minimum volume size limit is 100kB. Small volume +size may degrade compression ratio, so use it only when needed. @item -t @itemx --test @@ -285,8 +286,8 @@ Use it together with @samp{-v} to see information about the file. @item -v @itemx --verbose -Verbose mode. -When compressing, show the compression ratio for each file processed. +Verbose mode.@* +When compressing, show the compression ratio for each file processed.@* When decompressing or testing, further -v's (up to 4) increase the verbosity level, showing status, dictionary size, compression ratio, trailer contents (CRC, data size, member size), and up to 6 bytes of @@ -422,8 +423,8 @@ file.lz | cmp file -}}. @sp 1 @noindent -Example 1: Replace a regular file with its compressed version file.lz -and show the compression ratio. +Example 1: Replace a regular file with its compressed version +@samp{file.lz} and show the compression ratio. @example lzip -v file @@ -431,8 +432,8 @@ lzip -v file @sp 1 @noindent -Example 2: Like example 1 but the created file.lz is multimember with a -member size of 1MiB. The compression ratio is not shown. +Example 2: Like example 1 but the created @samp{file.lz} is multimember +with a member size of 1MiB. The compression ratio is not shown. @example lzip -b 1MiB file @@ -440,8 +441,9 @@ lzip -b 1MiB file @sp 1 @noindent -Example 3: Restore a regular file from its compressed version file.lz. -If the operation is successful, file.lz is removed. +Example 3: Restore a regular file from its compressed version +@samp{file.lz}. If the operation is successful, @samp{file.lz} is +removed. @example lzip -d file.lz @@ -449,8 +451,8 @@ lzip -d file.lz @sp 1 @noindent -Example 4: Verify the integrity of the compressed file file.lz and show -status. +Example 4: Verify the integrity of the compressed file @samp{file.lz} +and show status. @example lzip -tv file.lz @@ -459,7 +461,7 @@ lzip -tv file.lz @sp 1 @noindent Example 5: Compress a whole floppy in /dev/fd0 and send the output to -file.lz. +@samp{file.lz}. @example lzip -c /dev/fd0 > file.lz @@ -467,8 +469,8 @@ lzip -c /dev/fd0 > file.lz @sp 1 @noindent -Example 6: Decompress file.lz partially until 10KiB of decompressed data -are produced. +Example 6: Decompress @samp{file.lz} partially until 10KiB of +decompressed data are produced. @example lzip -cd file.lz | dd bs=1024 count=10 @@ -476,184 +478,40 @@ lzip -cd file.lz | dd bs=1024 count=10 @sp 1 @noindent -Example 7: Create a multivolume compressed tar archive with a volume -size of 1440KiB. - -@example -tar -c some_directory | lzip -S 1440KiB -o volume_name -@end example - -@sp 1 -@noindent -Example 8: Extract a multivolume compressed tar archive. +Example 7: Decompress @samp{file.lz} partially from decompressed byte +10000 to decompressed byte 15000 (5000 bytes are produced). @example -lzip -cd volume_name*.lz | tar -xf - +lzip -cd file.lz | dd bs=1000 skip=10 count=5 @end example @sp 1 @noindent -Example 9: Create a multivolume compressed backup of a big database file -with a volume size of 650MB, where each volume is a multimember file -with a member size of 32MiB. +Example 8: Create a multivolume compressed tar archive with a volume +size of 1440KiB. @example -lzip -b 32MiB -S 650MB big_db +tar -c some_directory | lzip -S 1440KiB -o volume_name @end example @sp 1 -@anchor{ddrescue-example} @noindent -Example 10: Recover a compressed backup from two copies on CD-ROM (see -the GNU ddrescue manual for details about ddrescue) +Example 9: Extract a multivolume compressed tar archive. @example -ddrescue -b2048 /dev/cdrom cdimage1 logfile1 -mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage -cp /mnt/cdimage/backup.tar.lz rescued1.tar.lz -umount /mnt/cdimage - (insert second copy in the CD drive) -ddrescue -b2048 /dev/cdrom cdimage2 logfile2 -mount -t iso9660 -o loop,ro cdimage2 /mnt/cdimage -cp /mnt/cdimage/backup.tar.lz rescued2.tar.lz -umount /mnt/cdimage -lziprecover -m -v -o rescued.tar.lz rescued1.tar.lz rescued2.tar.lz +lzip -cd volume_name*.lz | tar -xf - @end example @sp 1 @noindent -Example 11: Recover the first volume of those created in example 9 from -two copies, @samp{big_db1_00001.lz} and @samp{big_db2_00001.lz}, with -member 00007 damaged in the first copy, member 00018 damaged in the -second copy, and member 00012 damaged in both copies. (Indented lines -are abridged error messages from lzip/lziprecover). Two correct copies -are produced and compared. - -@example -lziprecover -s big_db1_00001.lz -lziprecover -s big_db2_00001.lz -lzip -t rec*big_db1_00001.lz - rec00007big_db1_00001.lz: crc mismatch - rec00012big_db1_00001.lz: crc mismatch -lzip -t rec*big_db2_00001.lz - rec00012big_db2_00001.lz: crc mismatch - rec00018big_db2_00001.lz: crc mismatch -lziprecover -m -v rec00012big_db1_00001.lz rec00012big_db2_00001.lz - Input files merged successfully -cp rec00007big_db2_00001.lz rec00007big_db1_00001.lz -cp rec00012big_db1_00001_fixed.lz rec00012big_db1_00001.lz -cp rec00012big_db1_00001_fixed.lz rec00012big_db2_00001.lz -cp rec00018big_db1_00001.lz rec00018big_db2_00001.lz -cat rec*big_db1_00001.lz > big_db3_00001.lz -cat rec*big_db2_00001.lz > big_db4_00001.lz -zcmp big_db3_00001.lz big_db4_00001.lz -@end example - - -@node Lziprecover -@chapter Lziprecover -@cindex lziprecover - -Lziprecover is a data recovery tool for lzip compressed files able to -repair slightly damaged files, recover badly damaged files from two or -more copies, and extract undamaged members from multi-member files. - -Lziprecover takes as arguments the names of the damaged files and writes -zero or more recovered files depending on the operation selected and -whether the recovery succeeded or not. The damaged files themselves are -never modified. - -If the files are too damaged for lziprecover to repair them, data from -damaged members can be partially recovered writing it to stdout as shown -in the following example (the resulting file may contain garbage data at -the end): - -@example -lzip -cd rec00001file.lz > rec00001file -@end example - -If the cause of file corruption is damaged media, the combination GNU -ddrescue + lziprecover is the best option for recovering data from -multiple damaged copies. @xref{ddrescue-example}, for an example. - - -@node Invoking Lziprecover -@chapter Invoking Lziprecover -@cindex invoking lziprecover - -The format for running lziprecover is: +Example 10: Create a multivolume compressed backup of a big database +file with a volume size of 650MB, where each volume is a multimember +file with a member size of 32MiB. @example -lziprecover [@var{options}] [@var{files}] +lzip -b 32MiB -S 650MB big_db @end example -Lziprecover supports the following options: - -@table @samp -@item -h -@itemx --help -Print an informative help message describing the options and exit. - -@item -V -@itemx --version -Print the version number of lziprecover on the standard output and exit. - -@item -f -@itemx --force -Force overwrite of output file. - -@item -m -@itemx --merge -Try to produce a correct file merging the good parts of two or more -damaged copies. The copies must be single-member files. The merge will -fail if the copies have too many damaged areas or if the same byte is -damaged in all copies. If successful, a repaired copy is written to the -file @samp{@var{file}_fixed.lz}. - -To give you an idea of its possibilities, when merging two copies each -of them with one damaged area affecting 1 percent of the copy, the -probability of obtaining a correct file is about 98 percent. With three -such copies the probability rises to 99.97 percent. For large files with -small errors, the probability approaches 100 percent even with only two -copies. - -@item -o @var{file} -@itemx --output=@var{file} -Place the output into @samp{@var{file}} instead of into -@samp{@var{file}_fixed.lz}. - -If splitting, the names of the files produced are in the form -@samp{rec00001@var{file}}, etc. - -@item -q -@itemx --quiet -Quiet operation. Suppress all messages. - -@item -R -@itemx --repair -Try to repair a small error, affecting only one byte, in a single-member -@var{file}. If successful, a repaired copy is written to the file -@samp{@var{file}_fixed.lz}. @samp{@var{file}} is not modified at all. - -@item -s -@itemx --split -Search for members in @samp{@var{file}} and write each member in its own -@samp{.lz} file. You can then use @samp{lzip -t} to test the integrity -of the resulting files, decompress those which are undamaged, and try to -repair or partially decompress those which are damaged. - -The names of the files produced are in the form -@samp{rec00001@var{file}.lz}, @samp{rec00002@var{file}.lz}, etc, and are -designed so that the use of wildcards in subsequent processing, for -example, @w{@samp{lzip -cd rec*@var{file}.lz > recovered_data}}, -processes the files in the correct order. - -@item -v -@itemx --verbose -Verbose mode. Further -v's increase the verbosity level. - -@end table - @node Problems @chapter Reporting Bugs diff --git a/doc/lziprecover.1 b/doc/lziprecover.1 deleted file mode 100644 index ff8e0ed..0000000 --- a/doc/lziprecover.1 +++ /dev/null @@ -1,47 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. -.TH LZIPRECOVER "1" "April 2011" "Lziprecover 1.12" "User Commands" -.SH NAME -Lziprecover \- recovers data from damaged lzip files -.SH SYNOPSIS -.B lziprecover -[\fIoptions\fR] [\fIfiles\fR] -.SH DESCRIPTION -Lziprecover \- Data recovery tool for lzip compressed files. -.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\-f\fR, \fB\-\-force\fR -overwrite existing output files -.TP -\fB\-m\fR, \fB\-\-merge\fR -correct errors in file using several copies -.TP -\fB\-o\fR, \fB\-\-output=\fR -place the output into -.TP -\fB\-q\fR, \fB\-\-quiet\fR -suppress all messages -.TP -\fB\-R\fR, \fB\-\-repair\fR -try to repair a small error in file -.TP -\fB\-s\fR, \fB\-\-split\fR -split a multimember file in single\-member files -.TP -\fB\-v\fR, \fB\-\-verbose\fR -be verbose (a 2nd \fB\-v\fR gives more) -.SH "REPORTING BUGS" -Report bugs to lzip\-bug@nongnu.org -.br -Lzip home page: http://www.nongnu.org/lzip/lzip.html -.SH COPYRIGHT -Copyright \(co 2011 Antonio Diaz Diaz. -License GPLv3+: GNU GPL version 3 or later -.br -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. diff --git a/encoder.cc b/encoder.cc index 1bdf78e..79dd5cf 100644 --- a/encoder.cc +++ b/encoder.cc @@ -63,12 +63,14 @@ Matchfinder::Matchfinder( const int dict_size, const int len_limit, const int buffer_size_limit = ( 2 * dict_size ) + before_size + after_size; buffer_size = std::max( 65536, dict_size ); buffer = (uint8_t *)std::malloc( buffer_size ); - if( !buffer ) throw std::bad_alloc(); + if( !buffer ) { delete[] prev_positions; throw std::bad_alloc(); } if( read_block() && !at_stream_end && buffer_size < buffer_size_limit ) { buffer_size = buffer_size_limit; - buffer = (uint8_t *)std::realloc( buffer, buffer_size ); - if( !buffer ) throw std::bad_alloc(); + uint8_t * const tmp = (uint8_t *)std::realloc( buffer, buffer_size ); + if( !tmp ) + { std::free( buffer ); delete[] prev_positions; throw std::bad_alloc(); } + buffer = tmp; read_block(); } if( at_stream_end && stream_pos < dict_size ) @@ -76,7 +78,9 @@ Matchfinder::Matchfinder( const int dict_size, const int len_limit, else dictionary_size_ = dict_size; pos_limit = buffer_size; if( !at_stream_end ) pos_limit -= after_size; - prev_pos_tree = new int32_t[2*dictionary_size_]; + prev_pos_tree = new( std::nothrow ) int32_t[2*dictionary_size_]; + if( !prev_pos_tree ) + { std::free( buffer ); delete[] prev_positions; throw std::bad_alloc(); } for( int i = 0; i < num_prev_positions; ++i ) prev_positions[i] = -1; } diff --git a/encoder.h b/encoder.h index 314bdcc..86c23c2 100644 --- a/encoder.h +++ b/encoder.h @@ -173,7 +173,7 @@ public: Matchfinder( const int dict_size, const int len_limit, const int ifd ); ~Matchfinder() - { delete[] prev_pos_tree; delete[] prev_positions; std::free( buffer ); } + { delete[] prev_pos_tree; std::free( buffer ); delete[] prev_positions; } uint8_t operator[]( const int i ) const throw() { return buffer[pos+i]; } int available_bytes() const throw() { return stream_pos - pos; } diff --git a/fast_encoder.cc b/fast_encoder.cc index 4574379..ba7c34c 100644 --- a/fast_encoder.cc +++ b/fast_encoder.cc @@ -60,12 +60,14 @@ Fmatchfinder::Fmatchfinder( const int ifd ) const int buffer_size_limit = ( 16 * dict_size ) + before_size + after_size; buffer_size = dict_size; buffer = (uint8_t *)std::malloc( buffer_size ); - if( !buffer ) throw std::bad_alloc(); + if( !buffer ) { delete[] prev_positions; throw std::bad_alloc(); } if( read_block() && !at_stream_end && buffer_size < buffer_size_limit ) { buffer_size = buffer_size_limit; - buffer = (uint8_t *)std::realloc( buffer, buffer_size ); - if( !buffer ) throw std::bad_alloc(); + uint8_t * const tmp = (uint8_t *)std::realloc( buffer, buffer_size ); + if( !tmp ) + { std::free( buffer ); delete[] prev_positions; throw std::bad_alloc(); } + buffer = tmp; read_block(); } if( at_stream_end && stream_pos < dict_size ) @@ -73,7 +75,9 @@ Fmatchfinder::Fmatchfinder( const int ifd ) else dictionary_size_ = dict_size; pos_limit = buffer_size; if( !at_stream_end ) pos_limit -= after_size; - prev_pos_chain = new int32_t[dictionary_size_]; + prev_pos_chain = new( std::nothrow ) int32_t[dictionary_size_]; + if( !prev_pos_chain ) + { std::free( buffer ); delete[] prev_positions; throw std::bad_alloc(); } for( int i = 0; i < num_prev_positions; ++i ) prev_positions[i] = -1; } diff --git a/lzip.h b/lzip.h index a580b3e..f789ba3 100644 --- a/lzip.h +++ b/lzip.h @@ -277,7 +277,7 @@ struct Error }; -// defined in main.cc lziprecover.cc +// defined in main.cc void show_error( const char * const msg, const int errcode = 0, const bool help = false ) throw(); void internal_error( const char * const msg ); diff --git a/lziprecover.cc b/lziprecover.cc deleted file mode 100644 index 8aded3f..0000000 --- a/lziprecover.cc +++ /dev/null @@ -1,790 +0,0 @@ -/* Lziprecover - Data recovery tool for lzip compressed files - Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/* - Return values: 0 for a normal exit, 1 for environmental problems - (file not found, invalid flags, I/O errors, etc), 2 to indicate a - corrupt or invalid input file, 3 for an internal consistency error - (eg, bug) which caused lziprecover to panic. -*/ - -#define _FILE_OFFSET_BITS 64 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__MSVCRT__) -#define S_IRGRP 0 -#define S_IWGRP 0 -#define S_IROTH 0 -#define S_IWOTH 0 -#endif - -#include "arg_parser.h" -#include "lzip.h" -#include "decoder.h" - -#if CHAR_BIT != 8 -#error "Environments where CHAR_BIT != 8 are not supported." -#endif - -#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 { - -const char * const Program_name = "Lziprecover"; -const char * const program_name = "lziprecover"; -const char * const program_year = "2011"; -const char * invocation_name = 0; - -#ifdef O_BINARY -const int o_binary = O_BINARY; -#else -const int o_binary = 0; -#endif - -int verbosity = 0; - - -class Block - { - long long pos_, size_; // pos + size <= LLONG_MAX - -public: - Block( const long long p, const long long s ) throw() - : pos_( p ), size_( s ) {} - - long long pos() const throw() { return pos_; } - long long size() const throw() { return size_; } - long long end() const throw() { return pos_ + size_; } - - void pos( const long long p ) throw() { pos_ = p; } - void size( const long long s ) throw() { size_ = s; } - void shift( Block & b ) throw() { ++size_; ++b.pos_; --b.size_; } - }; - - -void show_help() throw() - { - std::printf( "%s - Data recovery tool for lzip compressed files.\n", Program_name ); - std::printf( "\nUsage: %s [options] [files]\n", invocation_name ); - std::printf( "\nOptions:\n" ); - std::printf( " -h, --help display this help and exit\n" ); - std::printf( " -V, --version output version information and exit\n" ); -// std::printf( " -c, --create-recover-file create a recover file\n" ); - std::printf( " -f, --force overwrite existing output files\n" ); - std::printf( " -m, --merge correct errors in file using several copies\n" ); - std::printf( " -o, --output= place the output into \n" ); - std::printf( " -q, --quiet suppress all messages\n" ); -// std::printf( " -r, --recover correct errors in file using a recover file\n" ); - std::printf( " -R, --repair try to repair a small error in file\n" ); - std::printf( " -s, --split split a multimember file in single-member files\n" ); -// std::printf( " -u, --update convert file from version 0 to version 1\n" ); - std::printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" ); - std::printf( "\nReport bugs to lzip-bug@nongnu.org\n"); - std::printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" ); - } - - -void show_version() throw() - { - std::printf( "%s %s\n", Program_name, PROGVERSION ); - std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year ); - std::printf( "License GPLv3+: GNU GPL version 3 or later \n" ); - std::printf( "This is free software: you are free to change and redistribute it.\n" ); - std::printf( "There is NO WARRANTY, to the extent permitted by law.\n" ); - } - - -int open_instream( const std::string & input_filename ) throw() - { - int infd = open( input_filename.c_str(), O_RDONLY | o_binary ); - if( infd < 0 ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "%s: Can't open input file `%s': %s.\n", - program_name, input_filename.c_str(), std::strerror( errno ) ); - } - else - { - struct stat in_stats; - const int i = fstat( infd, &in_stats ); - if( i < 0 || !S_ISREG( in_stats.st_mode ) ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "%s: Input file `%s' is not a regular file.\n", - program_name, input_filename.c_str() ); - close( infd ); - infd = -1; - } - } - return infd; - } - - -int open_outstream( const std::string & output_filename, - const bool force ) throw() - { - int flags = O_CREAT | O_RDWR | o_binary; - if( force ) flags |= O_TRUNC; else flags |= O_EXCL; - - int outfd = open( output_filename.c_str(), flags, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); - if( outfd < 0 && verbosity >= 0 ) - { - if( errno == EEXIST ) - std::fprintf( stderr, "%s: Output file `%s' already exists." - " Use `--force' to overwrite it.\n", - program_name, output_filename.c_str() ); - else - std::fprintf( stderr, "%s: Can't create output file `%s': %s.\n", - program_name, output_filename.c_str(), std::strerror( errno ) ); - } - return outfd; - } - - -bool verify_header( const File_header & header ) - { - if( !header.verify_magic() ) - { - show_error( "Bad magic number (file not in lzip format)." ); - return false; - } - if( header.version() == 0 ) - { - show_error( "Version 0 member format can't be recovered." ); - return false; - } - if( header.version() != 1 ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "Version %d member format not supported.\n", - header.version() ); - return false; - } - return true; - } - - -bool verify_single_member( const int fd, const long long file_size ) - { - File_header header; - if( lseek( fd, 0, SEEK_SET ) < 0 || - readblock( fd, header.data, File_header::size ) != File_header::size ) - { show_error( "Error reading member header", errno ); return false; } - if( !verify_header( header ) ) return false; - - File_trailer trailer; - if( lseek( fd, -File_trailer::size(), SEEK_END ) < 0 || - readblock( fd, trailer.data, File_trailer::size() ) != File_trailer::size() ) - { show_error( "Error reading member trailer", errno ); return false; } - const long long member_size = trailer.member_size(); - if( member_size != file_size ) - { - if( member_size < file_size && - lseek( fd, -member_size, SEEK_END ) > 0 && - readblock( fd, header.data, File_header::size ) == File_header::size && - verify_header( header ) ) - show_error( "Input file has more than 1 member. Split it first." ); - else - show_error( "Member size in input file trailer is corrupt." ); - return false; - } - return true; - } - - -bool try_decompress( const int fd, const long long file_size, - long long * failure_pos = 0 ) - { - try { - Range_decoder rdec( fd ); - File_header header; - rdec.reset_member_position(); - for( int i = 0; i < File_header::size; ++i ) - header.data[i] = rdec.get_byte(); - if( !rdec.finished() && // End Of File - header.verify_magic() && - header.version() == 1 && - header.dictionary_size() >= min_dictionary_size && - header.dictionary_size() <= max_dictionary_size ) - { - LZ_decoder decoder( header, rdec, -1 ); - std::vector< std::string > dummy_filenames; - Pretty_print dummy( dummy_filenames, -1 ); - - if( decoder.decode_member( dummy ) == 0 && - rdec.member_position() == file_size ) return true; - if( failure_pos ) *failure_pos = rdec.member_position(); - } - } - catch( std::bad_alloc ) - { - show_error( "Not enough memory. Find a machine with more memory." ); - std::exit( 1 ); - } - catch( Error e ) {} - return false; - } - - -bool copy_and_diff_file( const std::vector< int > & infd_vector, - const int outfd, std::vector< Block > & block_vector ) - { - const int buffer_size = 65536; - std::vector< uint8_t * > buffer_vector( infd_vector.size() ); - for( unsigned int i = 0; i < infd_vector.size(); ++i ) - buffer_vector[i] = new uint8_t[buffer_size]; - Block b( 0, 0 ); - long long partial_pos = 0; - int equal_bytes = 0; - bool error = false; - - while( !error ) - { - const int rd = readblock( infd_vector[0], buffer_vector[0], buffer_size ); - if( rd != buffer_size && errno ) - { show_error( "Error reading input file", errno ); error = true; } - if( rd > 0 ) - { - for( unsigned int i = 1; i < infd_vector.size(); ++i ) - if( readblock( infd_vector[i], buffer_vector[i], rd ) != rd ) - { show_error( "Error reading input file", errno ); error = true; } - const int wr = writeblock( outfd, buffer_vector[0], rd ); - if( wr != rd ) - { show_error( "Error writing output file", errno ); error = true; } - for( int i = 0; i < rd; ++i ) - { - while( i < rd && b.pos() == 0 ) - { - for( unsigned int j = 1; j < infd_vector.size(); ++j ) - if( buffer_vector[0][i] != buffer_vector[j][i] ) - { b.pos( partial_pos + i ); break; } // begin block - ++i; - } - while( i < rd && b.pos() > 0 ) - { - ++equal_bytes; - for( unsigned int j = 1; j < infd_vector.size(); ++j ) - if( buffer_vector[0][i] != buffer_vector[j][i] ) - { equal_bytes = 0; break; } - if( equal_bytes >= 2 ) // end block - { - b.size( partial_pos + i - ( equal_bytes - 1 ) - b.pos() ); - block_vector.push_back( b ); - b.pos( 0 ); - equal_bytes = 0; - } - ++i; - } - } - partial_pos += rd; - } - if( rd < buffer_size ) break; // EOF - } - if( b.pos() > 0 ) // finish last block - { - b.size( partial_pos - b.pos() ); - block_vector.push_back( b ); - } - for( unsigned int i = 0; i < infd_vector.size(); ++i ) - delete[] buffer_vector[i]; - return !error; - } - - -bool copy_file( const int infd, const int outfd, - const long long size = LLONG_MAX ) - { - long long rest = size; - const int buffer_size = 65536; - uint8_t * const buffer = new uint8_t[buffer_size]; - bool error = false; - - while( !error ) - { - const int block_size = std::min( (long long)buffer_size, rest ); - if( block_size <= 0 ) break; - const int rd = readblock( infd, buffer, block_size ); - if( rd != block_size && errno ) - { show_error( "Error reading input file", errno ); error = true; } - if( rd > 0 ) - { - const int wr = writeblock( outfd, buffer, rd ); - if( wr != rd ) - { show_error( "Error writing output file", errno ); error = true; } - rest -= rd; - } - if( rd < block_size ) break; // EOF - } - delete[] buffer; - return !error; - } - - -std::string insert_fixed( std::string name ) throw() - { - if( name.size() > 4 && name.compare( name.size() - 4, 4, ".tlz" ) == 0 ) - name.insert( name.size() - 4, "_fixed" ); - else if( name.size() > 3 && name.compare( name.size() - 3, 3, ".lz" ) == 0 ) - name.insert( name.size() - 3, "_fixed" ); - else name += "_fixed.lz"; - return name; - } - - -int ipow( const unsigned int base, const unsigned int exponent ) throw() - { - int result = 1; - for( unsigned int i = 0; i < exponent; ++i ) - { - if( INT_MAX / base >= (unsigned int)result ) result *= base; - else { result = INT_MAX; break; } - } - return result; - } - - -int merge_files( const std::vector< std::string > & filenames, - const std::string & output_filename, const bool force ) - { - std::vector< int > infd_vector( filenames.size() ); - for( unsigned int i = 0; i < filenames.size(); ++i ) - { - infd_vector[i] = open_instream( filenames[i] ); - if( infd_vector[i] < 0 ) return 1; - } - long long isize = 0; - for( unsigned int i = 0; i < filenames.size(); ++i ) - { - const long long tmp = lseek( infd_vector[i], 0, SEEK_END ); - if( tmp < 0 ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "File `%s' is not seekable.\n", filenames[i].c_str() ); - return 1; - } - if( i == 0 ) isize = tmp; - else if( isize != tmp ) - { show_error( "Sizes of input files are different." ); return 1; } - } - if( isize < 36 ) - { show_error( "Input file is too short." ); return 2; } - for( unsigned int i = 0; i < filenames.size(); ++i ) - if( !verify_single_member( infd_vector[i], isize ) ) - return 2; - for( unsigned int i = 0; i < filenames.size(); ++i ) - if( lseek( infd_vector[i], 0, SEEK_SET ) < 0 ) - { show_error( "Seek error in input file", errno ); return 1; } - for( unsigned int i = 0; i < filenames.size(); ++i ) - if( try_decompress( infd_vector[i], isize ) ) - { - if( verbosity >= 1 ) - std::printf( "File `%s' has no errors. Recovery is not needed.\n", - filenames[i].c_str() ); - return 0; - } - - const int outfd = open_outstream( output_filename, force ); - if( outfd < 0 ) return 1; - for( unsigned int i = 0; i < filenames.size(); ++i ) - if( lseek( infd_vector[i], 0, SEEK_SET ) < 0 ) - { show_error( "Seek error in input file", errno ); return 1; } - - // vector of data blocks differing among the copies of the input file. - std::vector< Block > block_vector; - if( !copy_and_diff_file( infd_vector, outfd, block_vector ) ) return 1; - - if( !block_vector.size() ) - { show_error( "Input files are identical. Recovery is not possible." ); - return 1; } - - const bool single_block = ( block_vector.size() == 1 ); - if( single_block && block_vector[0].size() < 2 ) - { show_error( "Input files have the same byte damaged." - " Try repairing one of them." ); - return 1; } - - if( ipow( filenames.size(), block_vector.size() ) >= INT_MAX || - ( single_block && - ipow( filenames.size(), 2 ) >= INT_MAX / block_vector[0].size() ) ) - { show_error( "Input files are too damaged. Recovery is not possible." ); - return 1; } - - const int shifts = ( single_block ? block_vector[0].size() - 1 : 1 ); - if( single_block ) - { - Block b( block_vector[0].pos() + 1, block_vector[0].size() - 1 ); - block_vector[0].size( 1 ); - block_vector.push_back( b ); - } - - const int base_variations = ipow( filenames.size(), block_vector.size() ); - const int variations = ( base_variations * shifts ) - 2; - bool done = false; - for( int var = 1; var <= variations; ++var ) - { - if( verbosity >= 1 ) - { - std::printf( "Trying variation %d of %d \r", var, variations ); - std::fflush( stdout ); - } - int tmp = var; - for( unsigned int i = 0; i < block_vector.size(); ++i ) - { - const int infd = infd_vector[tmp % filenames.size()]; - tmp /= filenames.size(); - if( lseek( infd, block_vector[i].pos(), SEEK_SET ) < 0 || - lseek( outfd, block_vector[i].pos(), SEEK_SET ) < 0 || - !copy_file( infd, outfd, block_vector[i].size() ) ) - { show_error( "Error reading output file", errno ); return 1; } - } - if( lseek( outfd, 0, SEEK_SET ) < 0 ) - { show_error( "Seek error in output file", errno ); return 1; } - if( try_decompress( outfd, isize ) ) - { done = true; break; } - if( var % base_variations == 0 ) block_vector[0].shift( block_vector[1] ); - } - if( verbosity >= 1 ) std::printf( "\n" ); - - if( close( outfd ) != 0 ) - { show_error( "Error closing output file", errno ); return 1; } - if( done ) - { - if( verbosity >= 1 ) - std::printf( "Input files merged successfully.\n" ); - return 0; - } - else - { - std::remove( output_filename.c_str() ); - show_error( "Some error areas overlap. Can't recover input file." ); - return 2; - } - } - - -int repair_file( const std::string & input_filename, - const std::string & output_filename, const bool force ) - { - const int infd = open_instream( input_filename ); - if( infd < 0 ) return 1; - const long long isize = lseek( infd, 0, SEEK_END ); - if( isize < 0 ) - { show_error( "Input file is not seekable", errno ); return 1; } - if( isize < 36 ) - { show_error( "Input file is too short." ); return 2; } - if( !verify_single_member( infd, isize ) ) return 2; - if( lseek( infd, 0, SEEK_SET ) < 0 ) - { show_error( "Seek error in input file", errno ); return 1; } - long long failure_pos = 0; - if( try_decompress( infd, isize, &failure_pos ) ) - { - if( verbosity >= 1 ) - std::printf( "Input file has no errors. Recovery is not needed.\n" ); - return 0; - } - if( failure_pos >= isize - 8 ) failure_pos = isize - 8 - 1; - if( failure_pos < File_header::size ) - { show_error( "Can't repair error in input file." ); return 2; } - - const int outfd = open_outstream( output_filename, force ); - if( outfd < 0 ) { close( infd ); return 1; } - if( lseek( infd, 0, SEEK_SET ) < 0 ) - { show_error( "Seek error in input file", errno ); return 1; } - if( !copy_file( infd, outfd ) ) return 1; - - const long long min_pos = - std::max( (long long)File_header::size, failure_pos - 1000 ); - bool done = false; - for( long long pos = failure_pos; pos >= min_pos; --pos ) - { - if( verbosity >= 1 ) - { - std::printf( "Trying position %lld \r", pos ); - std::fflush( stdout ); - } - uint8_t byte; - if( lseek( outfd, pos, SEEK_SET ) < 0 || - readblock( outfd, &byte, 1 ) != 1 ) - { show_error( "Error reading output file", errno ); return 1; } - for( int i = 0; i < 255; ++i ) - { - ++byte; - if( lseek( outfd, pos, SEEK_SET ) < 0 || - writeblock( outfd, &byte, 1 ) != 1 || - lseek( outfd, 0, SEEK_SET ) < 0 ) - { show_error( "Error writing output file", errno ); return 1; } - if( try_decompress( outfd, isize ) ) - { done = true; break; } - } - if( done ) break; - ++byte; - if( lseek( outfd, pos, SEEK_SET ) < 0 || - writeblock( outfd, &byte, 1 ) != 1 ) - { show_error( "Error writing output file", errno ); return 1; } - } - if( verbosity >= 1 ) std::printf( "\n" ); - - if( close( outfd ) != 0 ) - { show_error( "Error closing output file", errno ); return 1; } - if( done ) - { - if( verbosity >= 1 ) - std::printf( "Copy of input file repaired successfully.\n" ); - return 0; - } - else - { - std::remove( output_filename.c_str() ); - show_error( "Error is larger than 1 byte. Can't repair input file." ); - return 2; - } - } - - -bool next_filename( std::string & output_filename ) - { - for( int i = 7; i >= 3; --i ) // "rec00001" - { - if( output_filename[i] < '9' ) { ++output_filename[i]; return true; } - else output_filename[i] = '0'; - } - return false; - } - - -int do_split_file( const std::string & input_filename, uint8_t * & base_buffer, - const std::string & default_output_filename, const bool force ) - { - const int hsize = File_header::size; - const int tsize = File_trailer::size(); - const int buffer_size = 65536; - const int base_buffer_size = tsize + buffer_size + hsize; - base_buffer = new uint8_t[base_buffer_size]; - uint8_t * const buffer = base_buffer + tsize; - - const int infd = open_instream( input_filename ); - if( infd < 0 ) return 1; - int size = readblock( infd, buffer, buffer_size + hsize ) - hsize; - bool at_stream_end = ( size < buffer_size ); - if( size != buffer_size && errno ) - { show_error( "Read error", errno ); return 1; } - if( size <= tsize ) - { show_error( "Input file is too short." ); return 2; } - File_header header; - for( int i = 0; i < File_header::size; ++i ) - header.data[i] = buffer[i]; - if( !verify_header( header ) ) return 2; - - std::string output_filename( "rec00001" ); - output_filename += default_output_filename; - int outfd = open_outstream( output_filename, force ); - if( outfd < 0 ) { close( infd ); return 1; } - - long long partial_member_size = 0; - while( true ) - { - int pos = 0; - for( int newpos = 1; newpos <= size; ++newpos ) - if( buffer[newpos] == magic_string[0] && - buffer[newpos+1] == magic_string[1] && - buffer[newpos+2] == magic_string[2] && - buffer[newpos+3] == magic_string[3] ) - { - long long member_size = 0; - for( int i = 1; i <= 8; ++i ) - { member_size <<= 8; member_size += base_buffer[tsize+newpos-i]; } - if( partial_member_size + newpos - pos == member_size ) - { // header found - const int wr = writeblock( outfd, buffer + pos, newpos - pos ); - if( wr != newpos - pos ) - { show_error( "Write error", errno ); return 1; } - if( close( outfd ) != 0 ) - { show_error( "Error closing output file", errno ); return 1; } - if( !next_filename( output_filename ) ) - { show_error( "Too many members in file." ); close( infd ); return 1; } - outfd = open_outstream( output_filename, force ); - if( outfd < 0 ) { close( infd ); return 1; } - partial_member_size = 0; - pos = newpos; - } - } - - if( at_stream_end ) - { - const int wr = writeblock( outfd, buffer + pos, size + hsize - pos ); - if( wr != size + hsize - pos ) - { show_error( "Write error", errno ); return 1; } - break; - } - if( pos < buffer_size ) - { - partial_member_size += buffer_size - pos; - const int wr = writeblock( outfd, buffer + pos, buffer_size - pos ); - if( wr != buffer_size - pos ) - { show_error( "Write error", errno ); return 1; } - } - std::memcpy( base_buffer, base_buffer + buffer_size, tsize + hsize ); - size = readblock( infd, buffer + hsize, buffer_size ); - at_stream_end = ( size < buffer_size ); - if( size != buffer_size && errno ) - { show_error( "Read error", errno ); return 1; } - } - close( infd ); - if( close( outfd ) != 0 ) - { show_error( "Error closing output file", errno ); return 1; } - return 0; - } - - -int split_file( const std::string & input_filename, - const std::string & default_output_filename, const bool force ) - { - uint8_t * base_buffer; - const int retval = do_split_file( input_filename, base_buffer, - default_output_filename, force ); - delete[] base_buffer; - return retval; - } - -} // end namespace - - -void show_error( const char * const msg, const int errcode, const bool help ) throw() - { - if( verbosity >= 0 ) - { - if( msg && msg[0] ) - { - std::fprintf( stderr, "%s: %s", program_name, msg ); - if( errcode > 0 ) - std::fprintf( stderr, ": %s", std::strerror( errcode ) ); - std::fprintf( stderr, "\n" ); - } - if( help && invocation_name && invocation_name[0] ) - std::fprintf( stderr, "Try `%s --help' for more information.\n", - invocation_name ); - } - } - - -void internal_error( const char * const msg ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "%s: internal error: %s.\n", program_name, msg ); - std::exit( 3 ); - } - - -int main( const int argc, const char * const argv[] ) - { - enum Mode - { m_none, m_create, m_merge, m_recover, m_repair, m_split, m_update }; - Mode program_mode = m_none; - bool force = false; - std::string default_output_filename; - invocation_name = argv[0]; - - const Arg_parser::Option options[] = - { - { 'f', "force", Arg_parser::no }, - { 'h', "help", Arg_parser::no }, - { 'm', "merge", Arg_parser::no }, - { 'o', "output", Arg_parser::yes }, - { 'q', "quiet", Arg_parser::no }, - { 'R', "repair", Arg_parser::no }, - { 's', "split", Arg_parser::no }, - { 'v', "verbose", Arg_parser::no }, - { 'V', "version", Arg_parser::no }, - { 0 , 0, Arg_parser::no } }; - - 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 - switch( code ) - { - case 'f': force = true; break; - case 'h': show_help(); return 0; - case 'm': program_mode = m_merge; break; - case 'o': default_output_filename = parser.argument( argind ); break; - case 'q': verbosity = -1; break; - case 'R': program_mode = m_repair; break; - case 's': program_mode = m_split; break; - case 'v': if( verbosity < 4 ) ++verbosity; break; - case 'V': show_version(); return 0; - default : internal_error( "uncaught option" ); - } - } - - if( program_mode == m_merge ) - { - std::vector< std::string > filenames; - for( ; argind < parser.arguments(); ++argind ) - filenames.push_back( parser.argument( argind ) ); - if( filenames.size() < 2 ) - { show_error( "You must specify at least 2 files.", 0, true ); return 1; } - if( !default_output_filename.size() ) - default_output_filename = insert_fixed( filenames[0] ); - return merge_files( filenames, default_output_filename, force ); - } - - if( argind + 1 != parser.arguments() ) - { show_error( "You must specify exactly 1 file.", 0, true ); return 1; } - - if( program_mode == m_repair ) - { - if( !default_output_filename.size() ) - default_output_filename = insert_fixed( parser.argument( argind ) ); - return repair_file( parser.argument( argind ), default_output_filename, force ); - } - - if( program_mode == m_split ) - { - if( !default_output_filename.size() ) - default_output_filename = parser.argument( argind ); - return split_file( parser.argument( argind ), default_output_filename, force ); - } - - show_error( "You must specify the operation to be performed on file.", - 0, true ); - return 1; - } diff --git a/main.cc b/main.cc index c23b3bc..2de410b 100644 --- a/main.cc +++ b/main.cc @@ -102,7 +102,9 @@ enum Mode { m_compress, m_decompress, m_test }; std::string output_filename; int outfd = -1; int verbosity = 0; -mode_t outfd_mode = S_IRUSR | S_IWUSR; +const mode_t usr_rw = S_IRUSR | S_IWUSR; +const mode_t all_rw = usr_rw | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; +mode_t outfd_mode = usr_rw; bool delete_output_on_interrupt = false; @@ -110,31 +112,31 @@ void show_help() throw() { std::printf( "%s - Data compressor based on the LZMA algorithm.\n", Program_name ); std::printf( "\nUsage: %s [options] [files]\n", invocation_name ); - std::printf( "\nOptions:\n" ); - std::printf( " -h, --help display this help and exit\n" ); - std::printf( " -V, --version output version information and exit\n" ); - std::printf( " -b, --member-size= set member size limit in bytes\n" ); - std::printf( " -c, --stdout send output to standard output\n" ); - std::printf( " -d, --decompress decompress\n" ); - std::printf( " -f, --force overwrite existing output files\n" ); - std::printf( " -F, --recompress force recompression of compressed files\n" ); - std::printf( " -k, --keep keep (don't delete) input files\n" ); - std::printf( " -m, --match-length= set match length limit in bytes [36]\n" ); - std::printf( " -o, --output= if reading stdin, place the output into \n" ); - std::printf( " -q, --quiet suppress all messages\n" ); - std::printf( " -s, --dictionary-size= set dictionary size limit in bytes [8MiB]\n" ); - std::printf( " -S, --volume-size= set volume size limit in bytes\n" ); - std::printf( " -t, --test test compressed file integrity\n" ); - std::printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" ); - std::printf( " -0 .. -9 set compression level [default 6]\n" ); - std::printf( " --fast alias for -0\n" ); - std::printf( " --best alias for -9\n" ); - std::printf( "If no file names are given, %s compresses or decompresses\n", program_name ); - std::printf( "from standard input to standard output.\n" ); - std::printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" ); - std::printf( "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" ); - std::printf( "\nReport bugs to lzip-bug@nongnu.org\n" ); - std::printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" ); + std::printf( "\nOptions:\n" + " -h, --help display this help and exit\n" + " -V, --version output version information and exit\n" + " -b, --member-size= set member size limit in bytes\n" + " -c, --stdout send output to standard output\n" + " -d, --decompress decompress\n" + " -f, --force overwrite existing output files\n" + " -F, --recompress force recompression of compressed files\n" + " -k, --keep keep (don't delete) input files\n" + " -m, --match-length= set match length limit in bytes [36]\n" + " -o, --output= if reading stdin, place the output into \n" + " -q, --quiet suppress all messages\n" + " -s, --dictionary-size= set dictionary size limit in bytes [8MiB]\n" + " -S, --volume-size= set volume size limit in bytes\n" + " -t, --test test compressed file integrity\n" + " -v, --verbose be verbose (a 2nd -v gives more)\n" + " -0 .. -9 set compression level [default 6]\n" + " --fast alias for -0\n" + " --best alias for -9\n" + "If no file names are given, lzip compresses or decompresses\n" + "from standard input to standard output.\n" + "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" + "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" + "\nReport bugs to lzip-bug@nongnu.org\n" + "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" ); } @@ -142,9 +144,9 @@ void show_version() throw() { std::printf( "%s %s\n", Program_name, PROGVERSION ); std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year ); - std::printf( "License GPLv3+: GNU GPL version 3 or later \n" ); - std::printf( "This is free software: you are free to change and redistribute it.\n" ); - std::printf( "There is NO WARRANTY, to the extent permitted by law.\n" ); + std::printf( "License GPLv3+: GNU GPL version 3 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n" ); } @@ -155,10 +157,11 @@ const char * format_num( long long num ) throw() enum { buf_size = 16, factor = 1024 }; static char buf[buf_size]; const char *p = ""; + bool exact = ( num % factor == 0 ); for( int i = 0; i < 8 && ( llabs( num ) > 9999 || - ( llabs( num ) >= factor && num % factor == 0 ) ); ++i ) - { num /= factor; p = prefix[i]; } + ( exact && llabs( num ) >= factor ) ); ++i ) + { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; } snprintf( buf, buf_size, "%lld %s", num, p ); return buf; } @@ -369,31 +372,26 @@ void cleanup_and_fail( const int retval ) throw() // Set permissions, owner and times. void close_and_set_permissions( const struct stat * const in_statsp ) { - bool error = false; + bool warning = false; if( in_statsp ) { + // fchown will in many cases return with EPERM, which can be safely ignored. if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 && errno != EPERM ) || - fchmod( outfd, in_statsp->st_mode ) != 0 ) - error = true; - // fchown will in many cases return with EPERM, which can be safely ignored. + fchmod( outfd, in_statsp->st_mode ) != 0 ) warning = true; } - if( close( outfd ) == 0 ) outfd = -1; - else cleanup_and_fail( 1 ); + if( close( outfd ) != 0 ) cleanup_and_fail( 1 ); + outfd = -1; delete_output_on_interrupt = false; - if( !in_statsp ) return; - if( !error ) + if( in_statsp ) { struct utimbuf t; t.actime = in_statsp->st_atime; t.modtime = in_statsp->st_mtime; - if( utime( output_filename.c_str(), &t ) != 0 ) error = true; + if( utime( output_filename.c_str(), &t ) != 0 ) warning = true; } - if( error ) - { + if( warning && verbosity >= 1 ) show_error( "Can't change output file attributes." ); - cleanup_and_fail( 1 ); - } } @@ -852,7 +850,7 @@ int main( const int argc, const char * const argv[] ) if( program_mode == m_compress ) set_c_outname( default_output_filename, volume_size != LLONG_MAX ); else output_filename = default_output_filename; - outfd_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + outfd_mode = all_rw; if( !open_outstream( force ) ) { if( outfd == -1 && retval < 1 ) retval = 1; @@ -877,7 +875,7 @@ int main( const int argc, const char * const argv[] ) if( program_mode == m_compress ) set_c_outname( input_filename, volume_size != LLONG_MAX ); else set_d_outname( input_filename, eindex ); - outfd_mode = S_IRUSR | S_IWUSR; + outfd_mode = usr_rw; if( !open_outstream( force ) ) { if( outfd == -1 && retval < 1 ) retval = 1; diff --git a/testsuite/check.sh b/testsuite/check.sh index 82bc47d..69291e2 100755 --- a/testsuite/check.sh +++ b/testsuite/check.sh @@ -10,26 +10,22 @@ export LC_ALL objdir=`pwd` testdir=`cd "$1" ; pwd` LZIP="${objdir}"/lzip -LZIPRECOVER="${objdir}"/lziprecover framework_failure() { echo "failure in testing framework" ; exit 1 ; } if [ ! -x "${LZIP}" ] ; then echo "${LZIP}: cannot execute" exit 1 fi -if [ ! -x "${LZIPRECOVER}" ] ; then - echo "${LZIPRECOVER}: cannot execute" - exit 1 -fi if [ -d tmp ] ; then rm -rf tmp ; fi mkdir tmp -printf "testing lzip-%s..." "$2" cd "${objdir}"/tmp cat "${testdir}"/test.txt > in || framework_failure fail=0 +printf "testing lzip-%s..." "$2" + "${LZIP}" -t "${testdir}"/test_v0.lz || fail=1 printf . "${LZIP}" -cd "${testdir}"/test_v0.lz > copy || fail=1 @@ -48,7 +44,7 @@ printf . cmp in copy || fail=1 printf . -"${LZIP}" -cf "${testdir}"/test_v1.lz > out 2>/dev/null +"${LZIP}" -cfq "${testdir}"/test_v1.lz > out if [ $? != 1 ] ; then fail=1 ; printf - ; else printf . ; fi "${LZIP}" -cF "${testdir}"/test_v1.lz > out || fail=1 "${LZIP}" -cd out | "${LZIP}" -d > copy || fail=1 @@ -91,70 +87,6 @@ done cmp in anyothername.out || fail=1 printf . -# Description of test files for lziprecover: -# test_bad1.lz: byte at offset 67 changed from 0xCC to 0x33 -# test_bad2.lz: [ 34- 66) --> copy of bytes [ 68- 100) -# test_bad3.lz: [ 512-1536) --> zeroed; [2560-3584) --> zeroed -# test_bad4.lz: [3072-4096) --> random data; [4608-5632) --> zeroed -# test_bad5.lz: [1024-2048) --> random data; [5120-6144) --> random data - -printf "\ntesting lziprecover-%s..." "$2" - -"${LZIP}" -c in in in > out || fail=1 -printf "garbage" >> out || fail=1 -"${LZIPRECOVER}" -s out -o out.lz || fail=1 -for i in 1 2 3 ; do - "${LZIP}" -cd rec0000${i}out.lz > copy || fail=1 - cmp in copy || fail=1 - printf . -done - -"${LZIP}" -0kf -$i in || fail=1 -"${LZIPRECOVER}" -R in.lz || fail=1 -printf . -"${LZIPRECOVER}" -R "${testdir}"/test_v1.lz || fail=1 -printf . - -"${LZIPRECOVER}" -R -o copy.lz "${testdir}"/test_bad1.lz || fail=1 -"${LZIP}" -df copy.lz || fail=1 -cmp in copy || fail=1 -printf . - -"${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad1.lz "${testdir}"/test_bad2.lz || fail=1 -"${LZIP}" -df copy.lz || fail=1 -cmp in copy || fail=1 -printf . -"${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad2.lz "${testdir}"/test_bad1.lz || fail=1 -"${LZIP}" -df copy.lz || fail=1 -cmp in copy || fail=1 -printf . - -for i in 1 2 ; do - for j in 3 4 5 ; do - "${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad${i}.lz "${testdir}"/test_bad${j}.lz || fail=1 - "${LZIP}" -df copy.lz || fail=1 - cmp in copy || fail=1 - printf . - "${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad${j}.lz "${testdir}"/test_bad${i}.lz || fail=1 - "${LZIP}" -df copy.lz || fail=1 - cmp in copy || fail=1 - printf . - done -done - -"${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad3.lz "${testdir}"/test_bad4.lz "${testdir}"/test_bad5.lz || fail=1 -"${LZIP}" -df copy.lz || fail=1 -cmp in copy || fail=1 -printf . -"${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad4.lz "${testdir}"/test_bad5.lz "${testdir}"/test_bad3.lz || fail=1 -"${LZIP}" -df copy.lz || fail=1 -cmp in copy || fail=1 -printf . -"${LZIPRECOVER}" -m -o copy.lz "${testdir}"/test_bad5.lz "${testdir}"/test_bad3.lz "${testdir}"/test_bad4.lz || fail=1 -"${LZIP}" -df copy.lz || fail=1 -cmp in copy || fail=1 -printf . - echo if [ ${fail} = 0 ] ; then echo "tests completed successfully." diff --git a/testsuite/test_bad1.lz b/testsuite/test_bad1.lz deleted file mode 100644 index 0b84883..0000000 Binary files a/testsuite/test_bad1.lz and /dev/null differ diff --git a/testsuite/test_bad2.lz b/testsuite/test_bad2.lz deleted file mode 100644 index cce6a3c..0000000 Binary files a/testsuite/test_bad2.lz and /dev/null differ diff --git a/testsuite/test_bad3.lz b/testsuite/test_bad3.lz deleted file mode 100644 index a1676bb..0000000 Binary files a/testsuite/test_bad3.lz and /dev/null differ diff --git a/testsuite/test_bad4.lz b/testsuite/test_bad4.lz deleted file mode 100644 index a8f89a3..0000000 Binary files a/testsuite/test_bad4.lz and /dev/null differ diff --git a/testsuite/test_bad5.lz b/testsuite/test_bad5.lz deleted file mode 100644 index 73e0142..0000000 Binary files a/testsuite/test_bad5.lz and /dev/null differ diff --git a/testsuite/unzcrash.cc b/testsuite/unzcrash.cc index 5fac783..b80580f 100644 --- a/testsuite/unzcrash.cc +++ b/testsuite/unzcrash.cc @@ -58,22 +58,22 @@ int verbosity = 0; void show_help() throw() { std::printf( "%s - A test program written to test robustness to\n", Program_name ); - std::printf( "decompression of corrupted data.\n" ); - std::printf( "\nUsage: %s [options] \"lzip -tv\" filename.lz\n", invocation_name ); - std::printf( "\nThis program reads the specified file and then repeatedly decompresses\n" ); - std::printf( "it, increasing 256 times each byte of the compressed data, so as to test\n" ); - std::printf( "all possible one-byte errors. This should not cause any invalid memory\n" ); - std::printf( "accesses. If it does, please, report it as a bug.\n" ); - std::printf( "\nOptions:\n" ); - std::printf( " -h, --help display this help and exit\n" ); - std::printf( " -V, --version output version information and exit\n" ); - std::printf( " -b, --bits=[,n] test -bit errors instead of full byte\n" ); - std::printf( " -p, --position= first byte position to test\n" ); - std::printf( " -q, --quiet suppress all messages\n" ); - std::printf( " -s, --size= number of byte positions to test\n" ); - std::printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" ); - std::printf( "\nReport bugs to lzip-bug@nongnu.org\n" ); - std::printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" ); + std::printf( "decompression of corrupted data.\n" + "\nUsage: %s [options] \"lzip -tv\" filename.lz\n", invocation_name ); + std::printf( "\nThis program reads the specified file and then repeatedly decompresses\n" + "it, increasing 256 times each byte of the compressed data, so as to test\n" + "all possible one-byte errors. This should not cause any invalid memory\n" + "accesses. If it does, please, report it as a bug.\n" + "\nOptions:\n" + " -h, --help display this help and exit\n" + " -V, --version output version information and exit\n" + " -b, --bits=[,]... test -bit errors instead of full byte\n" + " -p, --position= first byte position to test\n" + " -q, --quiet suppress all messages\n" + " -s, --size= number of byte positions to test\n" + " -v, --verbose be verbose (a 2nd -v gives more)\n" + "\nReport bugs to lzip-bug@nongnu.org\n" + "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" ); } @@ -81,9 +81,9 @@ void show_version() throw() { std::printf( "%s %s\n", Program_name, PROGVERSION ); std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year ); - std::printf( "License GPLv3+: GNU GPL version 3 or later \n" ); - std::printf( "This is free software: you are free to change and redistribute it.\n" ); - std::printf( "There is NO WARRANTY, to the extent permitted by law.\n" ); + std::printf( "License GPLv3+: GNU GPL version 3 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n" ); } -- cgit v1.2.3