1
0
Fork 0

Adding upstream version 0.22.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:16:46 +01:00
parent cc1b855cb3
commit 22f7f3575c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
30 changed files with 307 additions and 182 deletions

View file

@ -1,3 +1,11 @@
2022-01-05 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.22 released.
* main.cc (getnum): Show option name and valid range if error.
(check_lib): Check that LZ_API_VERSION and LZ_version_string match.
(main): Report an error if -o is used with any operation except -z.
* Set variable LIBS from configure.
2021-06-14 Antonio Diaz Diaz <antonio@gnu.org> 2021-06-14 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.21 released. * Version 0.21 released.
@ -130,13 +138,13 @@
* Option '--ignore-crc' replaced with '--missing-crc'. * Option '--ignore-crc' replaced with '--missing-crc'.
* create.cc (add_member): Test that uid, gid, mtime, devmajor * create.cc (add_member): Test that uid, gid, mtime, devmajor
and devminor are in ustar range. and devminor are in ustar range.
* configure: Accept appending to CXXFLAGS, 'CXXFLAGS+=OPTIONS'. * configure: Accept appending to CXXFLAGS; 'CXXFLAGS+=OPTIONS'.
* Makefile.in: Use tarlz in target 'dist'. * Makefile.in: Use tarlz in target 'dist'.
2018-09-29 Antonio Diaz Diaz <antonio@gnu.org> 2018-09-29 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.5 released. * Version 0.5 released.
* Implement simplified posix pax format. * Implement simplified POSIX pax format.
* Implement CRC32-C (Castagnoli) of the extended header data. * Implement CRC32-C (Castagnoli) of the extended header data.
* New option '--ignore-crc'. * New option '--ignore-crc'.
* Add missing #includes for major, minor and makedev. * Add missing #includes for major, minor and makedev.
@ -174,7 +182,7 @@
* Version 0.1 released. * Version 0.1 released.
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This file is a collection of facts, and thus it is not copyrightable, This file is a collection of facts, and thus it is not copyrightable,
but just in case, you have unlimited permission to copy, distribute, and but just in case, you have unlimited permission to copy, distribute, and

View file

@ -2,7 +2,7 @@ Requirements
------------ ------------
You will need a C++11 compiler and the compression library lzlib installed. You will need a C++11 compiler and the compression library lzlib installed.
(gcc 3.3.6 or newer is recommended). (gcc 3.3.6 or newer is recommended).
I use gcc 6.1.0 and 4.1.2, but the code should compile with any standards I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards
compliant compiler. compliant compiler.
Lzlib must be version 1.12 or newer. Lzlib must be version 1.12 or newer.
@ -70,7 +70,7 @@ After running 'configure', you can run 'make' and 'make install' as
explained above. explained above.
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy, This file is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.

View file

