1
0
Fork 0

Adding upstream version 1.2~pre2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 05:45:13 +01:00
parent 2ee9737b93
commit c9a98be648
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
22 changed files with 804 additions and 87 deletions

View file

@ -1,3 +1,8 @@
2013-09-04 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.2-pre2 released.
* Added new utility; zupdate.
2013-08-02 Antonio Diaz Diaz <antonio@gnu.org> 2013-08-02 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.1 released. * Version 1.1 released.

View file

@ -1,6 +1,7 @@
Requirements Requirements
------------ ------------
You will need a C++ compiler. You will need a C++ compiler, (de)compressors for bzip2 and gzip
formats, and a compressor for the lzip format.
I use gcc 4.8.1 and 3.3.6, but the code should compile with any I use gcc 4.8.1 and 3.3.6, but the code should compile with any
standards compliant compiler. standards compliant compiler.
Gcc is available at http://gcc.gnu.org. Gcc is available at http://gcc.gnu.org.

View file

@ -10,6 +10,7 @@ SHELL = /bin/sh
objs = arg_parser.o rc.o zutils.o main.o objs = arg_parser.o rc.o zutils.o main.o
zcmp_objs = arg_parser.o rc.o zutils.o zcmp.o zcmp_objs = arg_parser.o rc.o zutils.o zcmp.o
zdiff_objs = arg_parser.o rc.o zutils.o zdiff.o zdiff_objs = arg_parser.o rc.o zutils.o zdiff.o
zupdate_objs = arg_parser.o rc.o zutils.o zupdate.o
scripts = zcat zegrep zfgrep zgrep ztest scripts = zcat zegrep zfgrep zgrep ztest
@ -17,7 +18,7 @@ scripts = zcat zegrep zfgrep zgrep ztest
uninstall uninstall-bin uninstall-info uninstall-man \ uninstall uninstall-bin uninstall-info uninstall-man \
doc info man check dist clean distclean doc info man check dist clean distclean
all : $(progname) zcmp zdiff $(scripts) all : $(progname) zcmp zdiff zupdate $(scripts)
$(progname) : $(objs) $(progname) : $(objs)
$(CXX) $(LDFLAGS) -o $@ $(objs) $(CXX) $(LDFLAGS) -o $@ $(objs)
@ -51,6 +52,9 @@ ztest : ztest.in
cat $(VPATH)/ztest.in > $@ cat $(VPATH)/ztest.in > $@
chmod a+x ztest chmod a+x ztest
zupdate : $(zupdate_objs)
$(CXX) $(LDFLAGS) -o $@ $(zupdate_objs)
main.o : main.cc main.o : main.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DGREP=\"$(GREP)\" -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DGREP=\"$(GREP)\" -c -o $@ $<
@ -73,6 +77,7 @@ main.o : arg_parser.h zutils.h rc.h zcat.cc zgrep.cc ztest.cc
rc.o : arg_parser.h zutils.h rc.h rc.o : arg_parser.h zutils.h rc.h
zcmp.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile zcmp.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile
zdiff.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile zdiff.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile
zupdate.o : arg_parser.h zutils.h rc.h Makefile
zutils.o : zutils.h rc.h zutils.o : zutils.h rc.h
@ -84,7 +89,7 @@ $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zcmp.1 $(VPATH)/doc/zdiff.1 \ man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zcmp.1 $(VPATH)/doc/zdiff.1 \
$(VPATH)/doc/zgrep.1 $(VPATH)/doc/ztest.1 $(VPATH)/doc/zgrep.1 $(VPATH)/doc/ztest.1 $(VPATH)/doc/zupdate.1
$(VPATH)/doc/zcat.1 : $(progname) zcat $(VPATH)/doc/zcat.1 : $(progname) zcat
help2man -n 'decompress and concatenate files to standard output' \ help2man -n 'decompress and concatenate files to standard output' \
@ -106,6 +111,10 @@ $(VPATH)/doc/ztest.1 : $(progname) ztest
help2man -n 'verify integrity of compressed files' \ help2man -n 'verify integrity of compressed files' \
-o $@ --no-info ./ztest -o $@ --no-info ./ztest
$(VPATH)/doc/zupdate.1 : zupdate
help2man -n 'recompress bzip2, gzip, xz files to lzip files' \
-o $@ --no-info ./zupdate
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
./config.status ./config.status
@ -124,6 +133,7 @@ install-bin : all
$(INSTALL_SCRIPT) ./zfgrep "$(DESTDIR)$(bindir)/zfgrep" $(INSTALL_SCRIPT) ./zfgrep "$(DESTDIR)$(bindir)/zfgrep"
$(INSTALL_SCRIPT) ./zgrep "$(DESTDIR)$(bindir)/zgrep" $(INSTALL_SCRIPT) ./zgrep "$(DESTDIR)$(bindir)/zgrep"
$(INSTALL_SCRIPT) ./ztest "$(DESTDIR)$(bindir)/ztest" $(INSTALL_SCRIPT) ./ztest "$(DESTDIR)$(bindir)/ztest"
$(INSTALL_PROGRAM) ./zupdate "$(DESTDIR)$(bindir)/zupdate"
if [ ! -e "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ] ; then \ if [ ! -e "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ] ; then \
if [ ! -d "$(DESTDIR)$(sysconfdir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)" ; fi ; \ if [ ! -d "$(DESTDIR)$(sysconfdir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)" ; fi ; \
$(INSTALL_DATA) $(VPATH)/$(pkgname)rc "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ; \ $(INSTALL_DATA) $(VPATH)/$(pkgname)rc "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ; \
@ -141,6 +151,7 @@ install-man :
$(INSTALL_DATA) $(VPATH)/doc/zdiff.1 "$(DESTDIR)$(mandir)/man1/zdiff.1" $(INSTALL_DATA) $(VPATH)/doc/zdiff.1 "$(DESTDIR)$(mandir)/man1/zdiff.1"
$(INSTALL_DATA) $(VPATH)/doc/zgrep.1 "$(DESTDIR)$(mandir)/man1/zgrep.1" $(INSTALL_DATA) $(VPATH)/doc/zgrep.1 "$(DESTDIR)$(mandir)/man1/zgrep.1"
$(INSTALL_DATA) $(VPATH)/doc/ztest.1 "$(DESTDIR)$(mandir)/man1/ztest.1" $(INSTALL_DATA) $(VPATH)/doc/ztest.1 "$(DESTDIR)$(mandir)/man1/ztest.1"
$(INSTALL_DATA) $(VPATH)/doc/zupdate.1 "$(DESTDIR)$(mandir)/man1/zupdate.1"
install-strip : all install-strip : all
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
@ -156,6 +167,7 @@ uninstall-bin :
-rm -f "$(DESTDIR)$(bindir)/zfgrep" -rm -f "$(DESTDIR)$(bindir)/zfgrep"
-rm -f "$(DESTDIR)$(bindir)/zgrep" -rm -f "$(DESTDIR)$(bindir)/zgrep"
-rm -f "$(DESTDIR)$(bindir)/ztest" -rm -f "$(DESTDIR)$(bindir)/ztest"
-rm -f "$(DESTDIR)$(bindir)/zupdate"
-rm -f "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" -rm -f "$(DESTDIR)$(sysconfdir)/$(pkgname)rc"
uninstall-info : uninstall-info :
@ -168,6 +180,7 @@ uninstall-man :
-rm -f "$(DESTDIR)$(mandir)/man1/zdiff.1" -rm -f "$(DESTDIR)$(mandir)/man1/zdiff.1"
-rm -f "$(DESTDIR)$(mandir)/man1/zgrep.1" -rm -f "$(DESTDIR)$(mandir)/man1/zgrep.1"
-rm -f "$(DESTDIR)$(mandir)/man1/ztest.1" -rm -f "$(DESTDIR)$(mandir)/man1/ztest.1"
-rm -f "$(DESTDIR)$(mandir)/man1/zupdate.1"
dist : doc dist : doc
ln -sf $(VPATH) $(DISTNAME) ln -sf $(VPATH) $(DISTNAME)
@ -195,7 +208,7 @@ dist : doc
clean : clean :
-rm -f $(progname) $(progname)_profiled $(objs) -rm -f $(progname) $(progname)_profiled $(objs)
-rm -f zcmp zcmp.o zdiff zdiff.o $(scripts) -rm -f zcmp zcmp.o zdiff zdiff.o zupdate zupdate.o $(scripts)
distclean : clean distclean : clean
-rm -f Makefile config.status *.tar *.tar.lz -rm -f Makefile config.status *.tar *.tar.lz

14
NEWS
View file

@ -1,12 +1,4 @@
Changes in version 1.1: Changes in version 1.2:
The new options "--bz2", "--gz", "--lz" and "--xz" have been added to The new utility zupdate, which recompresses bzip2, gzip and xz files to
all utilities. lzip format, has been added.
Zutils now provides the runtime configuration file "zutilsrc", which
allows the user change the compressor to be used for each format.
The checking of the exit status of compressors has been improved.
The use of "decompressed" and "uncompressed" in the documentation has
been revised.

View file

@ -156,12 +156,12 @@ Arg_parser::Arg_parser( const int argc, const char * const argv[],
while( argind < argc ) while( argind < argc )
{ {
const unsigned char ch1 = argv[argind][0]; const unsigned char ch1 = argv[argind][0];
const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 ); const unsigned char ch2 = ch1 ? argv[argind][1] : 0;
if( ch1 == '-' && ch2 ) // we found an option if( ch1 == '-' && ch2 ) // we found an option
{ {
const char * const opt = argv[argind]; const char * const opt = argv[argind];
const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0; const char * const arg = ( argind + 1 < argc ) ? argv[argind+1] : 0;
if( ch2 == '-' ) if( ch2 == '-' )
{ {
if( !argv[argind][2] ) { ++argind; break; } // we found "--" if( !argv[argind][2] ) { ++argind; break; } // we found "--"

2
configure vendored
View file

@ -6,7 +6,7 @@
# to copy, distribute and modify it. # to copy, distribute and modify it.
pkgname=zutils pkgname=zutils
pkgversion=1.1 pkgversion=1.2-pre2
progname=zutils progname=zutils
srctrigger=doc/${pkgname}.texinfo srctrigger=doc/${pkgname}.texinfo

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCAT "1" "August 2013" "Zcat (zutils) 1.1" "User Commands" .TH ZCAT "1" "September 2013" "Zcat (zutils) 1.2-pre2" "User Commands"
.SH NAME .SH NAME
Zcat \- decompress and concatenate files to standard output Zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCMP "1" "August 2013" "Zcmp (zutils) 1.1" "User Commands" .TH ZCMP "1" "September 2013" "Zcmp (zutils) 1.2-pre2" "User Commands"
.SH NAME .SH NAME
Zcmp \- decompress and compare two files byte by byte Zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZDIFF "1" "August 2013" "Zdiff (zutils) 1.1" "User Commands" .TH ZDIFF "1" "September 2013" "Zdiff (zutils) 1.2-pre2" "User Commands"
.SH NAME .SH NAME
Zdiff \- decompress and compare two files line by line Zdiff \- decompress and compare two files line by line
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZGREP "1" "August 2013" "Zgrep (zutils) 1.1" "User Commands" .TH ZGREP "1" "September 2013" "Zgrep (zutils) 1.2-pre2" "User Commands"
.SH NAME .SH NAME
Zgrep \- search compressed files for a regular expression Zgrep \- search compressed files for a regular expression
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZTEST "1" "August 2013" "Ztest (zutils) 1.1" "User Commands" .TH ZTEST "1" "September 2013" "Ztest (zutils) 1.2-pre2" "User Commands"
.SH NAME .SH NAME
Ztest \- verify integrity of compressed files Ztest \- verify integrity of compressed files
.SH SYNOPSIS .SH SYNOPSIS

76
doc/zupdate.1 Normal file
View file

@ -0,0 +1,76 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZUPDATE "1" "September 2013" "Zupdate (zutils) 1.2-pre2" "User Commands"
.SH NAME
Zupdate \- recompress bzip2, gzip, xz files to lzip files
.SH SYNOPSIS
.B zupdate
[\fIoptions\fR] [\fIfiles\fR]
.SH DESCRIPTION
Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.
The originals are compared with the new files and then deleted.
Only regular files with standard file name extensions are recompressed,
other files are ignored.
Compressed files are decompressed and then recompressed on the fly; no
temporary files are created.
The lzip format is chosen as destination because it is by far the most
appropriate for long\-term data archiving.
.PP
If the lzip compressed version of a file already exists, the file is
skipped unless the '\-\-force' option is given. In this case, if the
comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted.
.PP
Exit status is 0 if all the compressed files were successfully
recompressed (if needed), compared and deleted. Non\-zero otherwise.
.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
do not skip a file even if the .lz exists
.TP
\fB\-l\fR, \fB\-\-lzip\-verbose\fR
pass a \fB\-v\fR option to the lzip compressor
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
\fB\-r\fR, \fB\-\-recursive\fR
operate recursively on directories
.TP
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-0\fR .. \fB\-9\fR
set compression level [default 9]
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org
.br
Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT
Copyright \(co 2013 Antonio Diaz Diaz.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
.br
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

View file

@ -12,7 +12,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual Zutils Manual
************* *************
This manual is for Zutils (version 1.1, 2 August 2013). This manual is for Zutils (version 1.2-pre2, 4 September 2013).
* Menu: * Menu:
@ -24,11 +24,12 @@ This manual is for Zutils (version 1.1, 2 August 2013).
* Zdiff:: Comparing compressed files line by line * Zdiff:: Comparing compressed files line by line
* Zgrep:: Searching inside compressed files * Zgrep:: Searching inside compressed files
* Ztest:: Testing integrity of compressed files * Ztest:: Testing integrity of compressed files
* Zupdate:: Recompressing files to lzip format
* Problems:: Reporting bugs * Problems:: Reporting bugs
* Concept index:: Index of concepts * Concept index:: Index of concepts
Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz. Copyright (C) 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to This manual is free documentation: you have unlimited permission to
copy, distribute and modify it. copy, distribute and modify it.
@ -49,12 +50,13 @@ are created.
C++ programs. In particular the `--recursive' option is very efficient C++ programs. In particular the `--recursive' option is very efficient
in those utilities supporting it. in those utilities supporting it.
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest. The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate.
The supported formats are bzip2, gzip, lzip and xz. The supported formats are bzip2, gzip, lzip and xz.
The compressor to be used for each format is configurable at runtime. The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils. scripts provided with GNU gzip. Ztest is unique to zutils. Zupdate is
similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, NOTE: Bzip2 and lzip provide well-defined values of exit status,
which makes them safe to use with zutils. Gzip and xz may return which makes them safe to use with zutils. Gzip and xz may return
@ -545,7 +547,7 @@ matches were found, and 2 means trouble.
 
File: zutils.info, Node: Ztest, Next: Problems, Prev: Zgrep, Up: Top File: zutils.info, Node: Ztest, Next: Zupdate, Prev: Zgrep, Up: Top
8 Ztest 8 Ztest
******* *******
@ -588,10 +590,76 @@ environmental problems (file not found, invalid flags, I/O errors, etc),
 
File: zutils.info, Node: Problems, Next: Concept index, Prev: Ztest, Up: Top File: zutils.info, Node: Zupdate, Next: Problems, Prev: Ztest, Up: Top
9 Reporting Bugs 9 Zupdate
**************** *********
Zupdate recompresses files from bzip2, gzip, and xz formats to lzip
format. The originals are compared with the new files and then deleted.
Only regular files with standard file name extensions are recompressed,
other files are ignored. Compressed files are decompressed and then
recompressed on the fly; no temporary files are created. The lzip format
is chosen as destination because it is by far the most appropriate for
long-term data archiving.
If the lzip compressed version of a file already exists, the file is
skipped unless the `--force' option is given. In this case, if the
comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted.
The names of the original files must have one of the following
extensions: `.bz2', `.tbz', `.tbz2', `.gz', `.tgz', `.xz', `.txz'. The
files produced have the extensions `.lz' or `.tar.lz'.
The format for running zupdate is:
zupdate [OPTIONS] [FILES]
Exit status is 0 if all the compressed files were successfully
recompressed (if needed), compared and deleted. Non-zero otherwise.
Zupdate supports the following options:
`-f'
`--force'
Do not skip a file for which a lzip compressed version already
exists. `--force' compares the content of the input file with the
content of the lzip file and deletes the input file if both
contents are identical.
`-l'
`--lzip-verbose'
Pass a `-v' option to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and
newer, a second `-l' shows the progress of compression. Use it
together with `-v' to see the name of the file.
`-q'
`--quiet'
Quiet operation. Suppress all messages.
`-r'
`--recursive'
Operate recursively on directories.
`-v'
`--verbose'
Verbose mode. Show the files being processed. A second `-v' also
shows the files being ignored.
`-0 .. -9'
Set the compression level of lzip. By default zupdate passes `-9'
to lzip.

File: zutils.info, Node: Problems, Next: Concept index, Prev: Zupdate, Up: Top
10 Reporting bugs
*****************
There are probably bugs in zutils. There are certainly errors and There are probably bugs in zutils. There are certainly errors and
omissions in this manual. If you report them, they will get fixed. If omissions in this manual. If you report them, they will get fixed. If
@ -621,21 +689,23 @@ Concept index
* zdiff: Zdiff. (line 6) * zdiff: Zdiff. (line 6)
* zgrep: Zgrep. (line 6) * zgrep: Zgrep. (line 6)
* ztest: Ztest. (line 6) * ztest: Ztest. (line 6)
* zupdate: Zupdate. (line 6)
 
Tag Table: Tag Table:
Node: Top224 Node: Top224
Node: Introduction1095 Node: Introduction1156
Node: Common options3153 Node: Common options3258
Node: The zutilsrc file4402 Node: The zutilsrc file4507
Node: Zcat5328 Node: Zcat5433
Node: Zcmp7250 Node: Zcmp7355
Node: Zdiff9574 Node: Zdiff9679
Node: Zgrep12077 Node: Zgrep12182
Node: Ztest14914 Node: Ztest15019
Node: Problems16139 Node: Zupdate16243
Node: Concept index16668 Node: Problems18477
Node: Concept index19010
 
End Tag Table End Tag Table

View file

@ -6,8 +6,8 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 2 August 2013 @set UPDATED 4 September 2013
@set VERSION 1.1 @set VERSION 1.2-pre2
@dircategory Data Compression @dircategory Data Compression
@direntry @direntry
@ -43,13 +43,13 @@ This manual is for Zutils (version @value{VERSION}, @value{UPDATED}).
* Zdiff:: Comparing compressed files line by line * Zdiff:: Comparing compressed files line by line
* Zgrep:: Searching inside compressed files * Zgrep:: Searching inside compressed files
* Ztest:: Testing integrity of compressed files * Ztest:: Testing integrity of compressed files
* Zupdate:: Recompressing files to lzip format
* Problems:: Reporting bugs * Problems:: Reporting bugs
* Concept index:: Index of concepts * Concept index:: Index of concepts
@end menu @end menu
@sp 1 @sp 1
Copyright @copyright{} 2008, 2009, 2010, 2011, 2012, 2013 Copyright @copyright{} 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission This manual is free documentation: you have unlimited permission
to copy, distribute and modify it. to copy, distribute and modify it.
@ -70,12 +70,13 @@ programs. In particular the @samp{--recursive} option is very efficient
in those utilities supporting it. in those utilities supporting it.
@noindent @noindent
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest.@* The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate.@*
The supported formats are bzip2, gzip, lzip and xz.@* The supported formats are bzip2, gzip, lzip and xz.@*
The compressor to be used for each format is configurable at runtime. The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils. scripts provided with GNU gzip. Ztest is unique to zutils. Zupdate is
similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which NOTE: Bzip2 and lzip provide well-defined values of exit status, which
makes them safe to use with zutils. Gzip and xz may return ambiguous makes them safe to use with zutils. Gzip and xz may return ambiguous
@ -638,14 +639,85 @@ Operate recursively on directories.
@item -v @item -v
@itemx --verbose @itemx --verbose
Verbose mode. Show the verify status for each file processed. Verbose mode. Show the verify status for each file processed.@*
Further -v's increase the verbosity level. Further -v's increase the verbosity level.
@end table @end table
@node Zupdate
@chapter Zupdate
@cindex zupdate
Zupdate recompresses files from bzip2, gzip, and xz formats to lzip
format. The originals are compared with the new files and then deleted.
Only regular files with standard file name extensions are recompressed,
other files are ignored. Compressed files are decompressed and then
recompressed on the fly; no temporary files are created. The lzip format
is chosen as destination because it is by far the most appropriate for
long-term data archiving.
If the lzip compressed version of a file already exists, the file is
skipped unless the @samp{--force} option is given. In this case, if the
comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted.
The names of the original files must have one of the following
extensions: @samp{.bz2}, @samp{.tbz}, @samp{.tbz2}, @samp{.gz},
@samp{.tgz}, @samp{.xz}, @samp{.txz}. The files produced have the
extensions @samp{.lz} or @samp{.tar.lz}.
The format for running zupdate is:
@example
zupdate [@var{options}] [@var{files}]
@end example
@noindent
Exit status is 0 if all the compressed files were successfully
recompressed (if needed), compared and deleted. Non-zero otherwise.
Zupdate supports the following options:
@table @samp
@item -f
@itemx --force
Do not skip a file for which a lzip compressed version already exists.
@samp{--force} compares the content of the input file with the content
of the lzip file and deletes the input file if both contents are
identical.
@item -l
@itemx --lzip-verbose
Pass a @samp{-v} option to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and newer, a
second @samp{-l} shows the progress of compression. Use it together with
@samp{-v} to see the name of the file.
@item -q
@itemx --quiet
Quiet operation. Suppress all messages.
@item -r
@itemx --recursive
Operate recursively on directories.
@item -v
@itemx --verbose
Verbose mode. Show the files being processed. A second @samp{-v} also
shows the files being ignored.
@item -0 .. -9
Set the compression level of lzip. By default zupdate passes @samp{-9}
to lzip.
@end table
@node Problems @node Problems
@chapter Reporting Bugs @chapter Reporting bugs
@cindex bugs @cindex bugs
@cindex getting help @cindex getting help

View file

@ -275,7 +275,7 @@ int main( const int argc, const char * const argv[] )
for( ; argind < parser.arguments(); ++argind ) for( ; argind < parser.arguments(); ++argind )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
const char * arg = parser.argument( argind ).c_str(); const char * const arg = parser.argument( argind ).c_str();
if( !code ) if( !code )
{ {
if( program_mode == m_zgrep && !grep_pattern_found ) if( program_mode == m_zgrep && !grep_pattern_found )
@ -399,7 +399,7 @@ int main( const int argc, const char * const argv[] )
if( recursive ) if( recursive )
{ {
struct stat st; struct stat st;
if( !stat( input_filename.c_str(), &st ) && S_ISDIR( st.st_mode ) ) if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{ {
DIR * const dirp = opendir( input_filename.c_str() ); DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp ) if( !dirp )

View file

@ -16,6 +16,7 @@ ZGREP="${objdir}"/zgrep
ZEGREP="${objdir}"/zegrep ZEGREP="${objdir}"/zegrep
ZFGREP="${objdir}"/zfgrep ZFGREP="${objdir}"/zfgrep
ZTEST="${objdir}"/ztest ZTEST="${objdir}"/ztest
ZUPDATE="${objdir}"/zupdate
compressors="bzip2 gzip lzip" compressors="bzip2 gzip lzip"
extensions="bz2 gz lz" extensions="bz2 gz lz"
compressor_needed() { echo "${compressors} are needed to run tests" ; exit 1 ; } compressor_needed() { echo "${compressors} are needed to run tests" ; exit 1 ; }
@ -45,9 +46,9 @@ cat in.lz > lz_only.lz || framework_failure
cat in in in in in in > in6 || framework_failure cat in in in in in in > in6 || framework_failure
fail=0 fail=0
printf "testing zutils-%s..." "$2" printf "testing zutils-%s..." "$2"
printf "\ntesting zcat-%s..." "$2" printf "\ntesting zcat-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZCAT}" -N in.$i > copy || fail=1 "${ZCAT}" -N in.$i > copy || fail=1
@ -95,7 +96,7 @@ if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zcmp-%s..." "$2" printf "\ntesting zcmp-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZCMP}" -N in.$i || fail=1 "${ZCMP}" -N in.$i || fail=1
@ -176,7 +177,7 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zdiff-%s..." "$2" printf "\ntesting zdiff-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZDIFF}" -N in.$i > /dev/null || fail=1 "${ZDIFF}" -N in.$i > /dev/null || fail=1
@ -239,7 +240,7 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zgrep-%s..." "$2" printf "\ntesting zgrep-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZGREP}" -N "GNU" in.$i > /dev/null || fail=1 "${ZGREP}" -N "GNU" in.$i > /dev/null || fail=1
@ -305,7 +306,7 @@ printf .
printf . printf .
printf "\ntesting ztest-%s..." "$2" printf "\ntesting ztest-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZTEST}" -N --format=$i < in.$i || fail=1 "${ZTEST}" -N --format=$i < in.$i || fail=1
@ -335,10 +336,80 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --format=lz in.bz2 2> /dev/null "${ZTEST}" -N --format=lz in.bz2 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --lz='lzip --bad-option' in.lz 2> /dev/null "${ZTEST}" -N --lz='lzip --bad-option' in.lz 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --bad-option 2> /dev/null "${ZTEST}" -N --bad-option 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zupdate-%s..." "$2"
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N --bz2=bad_command x.bz2 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --bz2='bzip2 --bad-option' x.bz2 > /dev/null 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --gz=bad_command x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --gz='gzip --bad-option' x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --lz=bad_command x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --lz='lzip --bad-option' x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --bad-option 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
cat in.lz in.lz > x.lz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null
if [ $? = 1 ] && [ -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
"${ZUPDATE}" -N x.bz2 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
"${ZUPDATE}" -N x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N x.bz2 x.gz 2> /dev/null
if [ $? = 1 ] && [ ! -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] &&
[ ! -e x ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
"${ZUPDATE}" -N -6 -q x.bz2
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
echo echo
if [ ${fail} = 0 ] ; then if [ ${fail} = 0 ] ; then
echo "tests completed successfully." echo "tests completed successfully."

View file

@ -246,12 +246,12 @@ int cmp( const long long max_size, const int infd[2],
} }
} }
buffer0[rd[0]] = ~buffer1[rd[0]]; // sentinels for the block compare const int min_rd = std::min( rd[0], rd[1] );
buffer1[rd[1]] = ~buffer0[rd[1]]; buffer0[min_rd] = 0; // sentinels for the block compare
buffer1[min_rd] = 1;
int first_diff = block_compare( buffer0, buffer1, &line_number ); int first_diff = block_compare( buffer0, buffer1, &line_number );
byte_number += first_diff; byte_number += first_diff;
const int min_rd = std::min( rd[0], rd[1] );
if( first_diff < min_rd ) if( first_diff < min_rd )
{ {

View file

@ -389,6 +389,11 @@ int main( const int argc, const char * const argv[] )
set_signals(); set_signals();
if( !set_fifonames( filenames ) ) return 2; if( !set_fifonames( filenames ) ) return 2;
Children children[2];
if( !set_data_feeder( fifonames[0], infd[0], children[0], format_types[0] ) ||
!set_data_feeder( fifonames[1], infd[1], children[1], format_types[1] ) )
return 2;
const pid_t diff_pid = fork(); const pid_t diff_pid = fork();
if( diff_pid == 0 ) // child (diff) if( diff_pid == 0 ) // child (diff)
{ {
@ -407,11 +412,6 @@ int main( const int argc, const char * const argv[] )
if( diff_pid < 0 ) // parent if( diff_pid < 0 ) // parent
{ show_fork_error( DIFF ); return 2; } { show_fork_error( DIFF ); return 2; }
Children children[2];
if( !set_data_feeder( fifonames[0], infd[0], children[0], format_types[0] ) ||
!set_data_feeder( fifonames[1], infd[1], children[1], format_types[1] ) )
return 2;
int retval = wait_for_child( diff_pid, DIFF ); int retval = wait_for_child( diff_pid, DIFF );
for( int i = 0; i < 2; ++i ) for( int i = 0; i < 2; ++i )

View file

@ -59,7 +59,20 @@ int ztest_stdin( const int infd, int format_index,
{ show_error( "Can't create pipe", errno ); return 1; } { show_error( "Can't create pipe", errno ); return 1; }
const pid_t pid = fork(); const pid_t pid = fork();
if( pid == 0 ) // child1 (compressor) if( pid == 0 ) // child1 (compressor feeder)
{
if( close( fda[0] ) != 0 ||
!feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 1 );
if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 1 ); }
_exit( 0 );
}
if( pid < 0 ) // parent
{ show_fork_error( "data feeder" ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (compressor)
{ {
if( dup2( fda[0], STDIN_FILENO ) >= 0 && if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 ) close( fda[0] ) == 0 && close( fda[1] ) == 0 )
@ -81,25 +94,13 @@ int ztest_stdin( const int infd, int format_index,
show_exec_error( compressor_name ); show_exec_error( compressor_name );
_exit( 1 ); _exit( 1 );
} }
if( pid < 0 ) // parent if( pid2 < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; } { show_fork_error( compressor_name ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (compressor feeder)
{
if( close( fda[0] ) != 0 ||
!feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 1 );
if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 1 ); }
_exit( 0 );
}
if( pid2 < 0 ) // parent
{ show_fork_error( "data feeder" ); return 1; }
close( fda[0] ); close( fda[1] ); close( fda[0] ); close( fda[1] );
int retval = wait_for_child( pid, compressor_name, 1 ); const bool isgzxz = ( format_index == fmt_gz || format_index == fmt_xz );
if( retval == 0 && wait_for_child( pid2, "data feeder" ) != 0 ) int retval = wait_for_child( pid2, compressor_name, 1, isgzxz );
if( retval == 0 && wait_for_child( pid, "data feeder" ) != 0 )
retval = 1; retval = 1;
return retval; return retval;
} }
@ -141,5 +142,6 @@ int ztest_file( const int infd, int format_index,
if( pid < 0 ) // parent if( pid < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; } { show_fork_error( compressor_name ); return 1; }
return wait_for_child( pid, compressor_name, 1 ); const bool isgzxz = ( format_index == fmt_gz || format_index == fmt_xz );
return wait_for_child( pid, compressor_name, 1, isgzxz );
} }

415
zupdate.cc Normal file
View file

@ -0,0 +1,415 @@
/* Zupdate - recompress bzip2, gzip, xz files to lzip files
Copyright (C) 2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#include <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include <vector>
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <utime.h>
#include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__)
#include <io.h>
#endif
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
#endif
namespace {
#ifdef O_BINARY
const int o_binary = O_BINARY;
#else
const int o_binary = 0;
#endif
void show_zupdate_help()
{
std::printf( "Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.\n"
"The originals are compared with the new files and then deleted.\n"
"Only regular files with standard file name extensions are recompressed,\n"
"other files are ignored.\n"
"Compressed files are decompressed and then recompressed on the fly; no\n"
"temporary files are created.\n"
"The lzip format is chosen as destination because it is by far the most\n"
"appropriate for long-term data archiving.\n"
"\nIf the lzip compressed version of a file already exists, the file is\n"
"skipped unless the '--force' option is given. In this case, if the\n"
"comparison fails, an error is returned and the original file is not\n"
"deleted. The operation of zupdate is meant to be safe and not produce\n"
"any data loss. Therefore, existing lzip compressed files are never\n"
"overwritten nor deleted.\n"
"\nUsage: zupdate [options] [files]\n"
"\nExit status is 0 if all the compressed files were successfully\n"
"recompressed (if needed), compared and deleted. Non-zero otherwise.\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" -f, --force do not skip a file even if the .lz exists\n"
" -l, --lzip-verbose pass a -v option to the lzip compressor\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" -0 .. -9 set compression level [default 9]\n"
" --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" );
show_help_addr();
}
int cant_execute( const std::string & command, const int status )
{
if( verbosity >= 0 )
{
if( WIFEXITED( status ) )
std::fprintf( stderr, "%s: Error executing '%s'. Exit status = %d.\n",
util_name, command.c_str(), WEXITSTATUS( status ) );
else
std::fprintf( stderr, "%s: Can't execute '%s'.\n",
util_name, command.c_str() );
}
return 1;
}
// Set permissions, owner and times.
void set_permissions( const char * const rname, const struct stat & in_stats )
{
bool warning = false;
// fchown will in many cases return with EPERM, which can be safely ignored.
if( ( chown( rname, in_stats.st_uid, in_stats.st_gid ) != 0 &&
errno != EPERM ) ||
chmod( rname, in_stats.st_mode ) != 0 ) warning = true;
struct utimbuf t;
t.actime = in_stats.st_atime;
t.modtime = in_stats.st_mtime;
if( utime( rname, &t ) != 0 ) warning = true;
if( warning && verbosity >= 2 )
show_error( "Can't change output file attributes." );
}
struct { const char * from; const char * to; int format_index; } const
known_extensions[] = {
{ ".bz2", "", fmt_bz2 },
{ ".tbz", ".tar", fmt_bz2 },
{ ".tbz2", ".tar", fmt_bz2 },
{ ".gz", "", fmt_gz },
{ ".tgz", ".tar", fmt_gz },
{ ".lz", "", fmt_lz },
{ ".tlz", ".tar", fmt_lz },
{ ".xz", "", fmt_xz },
{ ".txz", ".tar", fmt_xz },
{ 0, 0, -1 } };
// Returns 0 for success, -1 for file skipped, 1 for error.
int zupdate_file( const std::string & name, const char * const lzip_name,
const std::vector< std::string > & lzip_args2,
const bool force )
{
int format_index = -1;
std::string dname; // decompressed_name
for( int i = 0; known_extensions[i].from; ++i ) // search extension
{
const std::string from( known_extensions[i].from );
if( name.size() > from.size() &&
name.compare( name.size() - from.size(), from.size(), from ) == 0 )
{
dname.assign( name, 0, name.size() - from.size() );
dname += known_extensions[i].to;
format_index = known_extensions[i].format_index;
if( format_index == fmt_lz )
{
if( verbosity >= 2 )
std::fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
util_name, name.c_str(), known_extensions[i].from );
return 0; // ignore this file
}
break;
}
}
const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name || !compressor_name[0] )
{
if( verbosity >= 2 )
std::fprintf( stderr, "%s: Unknown extension in file name '%s' -- ignored.\n",
util_name, name.c_str() );
return 0; // ignore this file
}
struct stat in_stats;
if( stat( name.c_str(), &in_stats ) != 0 ) // check input file
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't stat input file '%s': %s.\n",
util_name, name.c_str(), std::strerror( errno ) );
return 1;
}
if( !S_ISREG( in_stats.st_mode ) )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Input file '%s' is not a regular file.\n",
util_name, name.c_str() );
return 1;
}
struct stat st;
std::string rname( dname ); rname += ".lz"; // recompressed_name
const bool lz_exists = ( stat( rname.c_str(), &st ) == 0 );
if( lz_exists && !force )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
util_name, rname.c_str() );
return -1;
}
if( !lz_exists ) // recompress
{
if( verbosity >= 1 )
std::fprintf( stderr, "Recompressing file '%s'.\n", name.c_str() );
int fda[2]; // pipe between decompressor and compressor
if( pipe( fda ) < 0 )
{ show_error( "Can't create pipe", errno ); return 1; }
const pid_t pid = fork();
if( pid == 0 ) // child1 (decompressor)
{
if( dup2( fda[1], STDOUT_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 )
{
const std::vector< std::string > & compressor_args =
get_compressor_args( format_index );
const int size = compressor_args.size();
const char ** const argv = new const char *[size+5];
argv[0] = compressor_name;
for( int i = 0; i < size; ++i ) argv[i+1] = compressor_args[i].c_str();
argv[size+1] = "-cd";
argv[size+2] = "--";
argv[size+3] = name.c_str();
argv[size+4] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( compressor_name );
_exit( 1 );
}
if( pid < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (lzip compressor)
{
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 )
{
const std::vector< std::string > & lzip_args =
get_compressor_args( fmt_lz );
const int size = lzip_args.size();
const int size2 = lzip_args2.size();
const char ** const argv = new const char *[size+size2+5];
argv[0] = lzip_name;
argv[1] = "-9";
for( int i = 0; i < size; ++i ) argv[i+2] = lzip_args[i].c_str();
for( int i = 0; i < size2; ++i ) argv[i+size+2] = lzip_args2[i].c_str();
argv[size+size2+2] = "-o";
argv[size+size2+3] = dname.c_str();
argv[size+size2+4] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( lzip_name );
_exit( 1 );
}
if( pid2 < 0 ) // parent
{ show_fork_error( lzip_name ); return 1; }
close( fda[0] ); close( fda[1] );
int retval = wait_for_child( pid, compressor_name );
int retval2 = wait_for_child( pid2, lzip_name );
if( retval || retval2 ) { std::remove( rname.c_str() ); return 1; }
set_permissions( rname.c_str(), in_stats );
}
{
if( lz_exists && verbosity >= 1 )
std::fprintf( stderr, "Comparing file '%s'.\n", name.c_str() );
std::string zcmp_command( invocation_name );
unsigned i = zcmp_command.size();
while( i > 0 && zcmp_command[i-1] != '/' ) --i;
zcmp_command.resize( i );
zcmp_command += "zcmp "; // ${bindir}zcmp
zcmp_command += name; zcmp_command += ' '; zcmp_command += rname;
int status = std::system( zcmp_command.c_str() );
if( status != 0 )
{ if( !lz_exists ) std::remove( rname.c_str() );
return cant_execute( zcmp_command, status ); }
}
if( std::remove( name.c_str() ) != 0 && errno != ENOENT )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't delete input file '%s': %s.\n",
util_name, name.c_str(), std::strerror( errno ) );
return 1;
}
return 0;
}
} // end namespace
int main( const int argc, const char * const argv[] )
{
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt };
std::string input_filename;
std::list< std::string > filenames;
std::vector< std::string > lzip_args2; // args to lzip, maybe empty
bool force = false;
bool recursive = false;
invocation_name = argv[0];
util_name = "zupdate";
const Arg_parser::Option options[] =
{
{ '0', 0, Arg_parser::no },
{ '1', 0, Arg_parser::no },
{ '2', 0, Arg_parser::no },
{ '3', 0, Arg_parser::no },
{ '4', 0, Arg_parser::no },
{ '5', 0, Arg_parser::no },
{ '6', 0, Arg_parser::no },
{ '7', 0, Arg_parser::no },
{ '8', 0, Arg_parser::no },
{ '9', 0, Arg_parser::no },
{ 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
{ 'l', "lzip-verbose", Arg_parser::no },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 'r', "recursive", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 1; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
switch( code ) // common options
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
lzip_args2.push_back( "-" ); lzip_args2.back() += code; break;
case 'f': force = true; break;
case 'h': show_zupdate_help(); return 0;
case 'l': lzip_args2.push_back( "-v" ); break;
case 'N': continue;
case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break;
case 'r': recursive = true; break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version( "Zupdate" ); return 0;
case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); continue;
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); continue;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); continue;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); continue;
default : internal_error( "uncaught option" );
}
} // end process options
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY );
#endif
const char * const lzip_name = get_compressor_name( fmt_lz );
if( !lzip_name || !lzip_name[0] )
{ show_error( "Missing name of compressor for lzip format." ); return 1; }
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
int retval = 0;
while( !filenames.empty() )
{
input_filename = filenames.front();
filenames.pop_front();
if( !input_filename.size() || input_filename == "-" ) continue;
if( recursive )
{
struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{
DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp )
{
show_error2( "Can't open directory", input_filename.c_str() );
if( retval < 1 ) retval = 1; continue;
}
std::list< std::string > tmp_list;
while( true )
{
const struct dirent * const entryp = readdir( dirp );
if( !entryp ) { closedir( dirp ); break; }
std::string tmp_name( entryp->d_name );
if( tmp_name != "." && tmp_name != ".." )
tmp_list.push_back( input_filename + "/" + tmp_name );
}
filenames.splice( filenames.begin(), tmp_list );
continue;
}
}
int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force );
if( tmp < 0 && retval < 1 ) retval = 1;
if( tmp > retval ) retval = tmp;
if( tmp > 0 ) break;
}
return retval;
}

View file

@ -338,7 +338,7 @@ int test_format( const int infd, const uint8_t ** const magic_datap,
int wait_for_child( const pid_t pid, const char * const name, int wait_for_child( const pid_t pid, const char * const name,
const int eretval ) const int eretval, const bool isgzxz )
{ {
int status; int status;
while( waitpid( pid, &status, 0 ) == -1 ) while( waitpid( pid, &status, 0 ) == -1 )
@ -355,7 +355,7 @@ int wait_for_child( const pid_t pid, const char * const name,
if( WIFEXITED( status ) ) if( WIFEXITED( status ) )
{ {
const int tmp = WEXITSTATUS( status ); const int tmp = WEXITSTATUS( status );
if( eretval == 1 && tmp == 1 ) return 2; // for ztest if( isgzxz && eretval == 1 && tmp == 1 ) return 2; // for ztest
return tmp; return tmp;
} }
return eretval; return eretval;

View file

@ -79,7 +79,7 @@ int test_format( const int infd, const uint8_t ** const magic_datap,
// Returns exit status of child process 'pid', or 'eretval' in case of error. // Returns exit status of child process 'pid', or 'eretval' in case of error.
// //
int wait_for_child( const pid_t pid, const char * const name, int wait_for_child( const pid_t pid, const char * const name,
const int eretval = 2 ); const int eretval = 2, const bool isgzxz = false );
// Returns -1 if child not terminated, 'eretval' in case of error, or // Returns -1 if child not terminated, 'eretval' in case of error, or
// exit status of child process 'pid'. // exit status of child process 'pid'.