1
0
Fork 0

Adding upstream version 0.25.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:27:24 +01:00
parent 4f5d0de2b2
commit 8853aa3bf2
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
33 changed files with 317 additions and 280 deletions

View file

@ -1,3 +1,13 @@
2024-01-03 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.25 released.
* New option '--ignore-metadata.
* create.cc, decode.cc, decode_lz.cc:
'#include <sys/types.h>' for major, minor, makedev on BSD systems.
* compress.cc: Reformat file diagnostics as 'PROGRAM: FILE: MESSAGE'.
(compress_archive): Create missing intermediate directories.
* configure, Makefile.in: New variable 'MAKEINFO'.
2023-09-20 Antonio Diaz Diaz <antonio@gnu.org> 2023-09-20 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.24 released. * Version 0.24 released.
@ -42,7 +52,7 @@
* main.cc (getnum): Show option name and valid range if error. * main.cc (getnum): Show option name and valid range if error.
(check_lib): Check that LZ_API_VERSION and LZ_version_string match. (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. (main): Report an error if -o is used with any operation except -z.
* Set variable LIBS from configure. * configure: Set variable LIBS.
2021-06-14 Antonio Diaz Diaz <antonio@gnu.org> 2021-06-14 Antonio Diaz Diaz <antonio@gnu.org>
@ -59,7 +69,7 @@
* Version 0.19 released. * Version 0.19 released.
* extended.cc: Print a diagnostic for each unknown keyword found. * extended.cc: Print a diagnostic for each unknown keyword found.
* tarlz.h: Add a missing '#include <sys/types.h>'. * tarlz.h: Add a missing '#include <sys/types.h>' for 'mode_t'.
2020-11-21 Antonio Diaz Diaz <antonio@gnu.org> 2020-11-21 Antonio Diaz Diaz <antonio@gnu.org>
@ -219,7 +229,7 @@
* Version 0.1 released. * Version 0.1 released.
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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

@ -4,12 +4,11 @@ You will need a C++98 compiler with support for 'long long', and the
compression library lzlib installed. (gcc 3.3.6 or newer is recommended). compression library lzlib installed. (gcc 3.3.6 or newer is recommended).
I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards 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.
Gcc is available at http://gcc.gnu.org. Gcc is available at http://gcc.gnu.org.
Lzlib is available at http://www.nongnu.org/lzip/lzlib.html. Lzlib is available at http://www.nongnu.org/lzip/lzlib.html.
Lzlib must be version 1.12 or newer.
The operating system must allow signal handlers read access to objects with The operating system must allow signal handlers read access to objects with
static storage duration so that the cleanup handler for Control-C can delete static storage duration so that the cleanup handler for Control-C can delete
the partial output file in '-z, --compress' mode. the partial output file in '-z, --compress' mode.
@ -75,7 +74,7 @@ After running 'configure', you can run 'make' and 'make install' as
explained above. explained above.
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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

@ -29,6 +29,10 @@ main.o : main.cc
%.o : %.cc %.o : %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
# prevent 'make' from trying to remake source files
$(VPATH)/configure $(VPATH)/Makefile.in $(VPATH)/doc/$(pkgname).texi : ;
%.h %.cc : ;
$(objs) : Makefile $(objs) : Makefile
arg_parser.o : arg_parser.h arg_parser.o : arg_parser.h
archive_reader.o : tarlz.h lzip_index.h archive_reader.h archive_reader.o : tarlz.h lzip_index.h archive_reader.h
@ -48,7 +52,6 @@ extended.o : tarlz.h
lzip_index.o : tarlz.h lzip_index.h lzip_index.o : tarlz.h lzip_index.h
main.o : tarlz.h arg_parser.h main.o : tarlz.h arg_parser.h
doc : info man doc : info man
info : $(VPATH)/doc/$(pkgname).info info : $(VPATH)/doc/$(pkgname).info

21
NEWS
View file

@ -1,17 +1,14 @@
Changes in version 0.24: Changes in version 0.25:
The option '-C, --directory' is now position-dependent also for diff and The new option '--ignore-metadata', which makes '-d, --diff' ignore
extract. (Reported by Devon Sean McCullough). differences in file permissions, owner and group IDs, and modification time,
has been added.
Option '--uncompressed' can now be omitted if it can be deduced from the '#include <sys/types.h>' for major, minor, makedev on BSD systems.
archive name. (An uncompressed archive name lacks a '.lz' or '.tlz' extension).
The diagnostic shown when a file being archived or an archive being File diagnostics of '-z' have been reformatted as 'PROGRAM: FILE: MESSAGE'.
compressed fails to read, now shows the cause of the failure; end-of-file or
read error.
'-z, --compress' now exits with error status 2 if any input archive is an The option '-o, --output' now creates missing intermediate directories when
empty file. compressing to a file.
A failure in the '--diff' test of the testsuite on OS/2 has been fixed. The variable MAKEINFO has been added to configure and Makefile.in.
(Reported by Elbert Pol).

11
README
View file

@ -6,7 +6,7 @@ lzlib.
Tarlz creates tar archives using a simplified and safer variant of the POSIX Tarlz creates tar archives using a simplified and safer variant of the POSIX
pax format compressed in lzip format, keeping the alignment between tar pax format compressed in lzip format, keeping the alignment between tar
members and lzip members. The resulting multimember tar.lz archive is fully members and lzip members. The resulting multimember tar.lz archive is
backward compatible with standard tar tools like GNU tar, which treat it backward compatible with standard tar tools like GNU tar, which treat it
like any other tar.lz archive. Tarlz can append files to the end of such like any other tar.lz archive. Tarlz can append files to the end of such
compressed archives. compressed archives.
@ -61,7 +61,7 @@ large, making undetected corruption and archiver misbehavior more probable.
Headers and metadata must be protected separately from data because the Headers and metadata must be protected separately from data because the
integrity checking of lzip may not be able to detect the corruption before integrity checking of lzip may not be able to detect the corruption before
the metadata has been used, for example, to create a new file in the wrong the metadata have been used, for example, to create a new file in the wrong
place. place.
Because of the above, tarlz protects the extended records with a Cyclic Because of the above, tarlz protects the extended records with a Cyclic
@ -87,11 +87,10 @@ tar.lz
+===============+=================================================+========+ +===============+=================================================+========+
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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.
The file Makefile.in is a data file used by configure to produce the The file Makefile.in is a data file used by configure to produce the Makefile.
Makefile. It has the same copyright owner and permissions that configure It has the same copyright owner and permissions that configure itself.
itself.

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -76,7 +76,7 @@ void xLZ_decompress_write( LZ_Decoder * const decoder,
Archive_descriptor::Archive_descriptor( const std::string & archive_name ) Archive_descriptor::Archive_descriptor( const std::string & archive_name )
: name( archive_name ), namep( name.empty() ? "(stdin)" : name.c_str() ), : name( archive_name ), namep( name.empty() ? "(stdin)" : name.c_str() ),
infd( non_tty_infd( archive_name, namep ) ), infd( non_tty_infd( archive_name, namep ) ),
lzip_index( infd, true, false ), lzip_index( infd ),
seekable( lseek( infd, 0, SEEK_SET ) == 0 ), seekable( lseek( infd, 0, SEEK_SET ) == 0 ),
indexed( seekable && lzip_index.retval() == 0 ) {} indexed( seekable && lzip_index.retval() == 0 ) {}

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2006-2024 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

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-2023 Antonio Diaz Diaz. Copyright (C) 2006-2024 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

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -227,24 +227,23 @@ bool check_skip_filename( const Cl_options & cl_opts,
} }
bool make_path( const std::string & name ) bool make_dirs( const std::string & name )
{ {
const mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; int i = name.size();
unsigned end = name.size(); // first slash before last component while( i > 0 && name[i-1] == '/' ) --i; // remove trailing slashes
while( i > 0 && name[i-1] != '/' ) --i; // remove last component
while( i > 0 && name[i-1] == '/' ) --i; // remove more slashes
const int dirsize = i; // first slash before last component
while( end > 0 && name[end-1] == '/' ) --end; // remove trailing slashes for( i = 0; i < dirsize; ) // if dirsize == 0, dirname is '/' or empty
while( end > 0 && name[end-1] != '/' ) --end; // remove last component
while( end > 0 && name[end-1] == '/' ) --end; // remove more slashes
unsigned index = 0;
while( index < end )
{ {
while( index < end && name[index] == '/' ) ++index; while( i < dirsize && name[i] == '/' ) ++i;
unsigned first = index; const int first = i;
while( index < end && name[index] != '/' ) ++index; while( i < dirsize && name[i] != '/' ) ++i;
if( first < index ) if( first < i )
{ {
const std::string partial( name, 0, index ); const std::string partial( name, 0, i );
const mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
struct stat st; struct stat st;
if( lstat( partial.c_str(), &st ) == 0 ) if( lstat( partial.c_str(), &st ) == 0 )
{ if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } } { if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } }

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -53,12 +53,11 @@ void cleanup_and_fail( const int retval )
if( delete_output_on_interrupt ) if( delete_output_on_interrupt )
{ {
delete_output_on_interrupt = false; delete_output_on_interrupt = false;
if( verbosity >= 0 ) show_file_error( output_filename.c_str(),
std::fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n", "Deleting output file, if it exists." );
program_name, output_filename.c_str() );
if( outfd >= 0 ) { close( outfd ); outfd = -1; } if( outfd >= 0 ) { close( outfd ); outfd = -1; }
if( std::remove( output_filename.c_str() ) != 0 && errno != ENOENT ) if( std::remove( output_filename.c_str() ) != 0 && errno != ENOENT )
show_error( "WARNING: deletion of output file (apparently) failed." ); show_error( "warning: deletion of output file failed", errno );
} }
std::exit( retval ); std::exit( retval );
} }
@ -103,7 +102,7 @@ void close_and_set_permissions( const struct stat * const in_statsp )
if( in_statsp ) if( in_statsp )
{ {
const mode_t mode = in_statsp->st_mode; const mode_t mode = in_statsp->st_mode;
// fchown will in many cases return with EPERM, which can be safely ignored. // fchown in many cases returns with EPERM, which can be safely ignored.
if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 ) if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 )
{ if( fchmod( outfd, mode ) != 0 ) warning = true; } { if( fchmod( outfd, mode ) != 0 ) warning = true; }
else else
@ -112,10 +111,8 @@ void close_and_set_permissions( const struct stat * const in_statsp )
warning = true; warning = true;
} }
if( close( outfd ) != 0 ) if( close( outfd ) != 0 )
{ { show_file_error( output_filename.c_str(), "Error closing output file",
show_error( "Error closing output file", errno ); errno ); cleanup_and_fail( 1 ); }
cleanup_and_fail( 1 );
}
outfd = -1; outfd = -1;
delete_output_on_interrupt = false; delete_output_on_interrupt = false;
if( in_statsp ) if( in_statsp )
@ -126,7 +123,8 @@ void close_and_set_permissions( const struct stat * const in_statsp )
if( utime( output_filename.c_str(), &t ) != 0 ) warning = true; if( utime( output_filename.c_str(), &t ) != 0 ) warning = true;
} }
if( warning && verbosity >= 1 ) if( warning && verbosity >= 1 )
show_error( "Can't change output file attributes." ); show_file_error( output_filename.c_str(),
"warning: can't change output file attributes", errno );
} }
@ -233,6 +231,9 @@ int compress_archive( const Cl_options & cl_opts,
if( to_file && outfd < 0 && ( is_header || is_zero ) ) if( to_file && outfd < 0 && ( is_header || is_zero ) )
{ {
// open outfd after checking infd // open outfd after checking infd
if( !make_dirs( output_filename ) )
{ show_file_error( output_filename.c_str(), intdir_msg, errno );
return 1; }
outfd = open_outstream( output_filename, true, 0, false ); outfd = open_outstream( output_filename, true, 0, false );
// check tty only once and don't try to delete a tty // check tty only once and don't try to delete a tty
if( outfd < 0 || !check_tty_out() ) { close( infd ); return 1; } if( outfd < 0 || !check_tty_out() ) { close( infd ); return 1; }

66
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-2023 Antonio Diaz Diaz. # Copyright (C) 2013-2024 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.24 pkgversion=0.25
progname=tarlz progname=tarlz
srctrigger=doc/${pkgname}.texi srctrigger=doc/${pkgname}.texi
@ -36,7 +36,7 @@ no_create=
while [ $# != 0 ] ; do while [ $# != 0 ] ; do
# Get the first arg, and shuffle # Get the first arg, and shuffle
option="$1" ; arg2=no option=$1 ; arg2=no
shift shift
# Add the argument quoted to args # Add the argument quoted to args
@ -44,12 +44,12 @@ while [ $# != 0 ] ; do
else args="${args} \"${option}\"" ; fi else args="${args} \"${option}\"" ; fi
# Split out the argument for options that take them # Split out the argument for options that take them
case "${option}" in case ${option} in
*=*) optarg="`echo "${option}" | sed -e 's,^[^=]*=,,;s,/$,,'`" ;; *=*) optarg=`echo "${option}" | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
esac esac
# Process the options # Process the options
case "${option}" in case ${option} in
--help | -h) --help | -h)
echo "Usage: $0 [OPTION]... [VAR=VALUE]..." echo "Usage: $0 [OPTION]... [VAR=VALUE]..."
echo echo
@ -67,10 +67,10 @@ while [ $# != 0 ] ; do
echo " --infodir=DIR info files directory [${infodir}]" echo " --infodir=DIR info files directory [${infodir}]"
echo " --mandir=DIR man pages directory [${mandir}]" echo " --mandir=DIR man pages directory [${mandir}]"
echo " CXX=COMPILER C++ compiler to use [${CXX}]" echo " CXX=COMPILER C++ compiler to use [${CXX}]"
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]" echo " CPPFLAGS=OPTIONS command-line options for the preprocessor [${CPPFLAGS}]"
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 " LIBS=OPTIONS libraries to pass to the linker [${LIBS}]"
echo " MAKEINFO=NAME makeinfo program to use [${MAKEINFO}]" echo " MAKEINFO=NAME makeinfo program to use [${MAKEINFO}]"
echo echo
@ -78,30 +78,30 @@ while [ $# != 0 ] ; do
--version | -V) --version | -V)
echo "Configure script for ${pkgname} version ${pkgversion}" echo "Configure script for ${pkgname} version ${pkgversion}"
exit 0 ;; exit 0 ;;
--srcdir) srcdir="$1" ; arg2=yes ;; --srcdir) srcdir=$1 ; arg2=yes ;;
--prefix) prefix="$1" ; arg2=yes ;; --prefix) prefix=$1 ; arg2=yes ;;
--exec-prefix) exec_prefix="$1" ; arg2=yes ;; --exec-prefix) exec_prefix=$1 ; arg2=yes ;;
--bindir) bindir="$1" ; arg2=yes ;; --bindir) bindir=$1 ; arg2=yes ;;
--datarootdir) datarootdir="$1" ; arg2=yes ;; --datarootdir) datarootdir=$1 ; arg2=yes ;;
--infodir) infodir="$1" ; arg2=yes ;; --infodir) infodir=$1 ; arg2=yes ;;
--mandir) mandir="$1" ; arg2=yes ;; --mandir) mandir=$1 ; arg2=yes ;;
--srcdir=*) srcdir="${optarg}" ;; --srcdir=*) srcdir=${optarg} ;;
--prefix=*) prefix="${optarg}" ;; --prefix=*) prefix=${optarg} ;;
--exec-prefix=*) exec_prefix="${optarg}" ;; --exec-prefix=*) exec_prefix=${optarg} ;;
--bindir=*) bindir="${optarg}" ;; --bindir=*) bindir=${optarg} ;;
--datarootdir=*) datarootdir="${optarg}" ;; --datarootdir=*) datarootdir=${optarg} ;;
--infodir=*) infodir="${optarg}" ;; --infodir=*) infodir=${optarg} ;;
--mandir=*) mandir="${optarg}" ;; --mandir=*) mandir=${optarg} ;;
--no-create) no_create=yes ;; --no-create) no_create=yes ;;
CXX=*) CXX="${optarg}" ;; CXX=*) CXX=${optarg} ;;
CPPFLAGS=*) CPPFLAGS="${optarg}" ;; CPPFLAGS=*) CPPFLAGS=${optarg} ;;
CXXFLAGS=*) CXXFLAGS="${optarg}" ;; CXXFLAGS=*) CXXFLAGS=${optarg} ;;
CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;; CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;;
LDFLAGS=*) LDFLAGS="${optarg}" ;; LDFLAGS=*) LDFLAGS=${optarg} ;;
LIBS=*) LIBS="${optarg} ${LIBS}" ;; LIBS=*) LIBS="${optarg} ${LIBS}" ;;
MAKEINFO=*) MAKEINFO="${optarg}" ;; MAKEINFO=*) MAKEINFO=${optarg} ;;
--*) --*)
echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;; echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;;
@ -128,7 +128,7 @@ if [ -z "${srcdir}" ] ; then
if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then if [ ! -r "${srcdir}/${srctrigger}" ] ; then
## the sed command below emulates the dirname command ## the sed command below emulates the dirname command
srcdir="`echo "$0" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`" srcdir=`echo "$0" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
fi fi
fi fi
@ -175,7 +175,7 @@ echo "MAKEINFO = ${MAKEINFO}"
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-2023 Antonio Diaz Diaz. # Copyright (C) 2013-2024 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
@ -201,5 +201,5 @@ EOF
cat "${srcdir}/Makefile.in" >> Makefile cat "${srcdir}/Makefile.in" >> Makefile
echo "OK. Now you can run make." echo "OK. Now you can run make."
echo "If make fails, check that the compression library lzlib is correctly" echo "If make fails, check that the compression library lzlib is correctly installed"
echo "installed (see INSTALL)." echo "(see INSTALL)."

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -26,6 +26,8 @@
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \ #if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
!defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__ !defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__
#include <sys/sysmacros.h> // for major, minor #include <sys/sysmacros.h> // for major, minor
#else
#include <sys/types.h> // for major, minor
#endif #endif
#include <ftw.h> #include <ftw.h>
#include <grp.h> #include <grp.h>

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -29,6 +29,8 @@
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \ #if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
!defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__ !defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__
#include <sys/sysmacros.h> // for major, minor, makedev #include <sys/sysmacros.h> // for major, minor, makedev
#else
#include <sys/types.h> // for major, minor, makedev
#endif #endif
#include <lzlib.h> #include <lzlib.h>
@ -38,6 +40,9 @@
#include "archive_reader.h" #include "archive_reader.h"
#include "decode.h" #include "decode.h"
#ifndef O_DIRECTORY
#define O_DIRECTORY 0
#endif
namespace { namespace {
@ -124,7 +129,7 @@ int extract_member( const Cl_options & cl_opts, Archive_reader & ar,
if( !show_member_name( extended, header, 1, grbuf ) ) return 1; if( !show_member_name( extended, header, 1, grbuf ) ) return 1;
// remove file (or empty dir) before extraction to prevent following links // remove file (or empty dir) before extraction to prevent following links
std::remove( filename ); std::remove( filename );
if( !make_path( filename ) ) if( !make_dirs( filename ) )
{ {
show_file_error( filename, intdir_msg, errno ); show_file_error( filename, intdir_msg, errno );
set_error_status( 1 ); set_error_status( 1 );
@ -192,7 +197,7 @@ int extract_member( const Cl_options & cl_opts, Archive_reader & ar,
chown( filename, extended.get_uid(), extended.get_gid() ) != 0 ) ) chown( filename, extended.get_uid(), extended.get_gid() ) != 0 ) )
{ {
if( outfd >= 0 ) mode &= ~( S_ISUID | S_ISGID | S_ISVTX ); if( outfd >= 0 ) mode &= ~( S_ISUID | S_ISGID | S_ISVTX );
// chown will in many cases return with EPERM, which can be safely ignored. // chown in many cases returns with EPERM, which can be safely ignored.
if( errno != EPERM && errno != EINVAL ) if( errno != EPERM && errno != EINVAL )
{ show_file_error( filename, chown_msg, errno ); set_error_status( 1 ); } { show_file_error( filename, chown_msg, errno ); set_error_status( 1 ); }
} }
@ -286,7 +291,7 @@ bool compare_file_type( std::string & estr, std::string & ostr,
struct stat st; struct stat st;
bool diff = false, size_differs = false, type_differs = true; bool diff = false, size_differs = false, type_differs = true;
if( hstat( filename, &st, cl_opts.dereference ) != 0 ) if( hstat( filename, &st, cl_opts.dereference ) != 0 )
format_file_error( estr, filename, "warning: Can't stat", errno ); format_file_error( estr, filename, "warning: can't stat", errno );
else if( ( typeflag == tf_regular || typeflag == tf_hiperf ) && else if( ( typeflag == tf_regular || typeflag == tf_hiperf ) &&
!S_ISREG( st.st_mode ) ) !S_ISREG( st.st_mode ) )
format_file_diff( ostr, filename, "Is not a regular file" ); format_file_diff( ostr, filename, "Is not a regular file" );
@ -303,14 +308,14 @@ bool compare_file_type( std::string & estr, std::string & ostr,
else else
{ {
type_differs = false; type_differs = false;
if( typeflag != tf_symlink ) if( typeflag != tf_symlink && !cl_opts.ignore_metadata )
{ {
const mode_t mode = parse_octal( header + mode_o, mode_l ); // 12 bits const mode_t mode = parse_octal( header + mode_o, mode_l ); // 12 bits
if( mode != ( st.st_mode & ( S_ISUID | S_ISGID | S_ISVTX | if( mode != ( st.st_mode & ( S_ISUID | S_ISGID | S_ISVTX |
S_IRWXU | S_IRWXG | S_IRWXO ) ) ) S_IRWXU | S_IRWXG | S_IRWXO ) ) )
{ format_file_diff( ostr, filename, "Mode differs" ); diff = true; } { format_file_diff( ostr, filename, "Mode differs" ); diff = true; }
} }
if( !cl_opts.ignore_ids ) if( !cl_opts.ignore_ids && !cl_opts.ignore_metadata )
{ {
if( extended.get_uid() != (long long)st.st_uid ) if( extended.get_uid() != (long long)st.st_uid )
{ format_file_diff( ostr, filename, "Uid differs" ); diff = true; } { format_file_diff( ostr, filename, "Uid differs" ); diff = true; }
@ -319,7 +324,7 @@ bool compare_file_type( std::string & estr, std::string & ostr,
} }
if( typeflag != tf_symlink ) if( typeflag != tf_symlink )
{ {
if( typeflag != tf_directory && if( typeflag != tf_directory && !cl_opts.ignore_metadata &&
extended.mtime().sec() != (long long)st.st_mtime ) extended.mtime().sec() != (long long)st.st_mtime )
{ {
if( (time_t)extended.mtime().sec() == st.st_mtime ) if( (time_t)extended.mtime().sec() == st.st_mtime )

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -23,7 +23,6 @@ inline bool uid_gid_in_range( const long long uid, const long long gid )
gid == (long long)( (gid_t)gid ); } gid == (long long)( (gid_t)gid ); }
const char * const dotdot_msg = "Contains a '..' component, skipping."; const char * const dotdot_msg = "Contains a '..' component, skipping.";
const char * const intdir_msg = "Failed to create intermediate directory";
const char * const cantln_msg = "Can't %slink '%s' to '%s'"; const char * const cantln_msg = "Can't %slink '%s' to '%s'";
const char * const mkdir_msg = "Can't create directory"; const char * const mkdir_msg = "Can't create directory";
const char * const mknod_msg = "Can't create device node"; const char * const mknod_msg = "Can't create device node";

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -29,6 +29,8 @@
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \ #if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
!defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__ !defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__
#include <sys/sysmacros.h> // for major, minor, makedev #include <sys/sysmacros.h> // for major, minor, makedev
#else
#include <sys/types.h> // for major, minor, makedev
#endif #endif
#include <lzlib.h> #include <lzlib.h>
@ -258,10 +260,10 @@ Trival skip_member_lz( Archive_reader_i & ar, Packet_courier & courier,
Trival compare_member_lz( const Cl_options & cl_opts, Trival compare_member_lz( const Cl_options & cl_opts,
Archive_reader_i & ar, Packet_courier & courier, Archive_reader_i & ar, Packet_courier & courier,
const Extended & extended, const Tar_header header, const Extended & extended, const Tar_header header,
Resizable_buffer & rbuf, const long member_id, Resizable_buffer & rbuf, const long member_id,
const int worker_id ) const int worker_id )
{ {
if( verbosity < 1 ) rbuf()[0] = 0; if( verbosity < 1 ) rbuf()[0] = 0;
else if( !format_member_name( extended, header, rbuf, verbosity > 1 ) ) else if( !format_member_name( extended, header, rbuf, verbosity > 1 ) )
@ -357,7 +359,7 @@ Trival extract_member_lz( const Cl_options & cl_opts,
/* Remove file before extraction to prevent following links. /* Remove file before extraction to prevent following links.
Don't remove an empty dir because other thread may need it. */ Don't remove an empty dir because other thread may need it. */
if( typeflag != tf_directory ) std::remove( filename ); if( typeflag != tf_directory ) std::remove( filename );
if( !make_path( filename ) ) if( !make_dirs( filename ) )
{ {
if( format_file_error( rbuf, filename, intdir_msg, errno ) && if( format_file_error( rbuf, filename, intdir_msg, errno ) &&
!courier.collect_packet( member_id, worker_id, rbuf(), Packet::diag ) ) !courier.collect_packet( member_id, worker_id, rbuf(), Packet::diag ) )
@ -451,7 +453,7 @@ Trival extract_member_lz( const Cl_options & cl_opts,
chown( filename, extended.get_uid(), extended.get_gid() ) != 0 ) ) chown( filename, extended.get_uid(), extended.get_gid() ) != 0 ) )
{ {
if( outfd >= 0 ) mode &= ~( S_ISUID | S_ISGID | S_ISVTX ); if( outfd >= 0 ) mode &= ~( S_ISUID | S_ISGID | S_ISVTX );
// chown will in many cases return with EPERM, which can be safely ignored. // chown in many cases returns with EPERM, which can be safely ignored.
if( errno != EPERM && errno != EINVAL ) if( errno != EPERM && errno != EINVAL )
{ {
if( format_file_error( rbuf, filename, chown_msg, errno ) && if( format_file_error( rbuf, filename, chown_msg, errno ) &&

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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.49.2. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH TARLZ "1" "September 2023" "tarlz 0.24" "User Commands" .TH TARLZ "1" "January 2024" "tarlz 0.25" "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
@ -10,12 +10,12 @@ Tarlz is a massively parallel (multi\-threaded) combined implementation of
the tar archiver and the lzip compressor. Tarlz uses the compression library the tar archiver and the lzip compressor. Tarlz uses the compression library
lzlib. lzlib.
.PP .PP
Tarlz creates, lists, and extracts archives in a simplified and safer Tarlz creates tar archives using a simplified and safer variant of the POSIX
variant of the POSIX pax format compressed in lzip format, keeping the pax format compressed in lzip format, keeping the alignment between tar
alignment between tar members and lzip members. The resulting multimember members and lzip members. The resulting multimember tar.lz archive is
tar.lz archive is fully backward compatible with standard tar tools like GNU backward compatible with standard tar tools like GNU tar, which treat it
tar, which treat it like any other tar.lz archive. Tarlz can append files to like any other tar.lz archive. Tarlz can append files to the end of such
the end of such compressed archives. compressed archives.
.PP .PP
Keeping the alignment between tar members and lzip members has two Keeping the alignment between tar members and lzip members has two
advantages. It adds an indexed lzip layer on top of the tar archive, making advantages. It adds an indexed lzip layer on top of the tar archive, making
@ -127,6 +127,9 @@ exclude files matching a shell pattern
\fB\-\-ignore\-ids\fR \fB\-\-ignore\-ids\fR
ignore differences in owner and group IDs ignore differences in owner and group IDs
.TP .TP
\fB\-\-ignore\-metadata\fR
compare only file size and file content
.TP
\fB\-\-ignore\-overflow\fR \fB\-\-ignore\-overflow\fR
ignore mtime overflow differences on 32\-bit ignore mtime overflow differences on 32\-bit
.TP .TP
@ -149,7 +152,7 @@ If no archive is specified, tarlz tries to read it from standard input or
write it to standard output. write it to standard output.
.PP .PP
Exit status: 0 for a normal exit, 1 for environmental problems Exit status: 0 for a normal exit, 1 for environmental problems
(file not found, files differ, invalid command line options, I/O errors, (file not found, files differ, invalid command\-line options, I/O errors,
etc), 2 to indicate a corrupt or invalid input file, 3 for an internal etc), 2 to indicate a corrupt or invalid input file, 3 for an internal
consistency error (e.g., bug) which caused tarlz to panic. consistency error (e.g., bug) which caused tarlz to panic.
.SH "REPORTING BUGS" .SH "REPORTING BUGS"
@ -157,8 +160,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 2023 Antonio Diaz Diaz. Copyright \(co 2024 Antonio Diaz Diaz.
Using lzlib 1.13 Using lzlib 1.14\-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,12 +11,12 @@ File: tarlz.info, Node: Top, Next: Introduction, Up: (dir)
Tarlz Manual Tarlz Manual
************ ************
This manual is for Tarlz (version 0.24, 20 September 2023). This manual is for Tarlz (version 0.25, 3 January 2024).
* Menu: * Menu:
* Introduction:: Purpose and features of tarlz * Introduction:: Purpose and features of tarlz
* Invoking tarlz:: Command line interface * Invoking tarlz:: Command-line interface
* Portable character set:: POSIX portable filename character set * Portable character set:: POSIX portable filename character set
* File format:: Detailed format of the compressed archive * File format:: Detailed format of the compressed archive
* Amendments to pax format:: The reasons for the differences with pax * Amendments to pax format:: The reasons for the differences with pax
@ -28,7 +28,7 @@ This manual is for Tarlz (version 0.24, 20 September 2023).
* Concept index:: Index of concepts * Concept index:: Index of concepts
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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.
@ -46,8 +46,8 @@ library lzlib.
Tarlz creates tar archives using a simplified and safer variant of the Tarlz creates tar archives using a simplified and safer variant of the
POSIX pax format compressed in lzip format, keeping the alignment between POSIX pax format compressed in lzip format, keeping the alignment between
tar members and lzip members. The resulting multimember tar.lz archive is tar members and lzip members. The resulting multimember tar.lz archive is
fully backward compatible with standard tar tools like GNU tar, which treat backward compatible with standard tar tools like GNU tar, which treat it
it like any other tar.lz archive. Tarlz can append files to the end of such like any other tar.lz archive. Tarlz can append files to the end of such
compressed archives. compressed archives.
Keeping the alignment between tar members and lzip members has two Keeping the alignment between tar members and lzip members has two
@ -433,6 +433,12 @@ to '-1 --solid'.
Make '--diff' ignore differences in owner and group IDs. This option is Make '--diff' ignore differences in owner and group IDs. This option is
useful when comparing an '--anonymous' archive. useful when comparing an '--anonymous' archive.
'--ignore-metadata'
Make '--diff' ignore any differences in metadata (file permissions,
owner and group IDs, modification time). Compare only file type, file
size, and file content. This option is useful when file permissions
have not been fully restored because uid/gid changed on extraction.
'--ignore-overflow' '--ignore-overflow'
Make '--diff' ignore differences in mtime caused by overflow on 32-bit Make '--diff' ignore differences in mtime caused by overflow on 32-bit
systems with a 32-bit time_t. systems with a 32-bit time_t.
@ -485,7 +491,7 @@ to '-1 --solid'.
Exit status: 0 for a normal exit, 1 for environmental problems (file not Exit status: 0 for a normal exit, 1 for environmental problems (file not
found, files differ, invalid command line options, I/O errors, etc), 2 to found, files differ, invalid command-line options, I/O errors, etc), 2 to
indicate a corrupt or invalid input file, 3 for an internal consistency indicate a corrupt or invalid input file, 3 for an internal consistency
error (e.g., bug) which caused tarlz to panic. error (e.g., bug) which caused tarlz to panic.
@ -529,7 +535,7 @@ In the diagram below, a box like this:
bytes (for example 512). bytes (for example 512).
A tar.lz file consists of a series of lzip members (compressed data A tar.lz file consists of one or more lzip members (compressed data
sets). The members simply appear one after another in the file, with no sets). The members simply appear one after another in the file, with no
additional information before, between, or after them. additional information before, between, or after them.
@ -564,7 +570,7 @@ binary zeros, interpreted as an end-of-archive indicator. These EOA blocks
are either compressed in a separate lzip member or compressed along with the are either compressed in a separate lzip member or compressed along with the
tar members contained in the last lzip member. For a compressed archive to tar members contained in the last lzip member. For a compressed archive to
be recognized by tarlz as appendable, the last lzip member must contain be recognized by tarlz as appendable, the last lzip member must contain
between 512 and 32256 zeros alone. between 512 and 32256 zeros alone (without any non-zero bytes).
The diagram below shows the correspondence between each tar member The diagram below shows the correspondence between each tar member
(formed by one or two headers plus optional data) in the tar archive and (formed by one or two headers plus optional data) in the tar archive and
@ -618,7 +624,7 @@ space, equal-sign, and newline.
'gid' 'gid'
The unsigned decimal representation of the group ID of the group that The unsigned decimal representation of the group ID of the group that
owns the following file. The gid record is created only for files with owns the following file. The gid record is created only for files with
a group ID greater than 2_097_151 (octal 7777777). *Note a group ID greater than 2_097_151 (octal 7_777_777). *Note
ustar-uid-gid::. ustar-uid-gid::.
'linkpath' 'linkpath'
@ -653,13 +659,14 @@ space, equal-sign, and newline.
digits from the ISO/IEC 646:1991 (ASCII) standard. This record digits from the ISO/IEC 646:1991 (ASCII) standard. This record
overrides the field 'size' in the following ustar header block. The overrides the field 'size' in the following ustar header block. The
size record is created only for files with a size value greater than size record is created only for files with a size value greater than
8_589_934_591 (octal 77777777777); that is, 8 GiB (2^33 bytes) or 8_589_934_591 (octal 77_777_777_777); that is, 8 GiB (2^33 bytes) or
larger. larger.
'uid' 'uid'
The unsigned decimal representation of the user ID of the file owner The unsigned decimal representation of the user ID of the file owner
of the following file. The uid record is created only for files with a of the following file. The uid record is created only for files with a
user ID greater than 2_097_151 (octal 7777777). *Note ustar-uid-gid::. user ID greater than 2_097_151 (octal 7_777_777). *Note
ustar-uid-gid::.
'GNU.crc32' 'GNU.crc32'
CRC32-C (Castagnoli) of the extended header data excluding the 8 bytes CRC32-C (Castagnoli) of the extended header data excluding the 8 bytes
@ -737,7 +744,7 @@ S_IROTH 00004 S_IWOTH 00002 S_IXOTH 00001
The fields 'uid' and 'gid' are the user and group IDs of the owner and The fields 'uid' and 'gid' are the user and group IDs of the owner and
group of the file, respectively. If the file uid or gid are greater than group of the file, respectively. If the file uid or gid are greater than
2_097_151 (octal 7777777), an extended record is used to store the uid or 2_097_151 (octal 7_777_777), an extended record is used to store the uid or
gid. gid.
The field 'size' contains the octal representation of the size of the The field 'size' contains the octal representation of the size of the
@ -747,13 +754,13 @@ records following the header is (size / 512) rounded to the next integer.
For all other values of typeflag, tarlz either sets the size field to 0 or For all other values of typeflag, tarlz either sets the size field to 0 or
ignores it, and does not store or expect any logical records following the ignores it, and does not store or expect any logical records following the
header. If the file size is larger than 8_589_934_591 bytes header. If the file size is larger than 8_589_934_591 bytes
(octal 77777777777), an extended record is used to store the file size. (octal 77_777_777_777), an extended record is used to store the file size.
The field 'mtime' contains the octal representation of the modification The field 'mtime' contains the octal representation of the modification
time of the file at the time it was archived, obtained from the function time of the file at the time it was archived, obtained from the function
'stat'. If the modification time is negative or larger than 8_589_934_591 'stat'. If the modification time is negative or larger than 8_589_934_591
(octal 77777777777) seconds since the epoch, an extended record is used to (octal 77_777_777_777) seconds since the epoch, an extended record is used
store the modification time. The ustar range of mtime goes from to store the modification time. The ustar range of mtime goes from
'1970-01-01 00:00:00 UTC' to '2242-03-16 12:56:31 UTC'. '1970-01-01 00:00:00 UTC' to '2242-03-16 12:56:31 UTC'.
The field 'chksum' contains the octal representation of the value of the The field 'chksum' contains the octal representation of the value of the
@ -835,7 +842,7 @@ more probable.
Headers and metadata must be protected separately from data because the Headers and metadata must be protected separately from data because the
integrity checking of lzip may not be able to detect the corruption before integrity checking of lzip may not be able to detect the corruption before
the metadata has been used, for example, to create a new file in the wrong the metadata have been used, for example, to create a new file in the wrong
place. place.
Because of the above, tarlz protects the extended records with a Cyclic Because of the above, tarlz protects the extended records with a Cyclic
@ -923,7 +930,7 @@ There is no portable way to tell what charset a text string is coded into.
Therefore, tarlz stores all fields representing text strings unmodified, Therefore, tarlz stores all fields representing text strings unmodified,
without conversion to UTF-8 nor any other transformation. This prevents without conversion to UTF-8 nor any other transformation. This prevents
accidental double UTF-8 conversions. If the need arises this behavior will accidental double UTF-8 conversions. If the need arises this behavior will
be adjusted with a command line option in the future. be adjusted with a command-line option in the future.
 
File: tarlz.info, Node: Program design, Next: Multi-threaded decoding, Prev: Amendments to pax format, Up: Top File: tarlz.info, Node: Program design, Next: Multi-threaded decoding, Prev: Amendments to pax format, Up: Top
@ -1252,25 +1259,25 @@ Concept index
 
Tag Table: Tag Table:
Node: Top216 Node: Top216
Node: Introduction1210 Node: Introduction1207
Node: Invoking tarlz4041 Node: Invoking tarlz4032
Ref: --data-size13085 Ref: --data-size13076
Ref: --bsolid17521 Ref: --bsolid17512
Node: Portable character set23119 Node: Portable character set23425
Node: File format23762 Node: File format24068
Ref: key_crc3230703 Ref: key_crc3231050
Ref: ustar-uid-gid33968 Ref: ustar-uid-gid34315
Ref: ustar-mtime34770 Ref: ustar-mtime35122
Node: Amendments to pax format36770 Node: Amendments to pax format37125
Ref: crc3237479 Ref: crc3237834
Ref: flawed-compat38790 Ref: flawed-compat39146
Node: Program design42872 Node: Program design43228
Node: Multi-threaded decoding46797 Node: Multi-threaded decoding47153
Ref: mt-extraction50078 Ref: mt-extraction50434
Node: Minimum archive sizes51384 Node: Minimum archive sizes51740
Node: Examples53511 Node: Examples53867
Node: Problems55878 Node: Problems56234
Node: Concept index56433 Node: Concept index56789
 
End Tag Table End Tag Table

View file

@ -6,8 +6,8 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 20 September 2023 @set UPDATED 3 January 2024
@set VERSION 0.24 @set VERSION 0.25
@dircategory Archiving @dircategory Archiving
@direntry @direntry
@ -37,7 +37,7 @@ This manual is for Tarlz (version @value{VERSION}, @value{UPDATED}).
@menu @menu
* Introduction:: Purpose and features of tarlz * Introduction:: Purpose and features of tarlz
* Invoking tarlz:: Command line interface * Invoking tarlz:: Command-line interface
* Portable character set:: POSIX portable filename character set * Portable character set:: POSIX portable filename character set
* File format:: Detailed format of the compressed archive * File format:: Detailed format of the compressed archive
* Amendments to pax format:: The reasons for the differences with pax * Amendments to pax format:: The reasons for the differences with pax
@ -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-2023 Antonio Diaz Diaz. Copyright @copyright{} 2013-2024 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.
@ -68,7 +68,7 @@ compression library @uref{http://www.nongnu.org/lzip/lzlib.html,,lzlib}.
Tarlz creates tar archives using a simplified and safer variant of the POSIX Tarlz creates tar archives using a simplified and safer variant of the POSIX
pax format compressed in lzip format, keeping the alignment between tar pax format compressed in lzip format, keeping the alignment between tar
members and lzip members. The resulting multimember tar.lz archive is fully members and lzip members. The resulting multimember tar.lz archive is
backward compatible with standard tar tools like GNU tar, which treat it backward compatible with standard tar tools like GNU tar, which treat it
like any other tar.lz archive. Tarlz can append files to the end of such like any other tar.lz archive. Tarlz can append files to the end of such
compressed archives. compressed archives.
@ -477,6 +477,12 @@ Multiple @option{--exclude} options can be specified.
Make @option{--diff} ignore differences in owner and group IDs. This option is Make @option{--diff} ignore differences in owner and group IDs. This option is
useful when comparing an @option{--anonymous} archive. useful when comparing an @option{--anonymous} archive.
@item --ignore-metadata
Make @option{--diff} ignore any differences in metadata (file permissions,
owner and group IDs, modification time). Compare only file type, file size,
and file content. This option is useful when file permissions have not been
fully restored because uid/gid changed on extraction.
@item --ignore-overflow @item --ignore-overflow
Make @option{--diff} ignore differences in mtime caused by overflow on 32-bit Make @option{--diff} ignore differences in mtime caused by overflow on 32-bit
systems with a 32-bit time_t. systems with a 32-bit time_t.
@ -534,7 +540,7 @@ keyword appearing in the same block of extended records.
@end table @end table
Exit status: 0 for a normal exit, 1 for environmental problems Exit status: 0 for a normal exit, 1 for environmental problems
(file not found, files differ, invalid command line options, I/O errors, (file not found, files differ, invalid command-line options, I/O errors,
etc), 2 to indicate a corrupt or invalid input file, 3 for an internal etc), 2 to indicate a corrupt or invalid input file, 3 for an internal
consistency error (e.g., bug) which caused tarlz to panic. consistency error (e.g., bug) which caused tarlz to panic.
@ -582,7 +588,7 @@ represents a variable number of bytes or a fixed but large number of
bytes (for example 512). bytes (for example 512).
@sp 1 @sp 1
A tar.lz file consists of a series of lzip members (compressed data sets). A tar.lz file consists of one or more lzip members (compressed data sets).
The members simply appear one after another in the file, with no additional The members simply appear one after another in the file, with no additional
information before, between, or after them. information before, between, or after them.
@ -622,7 +628,7 @@ binary zeros, interpreted as an end-of-archive indicator. These EOA blocks
are either compressed in a separate lzip member or compressed along with the are either compressed in a separate lzip member or compressed along with the
tar members contained in the last lzip member. For a compressed archive to tar members contained in the last lzip member. For a compressed archive to
be recognized by tarlz as appendable, the last lzip member must contain be recognized by tarlz as appendable, the last lzip member must contain
between 512 and 32256 zeros alone. between 512 and 32256 zeros alone (without any non-zero bytes).
The diagram below shows the correspondence between each tar member (formed The diagram below shows the correspondence between each tar member (formed
by one or two headers plus optional data) in the tar archive and each by one or two headers plus optional data) in the tar archive and each
@ -694,7 +700,7 @@ time outside of the ustar range. @xref{ustar-mtime}.
@item gid @item gid
The unsigned decimal representation of the group ID of the group that owns The unsigned decimal representation of the group ID of the group that owns
the following file. The gid record is created only for files with a group ID the following file. The gid record is created only for files with a group ID
greater than 2_097_151 (octal 7777777). @xref{ustar-uid-gid}. greater than 2_097_151 @w{(octal 7_777_777)}. @xref{ustar-uid-gid}.
@item linkpath @item linkpath
The file name of a link being created to another file, of any type, The file name of a link being created to another file, of any type,
@ -726,12 +732,12 @@ The size of the file in bytes, expressed as a decimal number using digits
from the ISO/IEC 646:1991 (ASCII) standard. This record overrides the field from the ISO/IEC 646:1991 (ASCII) standard. This record overrides the field
@samp{size} in the following ustar header block. The size record is created @samp{size} in the following ustar header block. The size record is created
only for files with a size value greater than 8_589_934_591 only for files with a size value greater than 8_589_934_591
@w{(octal 77777777777)}; that is, @w{8 GiB} (2^33 bytes) or larger. @w{(octal 77_777_777_777)}; that is, @w{8 GiB} (2^33 bytes) or larger.
@item uid @item uid
The unsigned decimal representation of the user ID of the file owner of the The unsigned decimal representation of the user ID of the file owner of the
following file. The uid record is created only for files with a user ID following file. The uid record is created only for files with a user ID
greater than 2_097_151 (octal 7777777). @xref{ustar-uid-gid}. greater than 2_097_151 @w{(octal 7_777_777)}. @xref{ustar-uid-gid}.
@anchor{key_crc32} @anchor{key_crc32}
@item GNU.crc32 @item GNU.crc32
@ -815,7 +821,8 @@ table shows the symbolic name of each bit and its octal value:
@anchor{ustar-uid-gid} @anchor{ustar-uid-gid}
The fields @samp{uid} and @samp{gid} are the user and group IDs of the owner The fields @samp{uid} and @samp{gid} are the user and group IDs of the owner
and group of the file, respectively. If the file uid or gid are greater than and group of the file, respectively. If the file uid or gid are greater than
2_097_151 (octal 7777777), an extended record is used to store the uid or gid. 2_097_151 @w{(octal 7_777_777)}, an extended record is used to store the uid
or gid.
The field @samp{size} contains the octal representation of the size of the The field @samp{size} contains the octal representation of the size of the
file in bytes. If the field @samp{typeflag} specifies a file of type '0' file in bytes. If the field @samp{typeflag} specifies a file of type '0'
@ -824,13 +831,13 @@ records following the header is @w{(size / 512)} rounded to the next
integer. For all other values of typeflag, tarlz either sets the size field integer. For all other values of typeflag, tarlz either sets the size field
to 0 or ignores it, and does not store or expect any logical records to 0 or ignores it, and does not store or expect any logical records
following the header. If the file size is larger than 8_589_934_591 bytes following the header. If the file size is larger than 8_589_934_591 bytes
@w{(octal 77777777777)}, an extended record is used to store the file size. @w{(octal 77_777_777_777)}, an extended record is used to store the file size.
@anchor{ustar-mtime} @anchor{ustar-mtime}
The field @samp{mtime} contains the octal representation of the modification The field @samp{mtime} contains the octal representation of the modification
time of the file at the time it was archived, obtained from the function time of the file at the time it was archived, obtained from the function
@samp{stat}. If the modification time is negative or larger than @samp{stat}. If the modification time is negative or larger than
8_589_934_591 @w{(octal 77777777777)} seconds since the epoch, an extended 8_589_934_591 @w{(octal 77_777_777_777)} seconds since the epoch, an extended
record is used to store the modification time. The ustar range of mtime goes record is used to store the modification time. The ustar range of mtime goes
from @w{@samp{1970-01-01 00:00:00 UTC}} to @w{@samp{2242-03-16 12:56:31 UTC}}. from @w{@samp{1970-01-01 00:00:00 UTC}} to @w{@samp{2242-03-16 12:56:31 UTC}}.
@ -914,7 +921,7 @@ large, making undetected corruption and archiver misbehavior more probable.
Headers and metadata must be protected separately from data because the Headers and metadata must be protected separately from data because the
integrity checking of lzip may not be able to detect the corruption before integrity checking of lzip may not be able to detect the corruption before
the metadata has been used, for example, to create a new file in the wrong the metadata have been used, for example, to create a new file in the wrong
place. place.
Because of the above, tarlz protects the extended records with a Cyclic Because of the above, tarlz protects the extended records with a Cyclic
@ -999,7 +1006,7 @@ There is no portable way to tell what charset a text string is coded into.
Therefore, tarlz stores all fields representing text strings unmodified, Therefore, tarlz stores all fields representing text strings unmodified,
without conversion to UTF-8 nor any other transformation. This prevents without conversion to UTF-8 nor any other transformation. This prevents
accidental double UTF-8 conversions. If the need arises this behavior will accidental double UTF-8 conversions. If the need arises this behavior will
be adjusted with a command line option in the future. be adjusted with a command-line option in the future.
@node Program design @node Program design

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -354,7 +354,7 @@ bool Extended::parse( const char * const buf, const int edsize,
if( stored_crc != computed_crc ) if( stored_crc != computed_crc )
{ {
if( verbosity >= 2 ) if( verbosity >= 2 )
std::fprintf( stderr, "CRC32C = %08X\n", (unsigned)computed_crc ); std::fprintf( stderr, "CRC32-C = %08X\n", (unsigned)computed_crc );
return false; return false;
} }
} }

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -47,17 +47,16 @@ const char * bad_version( const unsigned version )
} // end namespace } // end namespace
bool Lzip_index::check_header_error( const Lzip_header & header, bool Lzip_index::check_header( const Lzip_header & header, const bool first )
const bool first )
{ {
if( !header.check_magic() ) if( !header.check_magic() )
{ error_ = bad_magic_msg; retval_ = 2; if( first ) bad_magic_ = true; { error_ = bad_magic_msg; retval_ = 2; if( first ) bad_magic_ = true;
return true; } return false; }
if( !header.check_version() ) if( !header.check_version() )
{ error_ = bad_version( header.version() ); retval_ = 2; return true; } { error_ = bad_version( header.version() ); retval_ = 2; return false; }
if( !isvalid_ds( header.dictionary_size() ) ) if( !isvalid_ds( header.dictionary_size() ) )
{ error_ = bad_dict_msg; retval_ = 2; return true; } { error_ = bad_dict_msg; retval_ = 2; return false; }
return false; return true;
} }
void Lzip_index::set_errno_error( const char * const msg ) void Lzip_index::set_errno_error( const char * const msg )
@ -78,16 +77,14 @@ void Lzip_index::set_num_error( const char * const msg, unsigned long long num )
bool Lzip_index::read_header( const int fd, Lzip_header & header, bool Lzip_index::read_header( const int fd, Lzip_header & header,
const long long pos ) const long long pos )
{ {
if( seek_read( fd, header.data, Lzip_header::size, pos ) != Lzip_header::size ) if( seek_read( fd, header.data, header.size, pos ) != header.size )
{ set_errno_error( "Error reading member header: " ); return false; } { set_errno_error( "Error reading member header: " ); return false; }
return true; return true;
} }
// If successful, push last member and set pos to member header. // If successful, push last member and set pos to member header.
bool Lzip_index::skip_trailing_data( const int fd, unsigned long long & pos, bool Lzip_index::skip_trailing_data( const int fd, unsigned long long & pos )
const bool ignore_trailing,
const bool loose_trailing )
{ {
if( pos < min_member_size ) return false; if( pos < min_member_size ) return false;
enum { block_size = 16384, enum { block_size = 16384,
@ -108,34 +105,31 @@ bool Lzip_index::skip_trailing_data( const int fd, unsigned long long & pos,
if( buffer[i-1] <= max_msb ) // most significant byte of member_size if( buffer[i-1] <= max_msb ) // most significant byte of member_size
{ {
const Lzip_trailer & trailer = const Lzip_trailer & trailer =
*(const Lzip_trailer *)( buffer + i - Lzip_trailer::size ); *(const Lzip_trailer *)( buffer + i - trailer.size );
const unsigned long long member_size = trailer.member_size(); const unsigned long long member_size = trailer.member_size();
if( member_size == 0 ) // skip trailing zeros if( member_size == 0 ) // skip trailing zeros
{ while( i > Lzip_trailer::size && buffer[i-9] == 0 ) --i; continue; } { while( i > trailer.size && buffer[i-9] == 0 ) --i; continue; }
if( member_size > ipos + i || !trailer.check_consistency() ) if( member_size > ipos + i || !trailer.check_consistency() ) continue;
continue;
Lzip_header header; Lzip_header header;
if( !read_header( fd, header, ipos + i - member_size ) ) return false; if( !read_header( fd, header, ipos + i - member_size ) ) return false;
if( !header.check() ) continue; if( !header.check() ) continue;
const Lzip_header & header2 = *(const Lzip_header *)( buffer + i ); const Lzip_header & header2 = *(const Lzip_header *)( buffer + i );
const bool full_h2 = bsize - i >= Lzip_header::size; const bool full_h2 = bsize - i >= header.size;
if( header2.check_prefix( bsize - i ) ) // last member if( header2.check_prefix( bsize - i ) ) // last member
{ {
if( !full_h2 ) error_ = "Last member in input file is truncated."; if( !full_h2 ) error_ = "Last member in input file is truncated.";
else if( !check_header_error( header2, false ) ) else if( check_header( header2, false ) )
error_ = "Last member in input file is truncated or corrupt."; error_ = "Last member in input file is truncated or corrupt.";
retval_ = 2; return false; retval_ = 2; return false;
} }
if( !loose_trailing && full_h2 && header2.check_corrupt() ) if( full_h2 && header2.check_corrupt() )
{ error_ = corrupt_mm_msg; retval_ = 2; return false; } { error_ = corrupt_mm_msg; retval_ = 2; return false; }
if( !ignore_trailing ) pos = ipos + i - member_size; // good member
{ error_ = trailing_msg; retval_ = 2; return false; }
pos = ipos + i - member_size;
const unsigned dictionary_size = header.dictionary_size(); const unsigned dictionary_size = header.dictionary_size();
member_vector.push_back( Member( 0, trailer.data_size(), pos,
member_size, dictionary_size ) );
if( dictionary_size_ < dictionary_size ) if( dictionary_size_ < dictionary_size )
dictionary_size_ = dictionary_size; dictionary_size_ = dictionary_size;
member_vector.push_back( Member( 0, trailer.data_size(), pos,
member_size, dictionary_size ) );
return true; return true;
} }
if( ipos == 0 ) if( ipos == 0 )
@ -150,8 +144,7 @@ bool Lzip_index::skip_trailing_data( const int fd, unsigned long long & pos,
} }
Lzip_index::Lzip_index( const int infd, const bool ignore_trailing, Lzip_index::Lzip_index( const int infd )
const bool loose_trailing )
: insize( lseek( infd, 0, SEEK_END ) ), retval_( 0 ), dictionary_size_( 0 ), : insize( lseek( infd, 0, SEEK_END ) ), retval_( 0 ), dictionary_size_( 0 ),
bad_magic_( false ) bad_magic_( false )
{ {
@ -164,42 +157,38 @@ Lzip_index::Lzip_index( const int infd, const bool ignore_trailing,
retval_ = 2; return; } retval_ = 2; return; }
Lzip_header header; Lzip_header header;
if( !read_header( infd, header, 0 ) ) return; if( !read_header( infd, header, 0 ) ||
if( check_header_error( header, true ) ) return; !check_header( header, true ) ) return;
unsigned long long pos = insize; // always points to a header or to EOF unsigned long long pos = insize; // always points to a header or to EOF
while( pos >= min_member_size ) while( pos >= min_member_size )
{ {
Lzip_trailer trailer; Lzip_trailer trailer;
if( seek_read( infd, trailer.data, Lzip_trailer::size, if( seek_read( infd, trailer.data, trailer.size, pos - trailer.size ) !=
pos - Lzip_trailer::size ) != Lzip_trailer::size ) trailer.size )
{ set_errno_error( "Error reading member trailer: " ); break; } { set_errno_error( "Error reading member trailer: " ); break; }
const unsigned long long member_size = trailer.member_size(); const unsigned long long member_size = trailer.member_size();
if( member_size > pos || !trailer.check_consistency() ) // bad trailer if( member_size > pos || !trailer.check_consistency() ) // bad trailer
{ {
if( member_vector.empty() ) if( member_vector.empty() )
{ if( skip_trailing_data( infd, pos, ignore_trailing, loose_trailing ) ) { if( skip_trailing_data( infd, pos ) ) continue; return; }
continue; else return; } set_num_error( "Bad trailer at pos ", pos - trailer.size ); break;
set_num_error( "Bad trailer at pos ", pos - Lzip_trailer::size );
break;
} }
if( !read_header( infd, header, pos - member_size ) ) break; if( !read_header( infd, header, pos - member_size ) ) break;
if( !header.check() ) // bad header if( !header.check() ) // bad header
{ {
if( member_vector.empty() ) if( member_vector.empty() )
{ if( skip_trailing_data( infd, pos, ignore_trailing, loose_trailing ) ) { if( skip_trailing_data( infd, pos ) ) continue; return; }
continue; else return; } set_num_error( "Bad header at pos ", pos - member_size ); break;
set_num_error( "Bad header at pos ", pos - member_size );
break;
} }
pos -= member_size; pos -= member_size; // good member
const unsigned dictionary_size = header.dictionary_size(); const unsigned dictionary_size = header.dictionary_size();
member_vector.push_back( Member( 0, trailer.data_size(), pos,
member_size, dictionary_size ) );
if( dictionary_size_ < dictionary_size ) if( dictionary_size_ < dictionary_size )
dictionary_size_ = dictionary_size; dictionary_size_ = dictionary_size;
member_vector.push_back( Member( 0, trailer.data_size(), pos,
member_size, dictionary_size ) );
} }
if( pos != 0 || member_vector.empty() ) if( pos != 0 || member_vector.empty() || retval_ != 0 )
{ {
member_vector.clear(); member_vector.clear();
if( retval_ == 0 ) { error_ = "Can't create file index."; retval_ = 2; } if( retval_ == 0 ) { error_ = "Can't create file index."; retval_ = 2; }

View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -22,7 +22,7 @@
class Block class Block
{ {
long long pos_, size_; // pos + size <= INT64_MAX long long pos_, size_; // pos >= 0, size >= 0, pos + size <= INT64_MAX
public: public:
Block( const long long p, const long long s ) : pos_( p ), size_( s ) {} Block( const long long p, const long long s ) : pos_( p ), size_( s ) {}
@ -43,9 +43,11 @@ class Lzip_index
Block dblock, mblock; // data block, member block Block dblock, mblock; // data block, member block
unsigned dictionary_size; unsigned dictionary_size;
Member( const long long dp, const long long ds, Member( const long long dpos, const long long dsize,
const long long mp, const long long ms, const unsigned dict_size ) const long long mpos, const long long msize,
: dblock( dp, ds ), mblock( mp, ms ), dictionary_size( dict_size ) {} const unsigned dict_size )
: dblock( dpos, dsize ), mblock( mpos, msize ),
dictionary_size( dict_size ) {}
}; };
std::vector< Member > member_vector; std::vector< Member > member_vector;
@ -55,16 +57,14 @@ class Lzip_index
unsigned dictionary_size_; // largest dictionary size in the file unsigned dictionary_size_; // largest dictionary size in the file
bool bad_magic_; // bad magic in first header bool bad_magic_; // bad magic in first header
bool check_header_error( const Lzip_header & header, const bool first ); bool check_header( const Lzip_header & header, const bool first );
void set_errno_error( const char * const msg ); void set_errno_error( const char * const msg );
void set_num_error( const char * const msg, unsigned long long num ); void set_num_error( const char * const msg, unsigned long long num );
bool read_header( const int fd, Lzip_header & header, const long long pos ); bool read_header( const int fd, Lzip_header & header, const long long pos );
bool skip_trailing_data( const int fd, unsigned long long & pos, bool skip_trailing_data( const int fd, unsigned long long & pos );
const bool ignore_trailing, const bool loose_trailing );
public: public:
Lzip_index( const int infd, const bool ignore_trailing, Lzip_index( const int infd );
const bool loose_trailing );
long members() const { return member_vector.size(); } long members() const { return member_vector.size(); }
const std::string & error() const { return error_; } const std::string & error() const { return error_; }

57
main.cc
View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -16,7 +16,7 @@
*/ */
/* /*
Exit status: 0 for a normal exit, 1 for environmental problems Exit status: 0 for a normal exit, 1 for environmental problems
(file not found, files differ, invalid command line options, I/O errors, (file not found, files differ, invalid command-line options, I/O errors,
etc), 2 to indicate a corrupt or invalid input file, 3 for an internal etc), 2 to indicate a corrupt or invalid input file, 3 for an internal
consistency error (e.g., bug) which caused tarlz to panic. consistency error (e.g., bug) which caused tarlz to panic.
*/ */
@ -56,7 +56,7 @@ const char * const program_name = "tarlz";
namespace { namespace {
const char * const program_year = "2023"; const char * const program_year = "2024";
const char * invocation_name = program_name; // default value const char * invocation_name = program_name; // default value
@ -65,12 +65,12 @@ void show_help( const long num_online )
std::printf( "Tarlz is a massively parallel (multi-threaded) combined implementation of\n" std::printf( "Tarlz is a massively parallel (multi-threaded) combined implementation of\n"
"the tar archiver and the lzip compressor. Tarlz uses the compression library\n" "the tar archiver and the lzip compressor. Tarlz uses the compression library\n"
"lzlib.\n" "lzlib.\n"
"\nTarlz creates, lists, and extracts archives in a simplified and safer\n" "\nTarlz creates tar archives using a simplified and safer variant of the POSIX\n"
"variant of the POSIX pax format compressed in lzip format, keeping the\n" "pax format compressed in lzip format, keeping the alignment between tar\n"
"alignment between tar members and lzip members. The resulting multimember\n" "members and lzip members. The resulting multimember tar.lz archive is\n"
"tar.lz archive is fully backward compatible with standard tar tools like GNU\n" "backward compatible with standard tar tools like GNU tar, which treat it\n"
"tar, which treat it like any other tar.lz archive. Tarlz can append files to\n" "like any other tar.lz archive. Tarlz can append files to the end of such\n"
"the end of such compressed archives.\n" "compressed archives.\n"
"\nKeeping the alignment between tar members and lzip members has two\n" "\nKeeping the alignment between tar members and lzip members has two\n"
"advantages. It adds an indexed lzip layer on top of the tar archive, making\n" "advantages. It adds an indexed lzip layer on top of the tar archive, making\n"
"it possible to decode the archive safely in parallel. It also minimizes the\n" "it possible to decode the archive safely in parallel. It also minimizes the\n"
@ -116,6 +116,7 @@ void show_help( const long num_online )
" --group=<group> use <group> name/ID for files added to archive\n" " --group=<group> use <group> name/ID for files added to archive\n"
" --exclude=<pattern> exclude files matching a shell pattern\n" " --exclude=<pattern> exclude files matching a shell pattern\n"
" --ignore-ids ignore differences in owner and group IDs\n" " --ignore-ids ignore differences in owner and group IDs\n"
" --ignore-metadata compare only file size and file content\n"
" --ignore-overflow ignore mtime overflow differences on 32-bit\n" " --ignore-overflow ignore mtime overflow differences on 32-bit\n"
" --keep-damaged don't delete partially extracted files\n" " --keep-damaged don't delete partially extracted files\n"
" --missing-crc exit with error status if missing extended CRC\n" " --missing-crc exit with error status if missing extended CRC\n"
@ -131,7 +132,7 @@ void show_help( const long num_online )
std::printf( "\nIf no archive is specified, tarlz tries to read it from standard input or\n" std::printf( "\nIf no archive is specified, tarlz tries to read it from standard input or\n"
"write it to standard output.\n" "write it to standard output.\n"
"\nExit status: 0 for a normal exit, 1 for environmental problems\n" "\nExit status: 0 for a normal exit, 1 for environmental problems\n"
"(file not found, files differ, invalid command line options, I/O errors,\n" "(file not found, files differ, invalid command-line options, I/O errors,\n"
"etc), 2 to indicate a corrupt or invalid input file, 3 for an internal\n" "etc), 2 to indicate a corrupt or invalid input file, 3 for an internal\n"
"consistency error (e.g., bug) which caused tarlz to panic.\n" "consistency error (e.g., bug) which caused tarlz to panic.\n"
"\nReport bugs to lzip-bug@nongnu.org\n" "\nReport bugs to lzip-bug@nongnu.org\n"
@ -211,9 +212,9 @@ int check_lib()
// separate numbers of 5 or more digits in groups of 3 digits using '_' // separate numbers of 5 or more digits in groups of 3 digits using '_'
const char * format_num3( long long num ) const char * format_num3( long long num )
{ {
enum { buffers = 8, bufsize = 4 * sizeof num, n = 10 };
const char * const si_prefix = "kMGTPEZYRQ"; const char * const si_prefix = "kMGTPEZYRQ";
const char * const binary_prefix = "KMGTPEZYRQ"; const char * const binary_prefix = "KMGTPEZYRQ";
enum { buffers = 8, bufsize = 4 * sizeof num };
static char buffer[buffers][bufsize]; // circle of static buffers for printf static char buffer[buffers][bufsize]; // circle of static buffers for printf
static int current = 0; static int current = 0;
@ -221,14 +222,17 @@ const char * format_num3( long long num )
char * p = buf + bufsize - 1; // fill the buffer backwards char * p = buf + bufsize - 1; // fill the buffer backwards
*p = 0; // terminator *p = 0; // terminator
const bool negative = num < 0; const bool negative = num < 0;
char prefix = 0; // try binary first, then si if( num > 1024 || num < -1024 )
for( int i = 0; i < 8 && num != 0 && ( num / 1024 ) * 1024 == num; ++i ) {
{ num /= 1024; prefix = binary_prefix[i]; } char prefix = 0; // try binary first, then si
if( prefix ) *(--p) = 'i'; for( int i = 0; i < n && num != 0 && num % 1024 == 0; ++i )
else { num /= 1024; prefix = binary_prefix[i]; }
for( int i = 0; i < 8 && num != 0 && ( num / 1000 ) * 1000 == num; ++i ) if( prefix ) *(--p) = 'i';
{ num /= 1000; prefix = si_prefix[i]; } else
if( prefix ) *(--p) = prefix; for( int i = 0; i < n && num != 0 && num % 1000 == 0; ++i )
{ num /= 1000; prefix = si_prefix[i]; }
if( prefix ) *(--p) = prefix;
}
const bool split = num >= 10000 || num <= -10000; const bool split = num >= 10000 || num <= -10000;
for( int i = 0; ; ) for( int i = 0; ; )
@ -251,8 +255,7 @@ void show_option_error( const char * const arg, const char * const msg,
} }
// Recognized formats: <num>[QRYZEPTGM][i], <num>k, <num>Ki // Recognized formats: <num>k, <num>Ki, <num>[MGTPEZYRQ][i]
//
long long getnum( const char * const arg, const char * const option_name, long long getnum( const char * const arg, const char * const option_name,
const long long llimit = LLONG_MIN, const long long llimit = LLONG_MIN,
const long long ulimit = LLONG_MAX ) const long long ulimit = LLONG_MAX )
@ -524,8 +527,8 @@ int main( const int argc, const char * const argv[] )
if( argc > 0 ) invocation_name = argv[0]; if( argc > 0 ) invocation_name = argv[0];
enum { opt_ano = 256, opt_aso, opt_bso, opt_chk, opt_crc, opt_dbg, opt_del, enum { opt_ano = 256, opt_aso, opt_bso, opt_chk, opt_crc, opt_dbg, opt_del,
opt_dso, opt_exc, opt_grp, opt_hlp, opt_id, opt_kd, opt_mti, opt_nso, opt_dso, opt_exc, opt_grp, opt_hlp, opt_iid, opt_imd, opt_kd, opt_mti,
opt_ofl, opt_out, opt_own, opt_per, opt_sol, opt_un, opt_wn }; opt_nso, opt_ofl, opt_out, opt_own, opt_per, opt_sol, opt_un, opt_wn };
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
{ '0', 0, Arg_parser::no }, { '0', 0, Arg_parser::no },
@ -566,7 +569,8 @@ int main( const int argc, const char * const argv[] )
{ opt_exc, "exclude", Arg_parser::yes }, { opt_exc, "exclude", Arg_parser::yes },
{ opt_grp, "group", Arg_parser::yes }, { opt_grp, "group", Arg_parser::yes },
{ opt_hlp, "help", Arg_parser::no }, { opt_hlp, "help", Arg_parser::no },
{ opt_id, "ignore-ids", Arg_parser::no }, { opt_iid, "ignore-ids", Arg_parser::no },
{ opt_imd, "ignore-metadata", Arg_parser::no },
{ opt_kd, "keep-damaged", Arg_parser::no }, { opt_kd, "keep-damaged", Arg_parser::no },
{ opt_crc, "missing-crc", Arg_parser::no }, { opt_crc, "missing-crc", Arg_parser::no },
{ opt_mti, "mtime", Arg_parser::yes }, { opt_mti, "mtime", Arg_parser::yes },
@ -642,7 +646,8 @@ int main( const int argc, const char * const argv[] )
case opt_exc: Exclude::add_pattern( sarg ); break; case opt_exc: Exclude::add_pattern( sarg ); break;
case opt_grp: cl_opts.gid = parse_group( arg, pn ); break; case opt_grp: cl_opts.gid = parse_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_iid: cl_opts.ignore_ids = true; break;
case opt_imd: cl_opts.ignore_metadata = true; break;
case opt_kd: cl_opts.keep_damaged = true; break; case opt_kd: cl_opts.keep_damaged = true; break;
case opt_mti: cl_opts.mtime = parse_mtime( arg, pn ); case opt_mti: cl_opts.mtime = parse_mtime( arg, pn );
cl_opts.mtime_set = true; break; cl_opts.mtime_set = true; break;
@ -654,7 +659,7 @@ int main( const int argc, const char * const argv[] )
case opt_sol: cl_opts.solidity = solid; break; case opt_sol: cl_opts.solidity = solid; break;
case opt_un: cl_opts.set_level( -1 ); break; case opt_un: cl_opts.set_level( -1 ); break;
case opt_wn: cl_opts.warn_newer = true; break; case opt_wn: cl_opts.warn_newer = true; break;
default : internal_error( "uncaught option" ); default: internal_error( "uncaught option." );
} }
} // end process options } // end process options

17
tarlz.h
View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression /* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2023 Antonio Diaz Diaz. Copyright (C) 2013-2024 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
@ -419,7 +419,7 @@ enum Program_mode { m_none, m_append, m_compress, m_concatenate, m_create,
enum Solidity { no_solid, bsolid, dsolid, asolid, solid }; enum Solidity { no_solid, bsolid, dsolid, asolid, solid };
class Arg_parser; class Arg_parser;
struct Cl_options // command line options struct Cl_options // command-line options
{ {
const Arg_parser & parser; const Arg_parser & parser;
std::string archive_name; std::string archive_name;
@ -438,6 +438,7 @@ struct Cl_options // command line options
bool dereference; bool dereference;
bool filenames_given; bool filenames_given;
bool ignore_ids; bool ignore_ids;
bool ignore_metadata;
bool ignore_overflow; bool ignore_overflow;
bool keep_damaged; bool keep_damaged;
bool level_set; // compression level set in command line bool level_set; // compression level set in command line
@ -451,10 +452,10 @@ struct Cl_options // command line options
: parser( ap ), mtime( 0 ), uid( -1 ), gid( -1 ), program_mode( m_none ), : parser( ap ), mtime( 0 ), uid( -1 ), gid( -1 ), program_mode( m_none ),
solidity( bsolid ), data_size( 0 ), debug_level( 0 ), level( 6 ), solidity( bsolid ), data_size( 0 ), debug_level( 0 ), level( 6 ),
num_files( 0 ), num_workers( -1 ), out_slots( 64 ), dereference( false ), num_files( 0 ), num_workers( -1 ), out_slots( 64 ), dereference( false ),
filenames_given( false ), ignore_ids( false ), ignore_overflow( false ), filenames_given( false ), ignore_ids( false ), ignore_metadata( false ),
keep_damaged( false ), level_set( false ), missing_crc( false ), ignore_overflow( false ), keep_damaged( false ), level_set( false ),
mtime_set( false ), permissive( false ), preserve_permissions( false ), missing_crc( false ), mtime_set( false ), permissive( false ),
warn_newer( false ) {} preserve_permissions( false ), warn_newer( false ) {}
void set_level( const int l ) { level = l; level_set = true; } void set_level( const int l ) { level = l; level_set = true; }
@ -469,7 +470,6 @@ inline void set_retval( int & retval, const int 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.";
const char * const trailing_msg = "Trailing data not allowed.";
const char * const bad_hdr_msg = "Corrupt or invalid tar header."; const char * const bad_hdr_msg = "Corrupt or invalid tar header.";
const char * const gblrec_msg = "Error in global extended records."; const char * const gblrec_msg = "Error in global extended records.";
const char * const extrec_msg = "Error in extended records."; const char * const extrec_msg = "Error in extended records.";
@ -490,6 +490,7 @@ const char * const nfound_msg = "Not found in archive.";
const char * const seek_msg = "Seek error"; const char * const seek_msg = "Seek error";
const char * const werr_msg = "Write error"; const char * const werr_msg = "Write error";
const char * const chdir_msg = "Error changing working directory"; const char * const chdir_msg = "Error changing working directory";
const char * const intdir_msg = "Failed to create intermediate directory";
// defined in common.cc // defined in common.cc
unsigned long long parse_octal( const uint8_t * const ptr, const int size ); unsigned long long parse_octal( const uint8_t * const ptr, const int size );
@ -505,7 +506,7 @@ bool show_member_name( const Extended & extended, const Tar_header header,
bool check_skip_filename( const Cl_options & cl_opts, bool check_skip_filename( const Cl_options & cl_opts,
std::vector< char > & name_pending, std::vector< char > & name_pending,
const char * const filename, const int chdir_fd = -1 ); const char * const filename, const int chdir_fd = -1 );
bool make_path( const std::string & name ); bool make_dirs( const std::string & name );
// defined in common_mutex.cc // defined in common_mutex.cc
void exit_fail_mt( const int retval = 1 ); // terminate the program void exit_fail_mt( const int retval = 1 ); // terminate the program

View file

@ -1,14 +1,14 @@
#! /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-2023 Antonio Diaz Diaz. # Copyright (C) 2013-2024 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.
LC_ALL=C LC_ALL=C
export LC_ALL export LC_ALL
objdir="`pwd`" objdir=`pwd`
testdir="`cd "$1" ; pwd`" testdir=`cd "$1" ; pwd`
TARLZ="${objdir}"/tarlz TARLZ="${objdir}"/tarlz
framework_failure() { echo "failure in testing framework" ; exit 1 ; } framework_failure() { echo "failure in testing framework" ; exit 1 ; }
@ -154,13 +154,13 @@ printf "testing tarlz-%s..." "$2"
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${TARLZ}" -q -x -C nx_dir "${test3_lz}" "${TARLZ}" -q -x -C nx_dir "${test3_lz}"
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
touch empty.tar.lz empty.tlz # list an empty lz file touch empty.tar.lz empty.tlz || framework_failure # list an empty lz file
"${TARLZ}" -q -tf empty.tar.lz "${TARLZ}" -q -tf empty.tar.lz
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${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
touch empty.tar # compress an empty archive touch empty.tar || framework_failure # compress an empty archive
"${TARLZ}" -q -z empty.tar "${TARLZ}" -q -z empty.tar
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
[ ! -e empty.tar.lz ] || test_failed $LINENO [ ! -e empty.tar.lz ] || test_failed $LINENO
@ -245,6 +245,7 @@ rm -f foo bar baz || framework_failure
cmp cfoo foo || test_failed $LINENO cmp cfoo foo || test_failed $LINENO
cmp cbar bar || test_failed $LINENO cmp cbar bar || test_failed $LINENO
cmp cbaz baz || test_failed $LINENO cmp cbaz baz || test_failed $LINENO
# time and mode comparison always fails on OS/2
if "${TARLZ}" -df "${test3}" --ignore-ids ; then d_works=yes if "${TARLZ}" -df "${test3}" --ignore-ids ; then d_works=yes
else printf "warning: some '--diff' tests will be skipped.\n" else printf "warning: some '--diff' tests will be skipped.\n"
fi fi
@ -290,10 +291,12 @@ for i in "${test3}" "${test3_lz}" ; do
cmp cfoo dir1/foo || test_failed $LINENO "$i" cmp cfoo dir1/foo || test_failed $LINENO "$i"
cmp cbar dir2/bar || test_failed $LINENO "$i" cmp cbar dir2/bar || test_failed $LINENO "$i"
cmp cbaz dir3/baz || test_failed $LINENO "$i" cmp cbaz dir3/baz || test_failed $LINENO "$i"
"${TARLZ}" -q -df "$i" -C dir1 foo -C ../dir2 --ignore-ids bar \ if [ "${d_works}" = yes ] ; then
-C ../dir3 baz || test_failed $LINENO "$i" "${TARLZ}" -df "$i" -C dir1 foo -C ../dir2 --ignore-ids bar \
"${TARLZ}" -q -df "$i" -C dir3 baz -C ../dir2 bar -C ../dir1 foo \ -C ../dir3 baz || test_failed $LINENO "$i"
--ignore-ids || test_failed $LINENO "$i" "${TARLZ}" -df "$i" -C dir3 baz -C ../dir2 bar -C ../dir1 foo \
--ignore-ids || test_failed $LINENO "$i"
fi
rm -rf dir1 dir2 dir3 || framework_failure rm -rf dir1 dir2 dir3 || framework_failure
done done
for i in "${test3dir}" "${test3dir_lz}" ; do for i in "${test3dir}" "${test3dir_lz}" ; do
@ -303,10 +306,12 @@ for i in "${test3dir}" "${test3dir_lz}" ; do
cmp cfoo dir1/dir/foo || test_failed $LINENO "$i" cmp cfoo dir1/dir/foo || test_failed $LINENO "$i"
cmp cbar dir2/dir/bar || test_failed $LINENO "$i" cmp cbar dir2/dir/bar || test_failed $LINENO "$i"
cmp cbaz dir3/dir/baz || test_failed $LINENO "$i" cmp cbaz dir3/dir/baz || test_failed $LINENO "$i"
"${TARLZ}" -q -df "$i" --ignore-ids -C dir1 dir/foo -C ../dir2 dir/bar \ if [ "${d_works}" = yes ] ; then
-C ../dir3 dir/baz || test_failed $LINENO "$i" "${TARLZ}" -q -df "$i" --ignore-ids -C dir1 dir/foo -C ../dir2 dir/bar \
"${TARLZ}" -q -df "${test3}" -C dir1/dir foo -C ../../dir2/dir bar \ -C ../dir3 dir/baz || test_failed $LINENO "$i"
--ignore-ids -C ../../dir3/dir baz || test_failed $LINENO "$i" "${TARLZ}" -q -df "${test3}" -C dir1/dir foo -C ../../dir2/dir bar \
--ignore-ids -C ../../dir3/dir baz || test_failed $LINENO "$i"
fi
rm -rf dir1 dir2 dir3 || framework_failure rm -rf dir1 dir2 dir3 || framework_failure
done done
@ -768,7 +773,6 @@ rm -rf out.tar dir || framework_failure
printf "\ntesting --diff..." printf "\ntesting --diff..."
# test --diff
"${TARLZ}" -xf "${test3_lz}" || test_failed $LINENO "${TARLZ}" -xf "${test3_lz}" || test_failed $LINENO
"${TARLZ}" -cf out.tar foo || test_failed $LINENO "${TARLZ}" -cf out.tar foo || test_failed $LINENO
"${TARLZ}" -cf aout.tar foo --anonymous || test_failed $LINENO "${TARLZ}" -cf aout.tar foo --anonymous || test_failed $LINENO
@ -787,6 +791,8 @@ else
rm -f bar || framework_failure rm -f bar || framework_failure
"${TARLZ}" -n$i -df "${test3_lz}" --ignore-ids foo baz || "${TARLZ}" -n$i -df "${test3_lz}" --ignore-ids foo baz ||
test_failed $LINENO $i test_failed $LINENO $i
"${TARLZ}" -n$i -df "${test3_lz}" --ignore-metadata foo baz ||
test_failed $LINENO $i
"${TARLZ}" -n$i -df "${test3_lz}" --exclude bar --ignore-ids || "${TARLZ}" -n$i -df "${test3_lz}" --exclude bar --ignore-ids ||
test_failed $LINENO $i test_failed $LINENO $i
rm -f foo baz || framework_failure rm -f foo baz || framework_failure
@ -1199,6 +1205,9 @@ cmp out.tar.lz out || test_failed $LINENO
"${TARLZ}" -0 -B8KiB -z --bsolid outz.tar || test_failed $LINENO "${TARLZ}" -0 -B8KiB -z --bsolid outz.tar || test_failed $LINENO
cmp out.tar.lz outz.tar.lz || test_failed $LINENO cmp out.tar.lz outz.tar.lz || test_failed $LINENO
rm -f out outz.tar.lz || framework_failure rm -f out outz.tar.lz || framework_failure
"${TARLZ}" -0 -B8KiB -z -o a/b/c/out --bsolid out.tar || test_failed $LINENO
cmp out.tar.lz a/b/c/out || test_failed $LINENO
rm -rf a || framework_failure
# #
"${TARLZ}" -0 -n0 --asolid -cf out.tar.lz test.txt foo bar baz test.txt || test_failed $LINENO "${TARLZ}" -0 -n0 --asolid -cf out.tar.lz test.txt foo bar baz test.txt || test_failed $LINENO
"${TARLZ}" -0 -n0 --asolid -cf out3.tar.lz foo bar baz || test_failed $LINENO "${TARLZ}" -0 -n0 --asolid -cf out3.tar.lz foo bar baz || test_failed $LINENO