@ -4,7 +4,6 @@ INSTALL = install
INSTALL_PROGRAM = $(INSTALL) -m 755 INSTALL_PROGRAM = $(INSTALL) -m 755
INSTALL_DATA = $(INSTALL) -m 644 INSTALL_DATA = $(INSTALL) -m 644
INSTALL_DIR = $(INSTALL) -d -m 755 INSTALL_DIR = $(INSTALL) -d -m 755
LIBS = -llz -lpthread
SHELL = /bin/sh SHELL = /bin/sh
CAN_RUN_INSTALLINFO = $(SHELL) -c "install-info --version" > /dev/null 2>&1 CAN_RUN_INSTALLINFO = $(SHELL) -c "install-info --version" > /dev/null 2>&1
@ -22,7 +21,7 @@ objs = arg_parser.o lzip_index.o archive_reader.o common.o common_decode.o \
all : $(progname) all : $(progname)
$(progname) : $(objs) $(progname) : $(objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(objs) $(LIBS) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(objs) $(LIBS)
main.o : main.cc main.o : main.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<

25
NEWS
View file

@ -1,22 +1,11 @@
Changes in version 0.21: Changes in version 0.22:
Lzlib 1.12 or newer is now required to compile and run tarlz. In case of error in a numerical argument to a command line option, tarlz
now shows the name of the option and the range of valid values.
Members without name are now skipped when decoding except when listing. This '--check-lib' now checks that LZ_API_VERSION and LZ_version_string match.
allows the reliable detection of certain format violations during parallel
extraction with more than two threads. (Thanks to Florian Schmaus for
reporting the problem).
The new option '-z, --compress', which compresses existing POSIX tar Tarlz now reports an error and exits with status 1 if '-o, --output' is used
archives aligning the lzip members to the tar members with choice of with any operation other than '-z, --compress'.
granularity, has been added. Existing compressed archives are not
overwritten.
The new option '-o, --output', which writes the compressed output to a file, The variable LIBS can now be set from configure.
has been added. Currently '--output' only works with '--compress'.
The new option '--warn-newer', which warns during archive creation if any
file being archived has a modification time newer than the archive creation
time, has been added.
A failure in the '--diff' test of the testsuite on OS/2 has been fixed.

2
README
View file

@ -87,7 +87,7 @@ tar.lz
+===============+=================================================+========+ +===============+=================================================+========+
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy, This file is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -30,8 +30,8 @@
namespace { namespace {
/* Returns the number of bytes really read. /* Return the number of bytes really read.
If (returned value < size) and (errno == 0), means EOF was reached. If (value returned < size) and (errno == 0), means EOF was reached.
*/ */
int preadblock( const int fd, uint8_t * const buf, const int size, int preadblock( const int fd, uint8_t * const buf, const int size,
const long long pos ) const long long pos )
@ -50,8 +50,8 @@ int preadblock( const int fd, uint8_t * const buf, const int size,
} }
/* Returns the number of bytes really written. /* Return the number of bytes really written.
If (returned value < size), it is always an error. If (value returned < size), it is always an error.
*//* *//*
int pwriteblock( const int fd, const uint8_t * const buf, const int size, int pwriteblock( const int fd, const uint8_t * const buf, const int size,
const long long pos ) const long long pos )

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version) /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006-2021 Antonio Diaz Diaz. Copyright (C) 2006-2022 Antonio Diaz Diaz.
This library is free software. Redistribution and use in source and This library is free software. Redistribution and use in source and
binary forms, with or without modification, are permitted provided binary forms, with or without modification, are permitted provided
@ -35,9 +35,10 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
// Test all long options for either exact match or abbreviated matches. // Test all long options for either exact match or abbreviated matches.
for( int i = 0; options[i].code != 0; ++i ) for( int i = 0; options[i].code != 0; ++i )
if( options[i].name && std::strncmp( options[i].name, &opt[2], len ) == 0 ) if( options[i].long_name &&
std::strncmp( options[i].long_name, &opt[2], len ) == 0 )
{ {
if( std::strlen( options[i].name ) == len ) // Exact match found if( std::strlen( options[i].long_name ) == len ) // Exact match found
{ index = i; exact = true; break; } { index = i; exact = true; break; }
else if( index < 0 ) index = i; // First nonexact match found else if( index < 0 ) index = i; // First nonexact match found
else if( options[index].code != options[i].code || else if( options[index].code != options[i].code ||
@ -58,19 +59,19 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
} }
++argind; ++argind;
data.push_back( Record( options[index].code ) ); data.push_back( Record( options[index].code, options[index].long_name ) );
if( opt[len+2] ) // '--<long_option>=<argument>' syntax if( opt[len+2] ) // '--<long_option>=<argument>' syntax
{ {
if( options[index].has_arg == no ) if( options[index].has_arg == no )
{ {
error_ = "option '--"; error_ += options[index].name; error_ = "option '--"; error_ += options[index].long_name;
error_ += "' doesn't allow an argument"; error_ += "' doesn't allow an argument";
return false; return false;
} }
if( options[index].has_arg == yes && !opt[len+3] ) if( options[index].has_arg == yes && !opt[len+3] )
{ {
error_ = "option '--"; error_ += options[index].name; error_ = "option '--"; error_ += options[index].long_name;
error_ += "' requires an argument"; error_ += "' requires an argument";
return false; return false;
} }
@ -82,7 +83,7 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
{ {
if( !arg || !arg[0] ) if( !arg || !arg[0] )
{ {
error_ = "option '--"; error_ += options[index].name; error_ = "option '--"; error_ += options[index].long_name;
error_ += "' requires an argument"; error_ += "' requires an argument";
return false; return false;
} }

View file

@ -1,5 +1,5 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version) /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006-2021 Antonio Diaz Diaz. Copyright (C) 2006-2022 Antonio Diaz Diaz.
This library is free software. Redistribution and use in source and This library is free software. Redistribution and use in source and
binary forms, with or without modification, are permitted provided binary forms, with or without modification, are permitted provided
@ -23,9 +23,9 @@
In case of error, 'error' returns a non-empty error message. In case of error, 'error' returns a non-empty error message.
'options' is an array of 'struct Option' terminated by an element 'options' is an array of 'struct Option' terminated by an element
containing a code which is zero. A null name means a short-only containing a code which is zero. A null long_name means a short-only
option. A code value outside the unsigned char range means a option. A code value outside the unsigned char range means a long-only
long-only option. option.
Arg_parser normally makes it appear as if all the option arguments Arg_parser normally makes it appear as if all the option arguments
were specified before all the non-option arguments for the purposes were specified before all the non-option arguments for the purposes
@ -48,7 +48,7 @@ public:
struct Option struct Option
{ {
int code; // Short option letter or code ( code != 0 ) int code; // Short option letter or code ( code != 0 )
const char * name; // Long option name (maybe null) const char * long_name; // Long option name (maybe null)
Has_arg has_arg; Has_arg has_arg;
}; };
@ -56,8 +56,12 @@ private:
struct Record struct Record
{ {
int code; int code;
std::string parsed_name;
std::string argument; std::string argument;
explicit Record( const int c ) : code( c ) {} explicit Record( const unsigned char c )
: code( c ), parsed_name( "-" ) { parsed_name += c; }
Record( const int c, const char * const long_name )
: code( c ), parsed_name( "--" ) { parsed_name += long_name; }
explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {} explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {}
}; };
@ -91,6 +95,13 @@ public:
else return 0; else return 0;
} }
// Full name of the option parsed (short or long).
const std::string & parsed_name( const int i ) const
{
if( i >= 0 && i < arguments() ) return data[i].parsed_name;
else return empty_arg;
}
const std::string & argument( const int i ) const const std::string & argument( const int i ) const
{ {
if( i >= 0 && i < arguments() ) return data[i].argument; if( i >= 0 && i < arguments() ) return data[i].argument;

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -108,8 +108,8 @@ unsigned long long parse_octal( const uint8_t * const ptr, const int size )
} }
/* Returns the number of bytes really read. /* Return the number of bytes really read.
If (returned value < size) and (errno == 0), means EOF was reached. If (value returned < size) and (errno == 0), means EOF was reached.
*/ */
int readblock( const int fd, uint8_t * const buf, const int size ) int readblock( const int fd, uint8_t * const buf, const int size )
{ {
@ -127,8 +127,8 @@ int readblock( const int fd, uint8_t * const buf, const int size )
} }
/* Returns the number of bytes really written. /* Return the number of bytes really written.
If (returned value < size), it is always an error. If (value returned < size), it is always an error.
*/ */
int writeblock( const int fd, const uint8_t * const buf, const int size ) int writeblock( const int fd, const uint8_t * const buf, const int size )
{ {

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -122,10 +122,6 @@ void close_and_set_permissions( const struct stat * const in_statsp )
} }
inline void set_retval( int & retval, const int new_val )
{ if( retval < new_val ) retval = new_val; }
bool archive_write( const uint8_t * const buf, const long long size, bool archive_write( const uint8_t * const buf, const long long size,
LZ_Encoder * const encoder ) LZ_Encoder * const encoder )
{ {
@ -318,9 +314,6 @@ int compress_archive( const Cl_options & cl_opts,
int compress( Cl_options & cl_opts ) int compress( Cl_options & cl_opts )
{ {
if( !cl_opts.archive_name.empty() )
{ show_file_error( cl_opts.archive_name.c_str(),
"Option '-f' is incompatible with '--compress'." ); return 1; }
if( cl_opts.num_files > 1 && cl_opts.output_filename.size() ) if( cl_opts.num_files > 1 && cl_opts.output_filename.size() )
{ show_file_error( cl_opts.output_filename.c_str(), { show_file_error( cl_opts.output_filename.c_str(),
"Only can compress one archive when using '-o'." ); return 1; } "Only can compress one archive when using '-o'." ); return 1; }

11
configure vendored
View file

@ -1,12 +1,12 @@
#! /bin/sh #! /bin/sh
# configure script for Tarlz - Archiver with multimember lzip compression # configure script for Tarlz - Archiver with multimember lzip compression
# Copyright (C) 2013-2021 Antonio Diaz Diaz. # Copyright (C) 2013-2022 Antonio Diaz Diaz.
# #
# This configure script is free software: you have unlimited permission # This configure script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
pkgname=tarlz pkgname=tarlz
pkgversion=0.21 pkgversion=0.22
progname=tarlz progname=tarlz
srctrigger=doc/${pkgname}.texi srctrigger=doc/${pkgname}.texi
@ -24,6 +24,7 @@ CXX=g++
CPPFLAGS= CPPFLAGS=
CXXFLAGS='-Wall -W -O2' CXXFLAGS='-Wall -W -O2'
LDFLAGS= LDFLAGS=
LIBS='-llz -lpthread'
# checking whether we are using GNU C++. # checking whether we are using GNU C++.
/bin/sh -c "${CXX} --version" > /dev/null 2>&1 || { CXX=c++ ; CXXFLAGS=-O2 ; } /bin/sh -c "${CXX} --version" > /dev/null 2>&1 || { CXX=c++ ; CXXFLAGS=-O2 ; }
@ -69,6 +70,7 @@ while [ $# != 0 ] ; do
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]" echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
echo " CXXFLAGS+=OPTIONS append options to the current value of CXXFLAGS" echo " CXXFLAGS+=OPTIONS append options to the current value of CXXFLAGS"
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]" echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
echo " LIBS=OPTIONS libraries to pass to the linker [${LIBS}]"
echo echo
exit 0 ;; exit 0 ;;
--version | -V) --version | -V)
@ -96,6 +98,7 @@ while [ $# != 0 ] ; do
CXXFLAGS=*) CXXFLAGS=${optarg} ;; CXXFLAGS=*) CXXFLAGS=${optarg} ;;
CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;; CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;;
LDFLAGS=*) LDFLAGS=${optarg} ;; LDFLAGS=*) LDFLAGS=${optarg} ;;
LIBS=*) LIBS="${optarg} ${LIBS}" ;;
--*) --*)
echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;; echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;;
@ -164,10 +167,11 @@ echo "CXX = ${CXX}"
echo "CPPFLAGS = ${CPPFLAGS}" echo "CPPFLAGS = ${CPPFLAGS}"
echo "CXXFLAGS = ${CXXFLAGS}" echo "CXXFLAGS = ${CXXFLAGS}"
echo "LDFLAGS = ${LDFLAGS}" echo "LDFLAGS = ${LDFLAGS}"
echo "LIBS = ${LIBS}"
rm -f Makefile rm -f Makefile
cat > Makefile << EOF cat > Makefile << EOF
# Makefile for Tarlz - Archiver with multimember lzip compression # Makefile for Tarlz - Archiver with multimember lzip compression
# Copyright (C) 2013-2021 Antonio Diaz Diaz. # Copyright (C) 2013-2022 Antonio Diaz Diaz.
# This file was generated automatically by configure. Don't edit. # This file was generated automatically by configure. Don't edit.
# #
# This Makefile is free software: you have unlimited permission # This Makefile is free software: you have unlimited permission
@ -187,6 +191,7 @@ CXX = ${CXX}
CPPFLAGS = ${CPPFLAGS} CPPFLAGS = ${CPPFLAGS}
CXXFLAGS = ${CXXFLAGS} CXXFLAGS = ${CXXFLAGS}
LDFLAGS = ${LDFLAGS} LDFLAGS = ${LDFLAGS}
LIBS = ${LIBS}
EOF EOF
cat "${srcdir}/Makefile.in" >> Makefile cat "${srcdir}/Makefile.in" >> Makefile

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -394,12 +394,13 @@ const char * remove_leading_dotslash( const char * const filename,
} }
// set file_size != 0 only for regular files
bool fill_headers( const char * const filename, Extended & extended, bool fill_headers( const char * const filename, Extended & extended,
Tar_header header, long long & file_size, const int flag ) Tar_header header, long long & file_size, const int flag )
{ {
struct stat st; struct stat st;
if( hstat( filename, &st, gcl_opts->dereference ) != 0 ) if( hstat( filename, &st, gcl_opts->dereference ) != 0 )
{ show_file_error( filename, "Can't stat input file", errno ); { show_file_error( filename, cant_stat, errno );
set_error_status( 1 ); return false; } set_error_status( 1 ); return false; }
if( archive_attrs.is_the_archive( st ) ) if( archive_attrs.is_the_archive( st ) )
{ show_file_error( archive_namep, "File is the archive; not dumped." ); { show_file_error( archive_namep, "File is the archive; not dumped." );
@ -717,8 +718,7 @@ int encode( Cl_options & cl_opts )
if( Exclude::excluded( filename ) ) continue; // skip excluded files if( Exclude::excluded( filename ) ) continue; // skip excluded files
struct stat st; struct stat st;
if( lstat( filename, &st ) != 0 ) // filename from command line if( lstat( filename, &st ) != 0 ) // filename from command line
{ show_file_error( filename, "Can't stat input file", errno ); { show_file_error( filename, cant_stat, errno ); set_error_status( 1 ); }
set_error_status( 1 ); }
else if( ( retval = nftw( filename, add_member, 16, else if( ( retval = nftw( filename, add_member, 16,
cl_opts.dereference ? 0 : FTW_PHYS ) ) != 0 ) cl_opts.dereference ? 0 : FTW_PHYS ) ) != 0 )
break; // write error break; // write error

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -43,3 +43,5 @@ public:
}; };
extern Archive_attrs archive_attrs; extern Archive_attrs archive_attrs;
const char * const cant_stat = "Can't stat input file";

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -316,8 +316,7 @@ extern "C" void * grouper( void * arg )
if( Exclude::excluded( filename ) ) continue; // skip excluded files if( Exclude::excluded( filename ) ) continue; // skip excluded files
struct stat st; struct stat st;
if( lstat( filename, &st ) != 0 ) // filename from command line if( lstat( filename, &st ) != 0 ) // filename from command line
{ show_file_error( filename, "Can't stat input file", errno ); { show_file_error( filename, cant_stat, errno ); set_error_status( 1 ); }
set_error_status( 1 ); }
else if( nftw( filename, add_member_lz, 16, else if( nftw( filename, add_member_lz, 16,
cl_opts.dereference ? 0 : FTW_PHYS ) != 0 ) cl_opts.dereference ? 0 : FTW_PHYS ) != 0 )
exit_fail_mt(); // write error or OOM exit_fail_mt(); // write error or OOM

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH TARLZ "1" "June 2021" "tarlz 0.21" "User Commands" .TH TARLZ "1" "January 2022" "tarlz 0.22" "User Commands"
.SH NAME .SH NAME
tarlz \- creates tar archives with multimember lzip compression tarlz \- creates tar archives with multimember lzip compression
.SH SYNOPSIS .SH SYNOPSIS
@ -150,8 +150,8 @@ Report bugs to lzip\-bug@nongnu.org
.br .br
Tarlz home page: http://www.nongnu.org/lzip/tarlz.html Tarlz home page: http://www.nongnu.org/lzip/tarlz.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
Using lzlib 1.12 Using lzlib 1.13\-rc1
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.

View file

@ -11,7 +11,7 @@ File: tarlz.info, Node: Top, Next: Introduction, Up: (dir)
Tarlz Manual Tarlz Manual
************ ************
This manual is for Tarlz (version 0.21, 14 June 2021). This manual is for Tarlz (version 0.22, 5 January 2022).
* Menu: * Menu:
@ -28,7 +28,7 @@ This manual is for Tarlz (version 0.21, 14 June 2021).
* Concept index:: Index of concepts * Concept index:: Index of concepts
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to copy, This manual is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.
@ -101,8 +101,9 @@ The format for running tarlz is:
tarlz [OPTIONS] [FILES] tarlz [OPTIONS] [FILES]
All operations except '--concatenate' operate on whole trees if any FILE is All operations except '--concatenate' and '--compress' operate on whole
a directory. Tarlz overwrites output files without warning. trees if any FILE is a directory. All operations except '--compress'
overwrite output files without warning.
On archive creation or appending tarlz archives the files specified, but On archive creation or appending tarlz archives the files specified, but
removes from member names any leading and trailing slashes and any file name removes from member names any leading and trailing slashes and any file name
@ -432,12 +433,14 @@ to '-1 --solid'.
'--check-lib' '--check-lib'
Compare the version of lzlib used to compile tarlz with the version Compare the version of lzlib used to compile tarlz with the version
actually being used and exit. Report any differences found. Exit with actually being used at run time and exit. Report any differences
error status 1 if differences are found. A mismatch may indicate that found. Exit with error status 1 if differences are found. A mismatch
lzlib is not correctly installed or that a different version of lzlib may indicate that lzlib is not correctly installed or that a different
has been installed after compiling tarlz. 'tarlz -v --check-lib' shows version of lzlib has been installed after compiling tarlz. Exit with
the version of lzlib being used and the value of 'LZ_API_VERSION' (if error status 2 if LZ_API_VERSION and LZ_version_string don't match.
defined). *Note Library version: (lzlib)Library version. 'tarlz -v --check-lib' shows the version of lzlib being used and the
value of LZ_API_VERSION (if defined). *Note Library version:
(lzlib)Library version.
'--warn-newer' '--warn-newer'
During archive creation, warn if any file being archived has a During archive creation, warn if any file being archived has a
@ -594,10 +597,10 @@ space, equal-sign, and newline.
representing the CRC <value> itself. The <value> is represented as 8 representing the CRC <value> itself. The <value> is represented as 8
hexadecimal digits in big endian order, '22 GNU.crc32=00000000\n'. The hexadecimal digits in big endian order, '22 GNU.crc32=00000000\n'. The
keyword of the CRC record is protected by the CRC to guarante that keyword of the CRC record is protected by the CRC to guarante that
corruption is always detected (except in case of CRC collision). A CRC corruption is always detected when using '--missing-crc' (except in
was chosen because a checksum is too weak for a potentially large list case of CRC collision). A CRC was chosen because a checksum is too
of variable sized records. A checksum can't detect simple errors like weak for a potentially large list of variable sized records. A
the swapping of two bytes. checksum can't detect simple errors like the swapping of two bytes.
At verbosity level 1 or higher tarlz prints a diagnostic for each unknown At verbosity level 1 or higher tarlz prints a diagnostic for each unknown
@ -844,16 +847,16 @@ workers. The workers compress the metadata received from the grouper along
with the file data read from the file system. The muxer collects processed with the file data read from the file system. The muxer collects processed
packets from the workers, and writes them to the archive. packets from the workers, and writes them to the archive.
,--------, .--------.
| data|---> to each worker below | data|---> to each worker below
| | ,------------, | | .------------.
| file | ,-->| worker 0 |--, | file | ,-->| worker 0 |--,
| system | | `------------' | | system | | `------------' |
| | ,---------, | ,------------, | ,-------, ,---------, | | .---------. | .------------. | .-------. .---------.
|metadata|--->| grouper |-+-->| worker 1 |--+-->| muxer |-->| archive | |metadata|--->| grouper |-+-->| worker 1 |--+-->| muxer |-->| archive |
`--------' `---------' | `------------' | `-------' `---------' `--------' `---------' | `------------' | `-------' `---------'
| ... | | ... |
| ,------------, | | .------------. |
`-->| worker N-1 |--' `-->| worker N-1 |--'
`------------' `------------'
@ -864,17 +867,17 @@ worker may access files in the file system either to read them (diff) or
write them (extract). As in plzip, each worker reads members directly from write them (extract). As in plzip, each worker reads members directly from
the archive. the archive.
,--------, .--------.
| file |<---> data to/from each worker below | file |<---> data to/from each worker below
| system | | system |
`--------' ,------------, `--------' .------------.
,-->| worker 0 |--, ,-->| worker 0 |--,
| `------------' | | `------------' |
,---------, | ,------------, | ,-------, ,--------, .---------. | .------------. | .-------. .--------.
| archive |-+-->| worker 1 |--+-->| muxer |-->| stdout | | archive |-+-->| worker 1 |--+-->| muxer |-->| stdout |
`---------' | `------------' | `-------' | stderr | `---------' | `------------' | `-------' | stderr |
| ... | `--------' | ... | `--------'
| ,------------, | | .------------. |
`-->| worker N-1 |--' `-->| worker N-1 |--'
`------------' `------------'
@ -956,7 +959,7 @@ example listing the Silesia corpus on a dual core machine:
On the other hand, multi-threaded '--list' won't detect corruption in On the other hand, multi-threaded '--list' won't detect corruption in
the tar member data because it only decodes the part of each lzip member the tar member data because it only decodes the part of each lzip member
corresponding to the tar member header. This is another reason why the tar corresponding to the tar member header. This is another reason why the tar
headers must provide its own integrity checking. headers must provide their own integrity checking.
7.1 Limitations of multi-threaded extraction 7.1 Limitations of multi-threaded extraction
@ -1101,7 +1104,7 @@ eternity, if not longer.
If you find a bug in tarlz, please send electronic mail to If you find a bug in tarlz, please send electronic mail to
<lzip-bug@nongnu.org>. Include the version number, which you can find by <lzip-bug@nongnu.org>. Include the version number, which you can find by
running 'tarlz --version'. running 'tarlz --version' and 'tarlz -v --check-lib'.
 
File: tarlz.info, Node: Concept index, Prev: Problems, Up: Top File: tarlz.info, Node: Concept index, Prev: Problems, Up: Top
@ -1131,22 +1134,22 @@ Concept index
 
Tag Table: Tag Table:
Node: Top223 Node: Top223
Node: Introduction1212 Node: Introduction1214
Node: Invoking tarlz4020 Node: Invoking tarlz4022
Ref: --data-size6389 Ref: --data-size6436
Ref: --bsolid16341 Ref: --bsolid16388
Node: Portable character set21079 Node: Portable character set21224
Node: File format21874 Node: File format22019
Ref: key_crc3226799 Ref: key_crc3226944
Node: Amendments to pax format32400 Node: Amendments to pax format32572
Ref: crc3233064 Ref: crc3233236
Ref: flawed-compat34375 Ref: flawed-compat34547
Node: Program design37176 Node: Program design37348
Node: Multi-threaded decoding41101 Node: Multi-threaded decoding41273
Node: Minimum archive sizes45590 Node: Minimum archive sizes45764
Node: Examples47728 Node: Examples47902
Node: Problems49744 Node: Problems49918
Node: Concept index50272 Node: Concept index50473
 
End Tag Table End Tag Table

View file

@ -6,8 +6,8 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 14 June 2021 @set UPDATED 5 January 2022
@set VERSION 0.21 @set VERSION 0.22
@dircategory Data Compression @dircategory Data Compression
@direntry @direntry
@ -50,7 +50,7 @@ This manual is for Tarlz (version @value{VERSION}, @value{UPDATED}).
@end menu @end menu
@sp 1 @sp 1
Copyright @copyright{} 2013-2021 Antonio Diaz Diaz. Copyright @copyright{} 2013-2022 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to copy, This manual is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.
@ -137,8 +137,9 @@ tarlz [@var{options}] [@var{files}]
@end example @end example
@noindent @noindent
All operations except @samp{--concatenate} operate on whole trees if any All operations except @samp{--concatenate} and @samp{--compress} operate on
@var{file} is a directory. Tarlz overwrites output files without warning. whole trees if any @var{file} is a directory. All operations except
@samp{--compress} overwrite output files without warning.
On archive creation or appending tarlz archives the files specified, but On archive creation or appending tarlz archives the files specified, but
removes from member names any leading and trailing slashes and any file name removes from member names any leading and trailing slashes and any file name
@ -467,12 +468,13 @@ values range from 1 to 1024. The default value is 64.
@item --check-lib @item --check-lib
Compare the Compare the
@uref{http://www.nongnu.org/lzip/manual/lzlib_manual.html#Library-version,,version of lzlib} @uref{http://www.nongnu.org/lzip/manual/lzlib_manual.html#Library-version,,version of lzlib}
used to compile tarlz with the version actually being used and exit. Report used to compile tarlz with the version actually being used at run time and
any differences found. Exit with error status 1 if differences are found. A exit. Report any differences found. Exit with error status 1 if differences
mismatch may indicate that lzlib is not correctly installed or that a are found. A mismatch may indicate that lzlib is not correctly installed or
different version of lzlib has been installed after compiling tarlz. that a different version of lzlib has been installed after compiling tarlz.
@w{@samp{tarlz -v --check-lib}} shows the version of lzlib being used and Exit with error status 2 if LZ_API_VERSION and LZ_version_string don't
the value of @samp{LZ_API_VERSION} (if defined). match. @w{@samp{tarlz -v --check-lib}} shows the version of lzlib being used
and the value of LZ_API_VERSION (if defined).
@ifnothtml @ifnothtml
@xref{Library version,,,lzlib}. @xref{Library version,,,lzlib}.
@end ifnothtml @end ifnothtml
@ -671,10 +673,11 @@ CRC32-C (Castagnoli) of the extended header data excluding the 8 bytes
representing the CRC <value> itself. The <value> is represented as 8 representing the CRC <value> itself. The <value> is represented as 8
hexadecimal digits in big endian order, hexadecimal digits in big endian order,
@w{@samp{22 GNU.crc32=00000000\n}}. The keyword of the CRC record is @w{@samp{22 GNU.crc32=00000000\n}}. The keyword of the CRC record is
protected by the CRC to guarante that corruption is always detected protected by the CRC to guarante that corruption is always detected when
(except in case of CRC collision). A CRC was chosen because a checksum using @samp{--missing-crc} (except in case of CRC collision). A CRC was
is too weak for a potentially large list of variable sized records. A chosen because a checksum is too weak for a potentially large list of
checksum can't detect simple errors like the swapping of two bytes. variable sized records. A checksum can't detect simple errors like the
swapping of two bytes.
@end table @end table
@ -926,16 +929,16 @@ with the file data read from the file system. The muxer collects processed
packets from the workers, and writes them to the archive. packets from the workers, and writes them to the archive.
@verbatim @verbatim
,--------, .--------.
| data|---> to each worker below | data|---> to each worker below
| | ,------------, | | .------------.
| file | ,-->| worker 0 |--, | file | ,-->| worker 0 |--,
| system | | `------------' | | system | | `------------' |
| | ,---------, | ,------------, | ,-------, ,---------, | | .---------. | .------------. | .-------. .---------.
|metadata|--->| grouper |-+-->| worker 1 |--+-->| muxer |-->| archive | |metadata|--->| grouper |-+-->| worker 1 |--+-->| muxer |-->| archive |
`--------' `---------' | `------------' | `-------' `---------' `--------' `---------' | `------------' | `-------' `---------'
| ... | | ... |
| ,------------, | | .------------. |
`-->| worker N-1 |--' `-->| worker N-1 |--'
`------------' `------------'
@end verbatim @end verbatim
@ -947,17 +950,17 @@ access files in the file system either to read them (diff) or write them
(extract). As in plzip, each worker reads members directly from the archive. (extract). As in plzip, each worker reads members directly from the archive.
@verbatim @verbatim
,--------, .--------.
| file |<---> data to/from each worker below | file |<---> data to/from each worker below
| system | | system |
`--------' ,------------, `--------' .------------.
,-->| worker 0 |--, ,-->| worker 0 |--,
| `------------' | | `------------' |
,---------, | ,------------, | ,-------, ,--------, .---------. | .------------. | .-------. .--------.
| archive |-+-->| worker 1 |--+-->| muxer |-->| stdout | | archive |-+-->| worker 1 |--+-->| muxer |-->| stdout |
`---------' | `------------' | `-------' | stderr | `---------' | `------------' | `-------' | stderr |
| ... | `--------' | ... | `--------'
| ,------------, | | .------------. |
`-->| worker N-1 |--' `-->| worker N-1 |--'
`------------' `------------'
@end verbatim @end verbatim
@ -1041,7 +1044,7 @@ time tarlz -tf silesia.tar.lz (0.020s)
On the other hand, multi-threaded @samp{--list} won't detect corruption in On the other hand, multi-threaded @samp{--list} won't detect corruption in
the tar member data because it only decodes the part of each lzip member the tar member data because it only decodes the part of each lzip member
corresponding to the tar member header. This is another reason why the tar corresponding to the tar member header. This is another reason why the tar
headers must provide its own integrity checking. headers must provide their own integrity checking.
@sp 1 @sp 1
@section Limitations of multi-threaded extraction @section Limitations of multi-threaded extraction
@ -1212,7 +1215,8 @@ for all eternity, if not longer.
If you find a bug in tarlz, please send electronic mail to If you find a bug in tarlz, please send electronic mail to
@email{lzip-bug@@nongnu.org}. Include the version number, which you can @email{lzip-bug@@nongnu.org}. Include the version number, which you can
find by running @w{@samp{tarlz --version}}. find by running @w{@samp{tarlz --version}} and
@w{@samp{tarlz -v --check-lib}}.
@node Concept index @node Concept index

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -159,7 +159,7 @@ void Extended::unknown_keyword( const char * const buf,
} }
// Returns the extended block size, or -1 if error. // Return the size of the extended block, or -1 if error.
long long Extended::format_block( Resizable_buffer & rbuf ) const long long Extended::format_block( Resizable_buffer & rbuf ) const
{ {
if( empty() ) return 0; // no extended data if( empty() ) return 0; // no extended data
@ -295,7 +295,7 @@ void Extended::fill_from_ustar( const Tar_header header )
} }
/* Returns file size from record or from ustar header, and resets file_size_. /* Return file size from record or from ustar header, and reset file_size_.
Used for fast parsing of headers in uncompressed archives. Used for fast parsing of headers in uncompressed archives.
*/ */
long long Extended::get_file_size_and_reset( const Tar_header header ) long long Extended::get_file_size_and_reset( const Tar_header header )

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

154
main.cc
View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -56,7 +56,7 @@ const char * const program_name = "tarlz";
namespace { namespace {
const char * const program_year = "2021"; const char * const program_year = "2022";
const char * invocation_name = program_name; // default value const char * invocation_name = program_name; // default value
@ -146,17 +146,44 @@ void show_version()
} }
int check_lzlib_ver() // <major>.<minor> or <major>.<minor>[a-z.-]*
{
#if defined LZ_API_VERSION && LZ_API_VERSION >= 1012
const unsigned char * p = (unsigned char *)LZ_version_string;
unsigned major = 0, minor = 0;
while( major < 100000 && isdigit( *p ) )
{ major *= 10; major += *p - '0'; ++p; }
if( *p == '.' ) ++p;
else
out: { show_error( "Invalid LZ_version_string in lzlib.h" ); return 2; }
while( minor < 100 && isdigit( *p ) )
{ minor *= 10; minor += *p - '0'; ++p; }
if( *p && *p != '-' && *p != '.' && !std::islower( *p ) ) goto out;
const unsigned version = major * 1000 + minor;
if( LZ_API_VERSION != version )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Version mismatch in lzlib.h: "
"LZ_API_VERSION = %u, should be %u.\n",
program_name, LZ_API_VERSION, version );
return 2;
}
#endif
return 0;
}
int check_lib() int check_lib()
{ {
bool warning = false; int retval = check_lzlib_ver();
if( std::strcmp( LZ_version_string, LZ_version() ) != 0 ) if( std::strcmp( LZ_version_string, LZ_version() ) != 0 )
{ warning = true; { set_retval( retval, 1 );
if( verbosity >= 0 ) if( verbosity >= 0 )
std::printf( "warning: LZ_version_string != LZ_version() (%s vs %s)\n", std::printf( "warning: LZ_version_string != LZ_version() (%s vs %s)\n",
LZ_version_string, LZ_version() ); } LZ_version_string, LZ_version() ); }
#if defined LZ_API_VERSION && LZ_API_VERSION >= 1012 #if defined LZ_API_VERSION && LZ_API_VERSION >= 1012
if( LZ_API_VERSION != LZ_api_version() ) if( LZ_API_VERSION != LZ_api_version() )
{ warning = true; { set_retval( retval, 1 );
if( verbosity >= 0 ) if( verbosity >= 0 )
std::printf( "warning: LZ_API_VERSION != LZ_api_version() (%u vs %u)\n", std::printf( "warning: LZ_API_VERSION != LZ_api_version() (%u vs %u)\n",
LZ_API_VERSION, LZ_api_version() ); } LZ_API_VERSION, LZ_api_version() ); }
@ -173,20 +200,54 @@ int check_lib()
"Using an unknown LZ_API_VERSION\n", LZ_API_VERSION ); "Using an unknown LZ_API_VERSION\n", LZ_API_VERSION );
#endif #endif
} }
return warning; return retval;
} }
unsigned long long getnum( const char * const ptr, // separate large numbers >= 100_000 in groups of 3 digits using '_'
const char * format_num3( unsigned long long num )
{
const char * const si_prefix = "kMGTPEZY";
const char * const binary_prefix = "KMGTPEZY";
enum { buffers = 8, bufsize = 4 * sizeof (long long) };
static char buffer[buffers][bufsize]; // circle of static buffers for printf
static int current = 0;
char * const buf = buffer[current++]; current %= buffers;
char * p = buf + bufsize - 1; // fill the buffer backwards
*p = 0; // terminator
char prefix = 0; // try binary first, then si
for( int i = 0; i < 8 && num >= 1024 && num % 1024 == 0; ++i )
{ num /= 1024; prefix = binary_prefix[i]; }
if( prefix ) *(--p) = 'i';
else
for( int i = 0; i < 8 && num >= 1000 && num % 1000 == 0; ++i )
{ num /= 1000; prefix = si_prefix[i]; }
if( prefix ) *(--p) = prefix;
const bool split = num >= 100000;
for( int i = 0; ; )
{
*(--p) = num % 10 + '0'; num /= 10; if( num == 0 ) break;
if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; }
}
return p;
}
unsigned long long getnum( const char * const arg,
const char * const option_name,
const unsigned long long llimit, const unsigned long long llimit,
const unsigned long long ulimit ) const unsigned long long ulimit )
{ {
char * tail; char * tail;
errno = 0; errno = 0;
unsigned long long result = strtoull( ptr, &tail, 0 ); unsigned long long result = strtoull( arg, &tail, 0 );
if( tail == ptr ) if( tail == arg )
{ {
show_error( "Bad or missing numerical argument.", 0, true ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad or missing numerical argument in "
"option '%s'.\n", program_name, option_name );
std::exit( 1 ); std::exit( 1 );
} }
@ -208,7 +269,9 @@ unsigned long long getnum( const char * const ptr,
} }
if( exponent <= 0 ) if( exponent <= 0 )
{ {
show_error( "Bad multiplier in numerical argument.", 0, true ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad multiplier in numerical argument of "
"option '%s'.\n", program_name, option_name );
std::exit( 1 ); std::exit( 1 );
} }
for( int i = 0; i < exponent; ++i ) for( int i = 0; i < exponent; ++i )
@ -220,7 +283,10 @@ unsigned long long getnum( const char * const ptr,
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE; if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
if( errno ) if( errno )
{ {
show_error( "Numerical argument out of limits." ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Numerical argument out of limits [%s,%s] "
"in option '%s'.\n", program_name, format_num3( llimit ),
format_num3( ulimit ), option_name );
std::exit( 1 ); std::exit( 1 );
} }
return result; return result;
@ -249,10 +315,10 @@ void set_mode( Program_mode & program_mode, const Program_mode new_mode )
} }
void set_mtime( long long & mtime, const char * arg ) void set_mtime( long long & mtime, const char * arg, const char * const pn )
{ {
if( *arg == '@' ) if( *arg == '@' )
{ mtime = getnum( arg + 1, 0, ( 1ULL << 33 ) - 1 ); return; } { mtime = getnum( arg + 1, pn, 0, ( 1ULL << 33 ) - 1 ); return; }
else if( *arg == '.' || *arg == '/' ) else if( *arg == '.' || *arg == '/' )
{ {
struct stat st; struct stat st;
@ -276,22 +342,22 @@ void set_mtime( long long & mtime, const char * arg )
} }
void set_owner( int & owner, const char * const arg ) void set_owner( int & owner, const char * const arg, const char * const pn )
{ {
const struct passwd * const pw = getpwnam( arg ); const struct passwd * const pw = getpwnam( arg );
if( pw ) owner = pw->pw_uid; if( pw ) owner = pw->pw_uid;
else if( std::isdigit( (unsigned char)arg[0] ) ) else if( std::isdigit( (unsigned char)arg[0] ) )
owner = getnum( arg, 0, INT_MAX ); owner = getnum( arg, pn, 0, INT_MAX );
else if( std::strcmp( arg, "root" ) == 0 ) owner = 0; else if( std::strcmp( arg, "root" ) == 0 ) owner = 0;
else { show_file_error( arg, "Invalid owner" ); std::exit( 1 ); } else { show_file_error( arg, "Invalid owner" ); std::exit( 1 ); }
} }
void set_group( int & group, const char * const arg ) void set_group( int & group, const char * const arg, const char * const pn )
{ {
const struct group * const gr = getgrnam( arg ); const struct group * const gr = getgrnam( arg );
if( gr ) group = gr->gr_gid; if( gr ) group = gr->gr_gid;
else if( std::isdigit( (unsigned char)arg[0] ) ) else if( std::isdigit( (unsigned char)arg[0] ) )
group = getnum( arg, 0, INT_MAX ); group = getnum( arg, pn, 0, INT_MAX );
else if( std::strcmp( arg, "root" ) == 0 ) group = 0; else if( std::strcmp( arg, "root" ) == 0 ) group = 0;
else { show_file_error( arg, "Invalid group" ); std::exit( 1 ); } else { show_file_error( arg, "Invalid group" ); std::exit( 1 ); }
} }
@ -308,7 +374,12 @@ int open_instream( const std::string & name )
{ {
const int infd = open( name.c_str(), O_RDONLY | O_BINARY ); const int infd = open( name.c_str(), O_RDONLY | O_BINARY );
if( infd < 0 ) if( infd < 0 )
show_file_error( name.c_str(), "Can't open for reading", errno ); { show_file_error( name.c_str(), "Can't open for reading", errno );
return -1; }
struct stat st; // infd must not be a directory
if( fstat( infd, &st ) == 0 && S_ISDIR( st.st_mode ) )
{ show_file_error( name.c_str(), "Is a directory." );
close( infd ); return -1; }
return infd; return infd;
} }
@ -460,6 +531,9 @@ int main( const int argc, const char * const argv[] )
if( max_workers < 1 || max_workers > INT_MAX / (int)sizeof (pthread_t) ) if( max_workers < 1 || max_workers > INT_MAX / (int)sizeof (pthread_t) )
max_workers = INT_MAX / sizeof (pthread_t); max_workers = INT_MAX / sizeof (pthread_t);
const char * f_pn = 0;
const char * o_pn = 0;
const char * z_pn = 0;
for( int argind = 0; argind < parser.arguments(); ++argind ) for( int argind = 0; argind < parser.arguments(); ++argind )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
@ -470,6 +544,7 @@ int main( const int argc, const char * const argv[] )
if( parser.argument( argind ) != "-" ) cl_opts.filenames_given = true; if( parser.argument( argind ) != "-" ) cl_opts.filenames_given = true;
++cl_opts.num_files; continue; ++cl_opts.num_files; continue;
} }
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & sarg = parser.argument( argind ); const std::string & sarg = parser.argument( argind );
const char * const arg = sarg.c_str(); const char * const arg = sarg.c_str();
switch( code ) switch( code )
@ -478,16 +553,16 @@ int main( const int argc, const char * const argv[] )
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
cl_opts.level = code - '0'; break; cl_opts.level = code - '0'; break;
case 'A': set_mode( cl_opts.program_mode, m_concatenate ); break; case 'A': set_mode( cl_opts.program_mode, m_concatenate ); break;
case 'B': cl_opts.data_size = getnum( arg, min_data_size, max_data_size ); case 'B': cl_opts.data_size =
break; getnum( arg, pn, min_data_size, max_data_size ); break;
case 'c': set_mode( cl_opts.program_mode, m_create ); break; case 'c': set_mode( cl_opts.program_mode, m_create ); break;
case 'C': break; // skip chdir case 'C': break; // skip chdir
case 'd': set_mode( cl_opts.program_mode, m_diff ); break; case 'd': set_mode( cl_opts.program_mode, m_diff ); break;
case 'f': set_archive_name( cl_opts.archive_name, sarg ); break; case 'f': set_archive_name( cl_opts.archive_name, sarg ); f_pn = pn; break;
case 'h': cl_opts.dereference = true; break; case 'h': cl_opts.dereference = true; break;
case 'H': break; // ignore format case 'H': break; // ignore format
case 'n': cl_opts.num_workers = getnum( arg, 0, max_workers ); break; case 'n': cl_opts.num_workers = getnum( arg, pn, 0, max_workers ); break;
case 'o': cl_opts.output_filename = sarg; break; case 'o': cl_opts.output_filename = sarg; o_pn = pn; break;
case 'p': cl_opts.preserve_permissions = true; break; case 'p': cl_opts.preserve_permissions = true; break;
case 'q': verbosity = -1; break; case 'q': verbosity = -1; break;
case 'r': set_mode( cl_opts.program_mode, m_append ); break; case 'r': set_mode( cl_opts.program_mode, m_append ); break;
@ -495,25 +570,25 @@ int main( const int argc, const char * const argv[] )
case 'v': if( verbosity < 4 ) ++verbosity; break; case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0; case 'V': show_version(); return 0;
case 'x': set_mode( cl_opts.program_mode, m_extract ); break; case 'x': set_mode( cl_opts.program_mode, m_extract ); break;
case 'z': set_mode( cl_opts.program_mode, m_compress ); break; case 'z': set_mode( cl_opts.program_mode, m_compress ); z_pn = pn; break;
case opt_ano: set_owner( cl_opts.owner, "root" ); case opt_ano: set_owner( cl_opts.owner, "root", pn );
set_group( cl_opts.group, "root" ); break; set_group( cl_opts.group, "root", pn ); break;
case opt_aso: cl_opts.solidity = asolid; break; case opt_aso: cl_opts.solidity = asolid; break;
case opt_bso: cl_opts.solidity = bsolid; break; case opt_bso: cl_opts.solidity = bsolid; break;
case opt_crc: cl_opts.missing_crc = true; break; case opt_crc: cl_opts.missing_crc = true; break;
case opt_chk: return check_lib(); case opt_chk: return check_lib();
case opt_dbg: cl_opts.debug_level = getnum( arg, 0, 3 ); break; case opt_dbg: cl_opts.debug_level = getnum( arg, pn, 0, 3 ); break;
case opt_del: set_mode( cl_opts.program_mode, m_delete ); break; case opt_del: set_mode( cl_opts.program_mode, m_delete ); break;
case opt_dso: cl_opts.solidity = dsolid; break; case opt_dso: cl_opts.solidity = dsolid; break;
case opt_exc: Exclude::add_pattern( sarg ); break; case opt_exc: Exclude::add_pattern( sarg ); break;
case opt_grp: set_group( cl_opts.group, arg ); break; case opt_grp: set_group( cl_opts.group, arg, pn ); break;
case opt_hlp: show_help( num_online ); return 0; case opt_hlp: show_help( num_online ); return 0;
case opt_id: cl_opts.ignore_ids = true; break; case opt_id: cl_opts.ignore_ids = true; break;
case opt_kd: cl_opts.keep_damaged = true; break; case opt_kd: cl_opts.keep_damaged = true; break;
case opt_mti: set_mtime( cl_opts.mtime, arg ); break; case opt_mti: set_mtime( cl_opts.mtime, arg, pn ); break;
case opt_nso: cl_opts.solidity = no_solid; break; case opt_nso: cl_opts.solidity = no_solid; break;
case opt_out: cl_opts.out_slots = getnum( arg, 1, 1024 ); break; case opt_out: cl_opts.out_slots = getnum( arg, pn, 1, 1024 ); break;
case opt_own: set_owner( cl_opts.owner, arg ); break; case opt_own: set_owner( cl_opts.owner, arg, pn ); break;
case opt_per: cl_opts.permissive = true; break; case opt_per: cl_opts.permissive = true; break;
case opt_sol: cl_opts.solidity = solid; break; case opt_sol: cl_opts.solidity = solid; break;
case opt_un: cl_opts.level = -1; break; case opt_un: cl_opts.level = -1; break;
@ -522,6 +597,21 @@ int main( const int argc, const char * const argv[] )
} }
} // end process options } // end process options
if( cl_opts.program_mode != m_compress && cl_opts.output_filename.size() )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Option '%s' can only be used with "
"'-z, --compress'.\n", program_name, o_pn );
return 1;
}
if( cl_opts.program_mode == m_compress && f_pn )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Option '%s' can't be used with '%s'.\n",
program_name, f_pn, z_pn );
return 1;
}
#if !defined LZ_API_VERSION || LZ_API_VERSION < 1012 // compile-time test #if !defined LZ_API_VERSION || LZ_API_VERSION < 1012 // compile-time test
#error "lzlib 1.12 or newer needed." #error "lzlib 1.12 or newer needed."
#endif #endif

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -201,6 +201,7 @@ public:
void update_byte( uint32_t & crc, const uint8_t byte ) const void update_byte( uint32_t & crc, const uint8_t byte ) const
{ crc = data[(crc^byte)&0xFF] ^ ( crc >> 8 ); } { crc = data[(crc^byte)&0xFF] ^ ( crc >> 8 ); }
// about as fast as it is possible without messing with endianness
void update_buf( uint32_t & crc, const uint8_t * const buffer, void update_buf( uint32_t & crc, const uint8_t * const buffer,
const int size ) const const int size ) const
{ {
@ -392,6 +393,9 @@ struct Cl_options // command line options
}; };
inline void set_retval( int & retval, const int new_val )
{ if( retval < new_val ) retval = new_val; }
const char * const bad_magic_msg = "Bad magic number (file not in lzip format)."; const char * const bad_magic_msg = "Bad magic number (file not in lzip format).";
const char * const bad_dict_msg = "Invalid dictionary size in member header."; const char * const bad_dict_msg = "Invalid dictionary size in member header.";
const char * const corrupt_mm_msg = "Corrupt header in multimember file."; const char * const corrupt_mm_msg = "Corrupt header in multimember file.";

View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# check script for Tarlz - Archiver with multimember lzip compression # check script for Tarlz - Archiver with multimember lzip compression
# Copyright (C) 2013-2021 Antonio Diaz Diaz. # Copyright (C) 2013-2022 Antonio Diaz Diaz.
# #
# This script is free software: you have unlimited permission # This script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
@ -115,6 +115,7 @@ cyg_symlink() { [ ${lwarnc} = 0 ] &&
# test3_bad3.tar.lz because their headers are intact. # test3_bad3.tar.lz because their headers are intact.
"${TARLZ}" --check-lib # just print warning "${TARLZ}" --check-lib # just print warning
[ $? != 2 ] || test_failed $LINENO # unless bad lzlib.h
printf "testing tarlz-%s..." "$2" printf "testing tarlz-%s..." "$2"
"${TARLZ}" -q -tf "${in}" "${TARLZ}" -q -tf "${in}"
@ -158,6 +159,8 @@ touch empty.tar.lz empty.tlz # list an empty lz file
"${TARLZ}" -q -tf empty.tlz "${TARLZ}" -q -tf empty.tlz
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
rm -f empty.tar.lz empty.tlz || framework_failure rm -f empty.tar.lz empty.tlz || framework_failure
"${TARLZ}" -q -cd # test mixed operations
[ $? = 1 ] || test_failed $LINENO
"${TARLZ}" -q -cr "${TARLZ}" -q -cr
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${TARLZ}" -q -ct "${TARLZ}" -q -ct
@ -168,6 +171,14 @@ rm -f empty.tar.lz empty.tlz || framework_failure
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${TARLZ}" -q -ctx "${TARLZ}" -q -ctx
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
for i in A c d r t x -delete ; do # test -o with operations other than -z
"${TARLZ}" -q -$i -o -
[ $? = 1 ] || test_failed $LINENO $i
done
"${TARLZ}" -q -z -f -
[ $? = 1 ] || test_failed $LINENO
"${TARLZ}" -q -z .
[ $? = 1 ] || test_failed $LINENO
"${TARLZ}" -q -tf "${in_tar_lz}" "" "${TARLZ}" -q -tf "${in_tar_lz}" ""
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${TARLZ}" --help > /dev/null || test_failed $LINENO "${TARLZ}" --help > /dev/null || test_failed $LINENO
@ -1059,6 +1070,12 @@ rm -f out3z.tar.lz || framework_failure
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
cmp out outz.tar.lz || test_failed $LINENO cmp out outz.tar.lz || test_failed $LINENO
cmp out3 out3z.tar.lz || test_failed $LINENO cmp out3 out3z.tar.lz || test_failed $LINENO
if [ "${ln_works}" = yes ] ; then
ln -s outz.tar loutz.tar || framework_failure
"${TARLZ}" -0 -z loutz.tar || test_failed $LINENO
cmp loutz.tar.lz outz.tar.lz || test_failed $LINENO
rm -f loutz.tar.lz loutz.tar || framework_failure
fi
rm -f out out3 outz.tar.lz out3z.tar.lz || framework_failure rm -f out out3 outz.tar.lz out3z.tar.lz || framework_failure
# #
for i in --solid --no-solid ; do for i in --solid --no-solid ; do