Adding upstream version 0.25.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
4f5d0de2b2
commit
8853aa3bf2
33 changed files with 317 additions and 280 deletions
16
ChangeLog
16
ChangeLog
|
@ -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>
|
||||
|
||||
* Version 0.24 released.
|
||||
|
@ -42,7 +52,7 @@
|
|||
* main.cc (getnum): Show option name and valid range if error.
|
||||
(check_lib): Check that LZ_API_VERSION and LZ_version_string match.
|
||||
(main): Report an error if -o is used with any operation except -z.
|
||||
* Set variable LIBS from configure.
|
||||
* configure: Set variable LIBS.
|
||||
|
||||
2021-06-14 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
|
@ -59,7 +69,7 @@
|
|||
|
||||
* Version 0.19 released.
|
||||
* 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>
|
||||
|
||||
|
@ -219,7 +229,7 @@
|
|||
* 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,
|
||||
but just in case, you have unlimited permission to copy, distribute, and
|
||||
|
|
7
INSTALL
7
INSTALL
|
@ -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).
|
||||
I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards
|
||||
compliant compiler.
|
||||
|
||||
Lzlib must be version 1.12 or newer.
|
||||
|
||||
Gcc is available at http://gcc.gnu.org.
|
||||
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
|
||||
static storage duration so that the cleanup handler for Control-C can delete
|
||||
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.
|
||||
|
||||
|
||||
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,
|
||||
distribute, and modify it.
|
||||
|
|
|
@ -29,6 +29,10 @@ main.o : main.cc
|
|||
%.o : %.cc
|
||||
$(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
|
||||
arg_parser.o : arg_parser.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
|
||||
main.o : tarlz.h arg_parser.h
|
||||
|
||||
|
||||
doc : info man
|
||||
|
||||
info : $(VPATH)/doc/$(pkgname).info
|
||||
|
|
21
NEWS
21
NEWS
|
@ -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
|
||||
extract. (Reported by Devon Sean McCullough).
|
||||
The new option '--ignore-metadata', which makes '-d, --diff' ignore
|
||||
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
|
||||
archive name. (An uncompressed archive name lacks a '.lz' or '.tlz' extension).
|
||||
'#include <sys/types.h>' for major, minor, makedev on BSD systems.
|
||||
|
||||
The diagnostic shown when a file being archived or an archive being
|
||||
compressed fails to read, now shows the cause of the failure; end-of-file or
|
||||
read error.
|
||||
File diagnostics of '-z' have been reformatted as 'PROGRAM: FILE: MESSAGE'.
|
||||
|
||||
'-z, --compress' now exits with error status 2 if any input archive is an
|
||||
empty file.
|
||||
The option '-o, --output' now creates missing intermediate directories when
|
||||
compressing to a file.
|
||||
|
||||
A failure in the '--diff' test of the testsuite on OS/2 has been fixed.
|
||||
(Reported by Elbert Pol).
|
||||
The variable MAKEINFO has been added to configure and Makefile.in.
|
||||
|
|
11
README
11
README
|
@ -6,7 +6,7 @@ lzlib.
|
|||
|
||||
Tarlz creates tar archives using a simplified and safer variant of the POSIX
|
||||
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
|
||||
like any other tar.lz archive. Tarlz can append files to the end of such
|
||||
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
|
||||
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.
|
||||
|
||||
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,
|
||||
distribute, and modify it.
|
||||
|
||||
The file Makefile.in is a data file used by configure to produce the
|
||||
Makefile. It has the same copyright owner and permissions that configure
|
||||
itself.
|
||||
The file Makefile.in is a data file used by configure to produce the Makefile.
|
||||
It has the same copyright owner and permissions that configure itself.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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 )
|
||||
: name( archive_name ), namep( name.empty() ? "(stdin)" : name.c_str() ),
|
||||
infd( non_tty_infd( archive_name, namep ) ),
|
||||
lzip_index( infd, true, false ),
|
||||
lzip_index( infd ),
|
||||
seekable( lseek( infd, 0, SEEK_SET ) == 0 ),
|
||||
indexed( seekable && lzip_index.retval() == 0 ) {}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||
Copyright (C) 2006-2023 Antonio Diaz Diaz.
|
||||
/* Arg_parser - POSIX/GNU command-line argument parser. (C++ version)
|
||||
Copyright (C) 2006-2024 Antonio Diaz Diaz.
|
||||
|
||||
This library is free software. Redistribution and use in source and
|
||||
binary forms, with or without modification, are permitted provided
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||
Copyright (C) 2006-2023 Antonio Diaz Diaz.
|
||||
/* Arg_parser - POSIX/GNU command-line argument parser. (C++ version)
|
||||
Copyright (C) 2006-2024 Antonio Diaz Diaz.
|
||||
|
||||
This library is free software. Redistribution and use in source and
|
||||
binary forms, with or without modification, are permitted provided
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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;
|
||||
unsigned end = name.size(); // first slash before last component
|
||||
int i = name.size();
|
||||
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
|
||||
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 )
|
||||
for( i = 0; i < dirsize; ) // if dirsize == 0, dirname is '/' or empty
|
||||
{
|
||||
while( index < end && name[index] == '/' ) ++index;
|
||||
unsigned first = index;
|
||||
while( index < end && name[index] != '/' ) ++index;
|
||||
if( first < index )
|
||||
while( i < dirsize && name[i] == '/' ) ++i;
|
||||
const int first = i;
|
||||
while( i < dirsize && name[i] != '/' ) ++i;
|
||||
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;
|
||||
if( lstat( partial.c_str(), &st ) == 0 )
|
||||
{ if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
23
compress.cc
23
compress.cc
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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 )
|
||||
{
|
||||
delete_output_on_interrupt = false;
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n",
|
||||
program_name, output_filename.c_str() );
|
||||
show_file_error( output_filename.c_str(),
|
||||
"Deleting output file, if it exists." );
|
||||
if( outfd >= 0 ) { close( outfd ); outfd = -1; }
|
||||
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 );
|
||||
}
|
||||
|
@ -103,7 +102,7 @@ void close_and_set_permissions( const struct stat * const in_statsp )
|
|||
if( in_statsp )
|
||||
{
|
||||
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( fchmod( outfd, mode ) != 0 ) warning = true; }
|
||||
else
|
||||
|
@ -112,10 +111,8 @@ void close_and_set_permissions( const struct stat * const in_statsp )
|
|||
warning = true;
|
||||
}
|
||||
if( close( outfd ) != 0 )
|
||||
{
|
||||
show_error( "Error closing output file", errno );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
{ show_file_error( output_filename.c_str(), "Error closing output file",
|
||||
errno ); cleanup_and_fail( 1 ); }
|
||||
outfd = -1;
|
||||
delete_output_on_interrupt = false;
|
||||
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( 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 ) )
|
||||
{
|
||||
// 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 );
|
||||
// check tty only once and don't try to delete a tty
|
||||
if( outfd < 0 || !check_tty_out() ) { close( infd ); return 1; }
|
||||
|
|
66
configure
vendored
66
configure
vendored
|
@ -1,12 +1,12 @@
|
|||
#! /bin/sh
|
||||
# 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
|
||||
# to copy, distribute, and modify it.
|
||||
|
||||
pkgname=tarlz
|
||||
pkgversion=0.24
|
||||
pkgversion=0.25
|
||||
progname=tarlz
|
||||
srctrigger=doc/${pkgname}.texi
|
||||
|
||||
|
@ -36,7 +36,7 @@ no_create=
|
|||
while [ $# != 0 ] ; do
|
||||
|
||||
# Get the first arg, and shuffle
|
||||
option="$1" ; arg2=no
|
||||
option=$1 ; arg2=no
|
||||
shift
|
||||
|
||||
# Add the argument quoted to args
|
||||
|
@ -44,12 +44,12 @@ while [ $# != 0 ] ; do
|
|||
else args="${args} \"${option}\"" ; fi
|
||||
|
||||
# Split out the argument for options that take them
|
||||
case "${option}" in
|
||||
*=*) optarg="`echo "${option}" | sed -e 's,^[^=]*=,,;s,/$,,'`" ;;
|
||||
case ${option} in
|
||||
*=*) optarg=`echo "${option}" | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
|
||||
esac
|
||||
|
||||
# Process the options
|
||||
case "${option}" in
|
||||
case ${option} in
|
||||
--help | -h)
|
||||
echo "Usage: $0 [OPTION]... [VAR=VALUE]..."
|
||||
echo
|
||||
|
@ -67,10 +67,10 @@ while [ $# != 0 ] ; do
|
|||
echo " --infodir=DIR info files directory [${infodir}]"
|
||||
echo " --mandir=DIR man pages directory [${mandir}]"
|
||||
echo " CXX=COMPILER C++ compiler to use [${CXX}]"
|
||||
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
|
||||
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
|
||||
echo " CPPFLAGS=OPTIONS command-line options for the preprocessor [${CPPFLAGS}]"
|
||||
echo " CXXFLAGS=OPTIONS command-line options for the C++ compiler [${CXXFLAGS}]"
|
||||
echo " CXXFLAGS+=OPTIONS append options to the current value of CXXFLAGS"
|
||||
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
|
||||
echo " LDFLAGS=OPTIONS command-line options for the linker [${LDFLAGS}]"
|
||||
echo " LIBS=OPTIONS libraries to pass to the linker [${LIBS}]"
|
||||
echo " MAKEINFO=NAME makeinfo program to use [${MAKEINFO}]"
|
||||
echo
|
||||
|
@ -78,30 +78,30 @@ while [ $# != 0 ] ; do
|
|||
--version | -V)
|
||||
echo "Configure script for ${pkgname} version ${pkgversion}"
|
||||
exit 0 ;;
|
||||
--srcdir) srcdir="$1" ; arg2=yes ;;
|
||||
--prefix) prefix="$1" ; arg2=yes ;;
|
||||
--exec-prefix) exec_prefix="$1" ; arg2=yes ;;
|
||||
--bindir) bindir="$1" ; arg2=yes ;;
|
||||
--datarootdir) datarootdir="$1" ; arg2=yes ;;
|
||||
--infodir) infodir="$1" ; arg2=yes ;;
|
||||
--mandir) mandir="$1" ; arg2=yes ;;
|
||||
--srcdir) srcdir=$1 ; arg2=yes ;;
|
||||
--prefix) prefix=$1 ; arg2=yes ;;
|
||||
--exec-prefix) exec_prefix=$1 ; arg2=yes ;;
|
||||
--bindir) bindir=$1 ; arg2=yes ;;
|
||||
--datarootdir) datarootdir=$1 ; arg2=yes ;;
|
||||
--infodir) infodir=$1 ; arg2=yes ;;
|
||||
--mandir) mandir=$1 ; arg2=yes ;;
|
||||
|
||||
--srcdir=*) srcdir="${optarg}" ;;
|
||||
--prefix=*) prefix="${optarg}" ;;
|
||||
--exec-prefix=*) exec_prefix="${optarg}" ;;
|
||||
--bindir=*) bindir="${optarg}" ;;
|
||||
--datarootdir=*) datarootdir="${optarg}" ;;
|
||||
--infodir=*) infodir="${optarg}" ;;
|
||||
--mandir=*) mandir="${optarg}" ;;
|
||||
--no-create) no_create=yes ;;
|
||||
--srcdir=*) srcdir=${optarg} ;;
|
||||
--prefix=*) prefix=${optarg} ;;
|
||||
--exec-prefix=*) exec_prefix=${optarg} ;;
|
||||
--bindir=*) bindir=${optarg} ;;
|
||||
--datarootdir=*) datarootdir=${optarg} ;;
|
||||
--infodir=*) infodir=${optarg} ;;
|
||||
--mandir=*) mandir=${optarg} ;;
|
||||
--no-create) no_create=yes ;;
|
||||
|
||||
CXX=*) CXX="${optarg}" ;;
|
||||
CPPFLAGS=*) CPPFLAGS="${optarg}" ;;
|
||||
CXXFLAGS=*) CXXFLAGS="${optarg}" ;;
|
||||
CXX=*) CXX=${optarg} ;;
|
||||
CPPFLAGS=*) CPPFLAGS=${optarg} ;;
|
||||
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
|
||||
CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;;
|
||||
LDFLAGS=*) LDFLAGS="${optarg}" ;;
|
||||
LDFLAGS=*) LDFLAGS=${optarg} ;;
|
||||
LIBS=*) LIBS="${optarg} ${LIBS}" ;;
|
||||
MAKEINFO=*) MAKEINFO="${optarg}" ;;
|
||||
MAKEINFO=*) MAKEINFO=${optarg} ;;
|
||||
|
||||
--*)
|
||||
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
|
||||
## 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
|
||||
|
||||
|
@ -175,7 +175,7 @@ echo "MAKEINFO = ${MAKEINFO}"
|
|||
rm -f Makefile
|
||||
cat > Makefile << EOF
|
||||
# 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 Makefile is free software: you have unlimited permission
|
||||
|
@ -201,5 +201,5 @@ EOF
|
|||
cat "${srcdir}/Makefile.in" >> Makefile
|
||||
|
||||
echo "OK. Now you can run make."
|
||||
echo "If make fails, check that the compression library lzlib is correctly"
|
||||
echo "installed (see INSTALL)."
|
||||
echo "If make fails, check that the compression library lzlib is correctly installed"
|
||||
echo "(see INSTALL)."
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -26,6 +26,8 @@
|
|||
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
|
||||
!defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__
|
||||
#include <sys/sysmacros.h> // for major, minor
|
||||
#else
|
||||
#include <sys/types.h> // for major, minor
|
||||
#endif
|
||||
#include <ftw.h>
|
||||
#include <grp.h>
|
||||
|
|
2
create.h
2
create.h
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
19
decode.cc
19
decode.cc
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,6 +29,8 @@
|
|||
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
|
||||
!defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__
|
||||
#include <sys/sysmacros.h> // for major, minor, makedev
|
||||
#else
|
||||
#include <sys/types.h> // for major, minor, makedev
|
||||
#endif
|
||||
#include <lzlib.h>
|
||||
|
||||
|
@ -38,6 +40,9 @@
|
|||
#include "archive_reader.h"
|
||||
#include "decode.h"
|
||||
|
||||
#ifndef O_DIRECTORY
|
||||
#define O_DIRECTORY 0
|
||||
#endif
|
||||
|
||||
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;
|
||||
// remove file (or empty dir) before extraction to prevent following links
|
||||
std::remove( filename );
|
||||
if( !make_path( filename ) )
|
||||
if( !make_dirs( filename ) )
|
||||
{
|
||||
show_file_error( filename, intdir_msg, errno );
|
||||
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 ) )
|
||||
{
|
||||
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 )
|
||||
{ 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;
|
||||
bool diff = false, size_differs = false, type_differs = true;
|
||||
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 ) &&
|
||||
!S_ISREG( st.st_mode ) )
|
||||
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
|
||||
{
|
||||
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
|
||||
if( mode != ( st.st_mode & ( S_ISUID | S_ISGID | S_ISVTX |
|
||||
S_IRWXU | S_IRWXG | S_IRWXO ) ) )
|
||||
{ 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 )
|
||||
{ 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_directory &&
|
||||
if( typeflag != tf_directory && !cl_opts.ignore_metadata &&
|
||||
extended.mtime().sec() != (long long)st.st_mtime )
|
||||
{
|
||||
if( (time_t)extended.mtime().sec() == st.st_mtime )
|
||||
|
|
3
decode.h
3
decode.h
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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 ); }
|
||||
|
||||
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 mkdir_msg = "Can't create directory";
|
||||
const char * const mknod_msg = "Can't create device node";
|
||||
|
|
16
decode_lz.cc
16
decode_lz.cc
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,6 +29,8 @@
|
|||
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
|
||||
!defined __DragonFly__ && !defined __APPLE__ && !defined __OS2__
|
||||
#include <sys/sysmacros.h> // for major, minor, makedev
|
||||
#else
|
||||
#include <sys/types.h> // for major, minor, makedev
|
||||
#endif
|
||||
#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,
|
||||
Archive_reader_i & ar, Packet_courier & courier,
|
||||
const Extended & extended, const Tar_header header,
|
||||
Resizable_buffer & rbuf, const long member_id,
|
||||
const int worker_id )
|
||||
Archive_reader_i & ar, Packet_courier & courier,
|
||||
const Extended & extended, const Tar_header header,
|
||||
Resizable_buffer & rbuf, const long member_id,
|
||||
const int worker_id )
|
||||
{
|
||||
if( verbosity < 1 ) rbuf()[0] = 0;
|
||||
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.
|
||||
Don't remove an empty dir because other thread may need it. */
|
||||
if( typeflag != tf_directory ) std::remove( filename );
|
||||
if( !make_path( filename ) )
|
||||
if( !make_dirs( filename ) )
|
||||
{
|
||||
if( format_file_error( rbuf, filename, intdir_msg, errno ) &&
|
||||
!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 ) )
|
||||
{
|
||||
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( format_file_error( rbuf, filename, chown_msg, errno ) &&
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
23
doc/tarlz.1
23
doc/tarlz.1
|
@ -1,5 +1,5 @@
|
|||
.\" 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
|
||||
tarlz \- creates tar archives with multimember lzip compression
|
||||
.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
|
||||
lzlib.
|
||||
.PP
|
||||
Tarlz creates, lists, and extracts archives in a simplified and safer
|
||||
variant of the POSIX pax format compressed in lzip format, keeping the
|
||||
alignment between tar members and lzip members. The resulting multimember
|
||||
tar.lz archive is fully 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 compressed archives.
|
||||
Tarlz creates tar archives using a simplified and safer variant of the POSIX
|
||||
pax format compressed in lzip format, keeping the alignment between tar
|
||||
members and lzip members. The resulting multimember tar.lz archive is
|
||||
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
|
||||
compressed archives.
|
||||
.PP
|
||||
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
|
||||
|
@ -127,6 +127,9 @@ exclude files matching a shell pattern
|
|||
\fB\-\-ignore\-ids\fR
|
||||
ignore differences in owner and group IDs
|
||||
.TP
|
||||
\fB\-\-ignore\-metadata\fR
|
||||
compare only file size and file content
|
||||
.TP
|
||||
\fB\-\-ignore\-overflow\fR
|
||||
ignore mtime overflow differences on 32\-bit
|
||||
.TP
|
||||
|
@ -149,7 +152,7 @@ If no archive is specified, tarlz tries to read it from standard input or
|
|||
write it to standard output.
|
||||
.PP
|
||||
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
|
||||
consistency error (e.g., bug) which caused tarlz to panic.
|
||||
.SH "REPORTING BUGS"
|
||||
|
@ -157,8 +160,8 @@ Report bugs to lzip\-bug@nongnu.org
|
|||
.br
|
||||
Tarlz home page: http://www.nongnu.org/lzip/tarlz.html
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2023 Antonio Diaz Diaz.
|
||||
Using lzlib 1.13
|
||||
Copyright \(co 2024 Antonio Diaz Diaz.
|
||||
Using lzlib 1.14\-rc1
|
||||
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
|
||||
.br
|
||||
This is free software: you are free to change and redistribute it.
|
||||
|
|
|
@ -11,12 +11,12 @@ File: tarlz.info, Node: Top, Next: Introduction, Up: (dir)
|
|||
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:
|
||||
|
||||
* Introduction:: Purpose and features of tarlz
|
||||
* Invoking tarlz:: Command line interface
|
||||
* Invoking tarlz:: Command-line interface
|
||||
* Portable character set:: POSIX portable filename character set
|
||||
* File format:: Detailed format of the compressed archive
|
||||
* 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
|
||||
|
||||
|
||||
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,
|
||||
distribute, and modify it.
|
||||
|
@ -46,8 +46,8 @@ library lzlib.
|
|||
Tarlz creates tar archives using a simplified and safer variant of the
|
||||
POSIX pax format compressed in lzip format, keeping the alignment between
|
||||
tar members and lzip members. The resulting multimember tar.lz archive is
|
||||
fully 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
|
||||
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
|
||||
compressed archives.
|
||||
|
||||
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
|
||||
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'
|
||||
Make '--diff' ignore differences in mtime caused by overflow on 32-bit
|
||||
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
|
||||
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
|
||||
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).
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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 by one or two headers plus optional data) in the tar archive and
|
||||
|
@ -618,7 +624,7 @@ space, equal-sign, and newline.
|
|||
'gid'
|
||||
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 greater than 2_097_151 (octal 7777777). *Note
|
||||
a group ID greater than 2_097_151 (octal 7_777_777). *Note
|
||||
ustar-uid-gid::.
|
||||
|
||||
'linkpath'
|
||||
|
@ -653,13 +659,14 @@ space, equal-sign, and newline.
|
|||
digits from the ISO/IEC 646:1991 (ASCII) standard. This record
|
||||
overrides the field '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 (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.
|
||||
|
||||
'uid'
|
||||
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 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'
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
(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
|
||||
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
|
||||
(octal 77777777777) seconds since the epoch, an extended record is used to
|
||||
store the modification time. The ustar range of mtime goes from
|
||||
(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 from
|
||||
'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
|
||||
|
@ -835,7 +842,7 @@ more probable.
|
|||
|
||||
Headers and metadata must be protected separately from data because the
|
||||
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.
|
||||
|
||||
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,
|
||||
without conversion to UTF-8 nor any other transformation. This prevents
|
||||
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
|
||||
|
@ -1252,25 +1259,25 @@ Concept index
|
|||
|
||||
Tag Table:
|
||||
Node: Top216
|
||||
Node: Introduction1210
|
||||
Node: Invoking tarlz4041
|
||||
Ref: --data-size13085
|
||||
Ref: --bsolid17521
|
||||
Node: Portable character set23119
|
||||
Node: File format23762
|
||||
Ref: key_crc3230703
|
||||
Ref: ustar-uid-gid33968
|
||||
Ref: ustar-mtime34770
|
||||
Node: Amendments to pax format36770
|
||||
Ref: crc3237479
|
||||
Ref: flawed-compat38790
|
||||
Node: Program design42872
|
||||
Node: Multi-threaded decoding46797
|
||||
Ref: mt-extraction50078
|
||||
Node: Minimum archive sizes51384
|
||||
Node: Examples53511
|
||||
Node: Problems55878
|
||||
Node: Concept index56433
|
||||
Node: Introduction1207
|
||||
Node: Invoking tarlz4032
|
||||
Ref: --data-size13076
|
||||
Ref: --bsolid17512
|
||||
Node: Portable character set23425
|
||||
Node: File format24068
|
||||
Ref: key_crc3231050
|
||||
Ref: ustar-uid-gid34315
|
||||
Ref: ustar-mtime35122
|
||||
Node: Amendments to pax format37125
|
||||
Ref: crc3237834
|
||||
Ref: flawed-compat39146
|
||||
Node: Program design43228
|
||||
Node: Multi-threaded decoding47153
|
||||
Ref: mt-extraction50434
|
||||
Node: Minimum archive sizes51740
|
||||
Node: Examples53867
|
||||
Node: Problems56234
|
||||
Node: Concept index56789
|
||||
|
||||
End Tag Table
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
@finalout
|
||||
@c %**end of header
|
||||
|
||||
@set UPDATED 20 September 2023
|
||||
@set VERSION 0.24
|
||||
@set UPDATED 3 January 2024
|
||||
@set VERSION 0.25
|
||||
|
||||
@dircategory Archiving
|
||||
@direntry
|
||||
|
@ -37,7 +37,7 @@ This manual is for Tarlz (version @value{VERSION}, @value{UPDATED}).
|
|||
|
||||
@menu
|
||||
* Introduction:: Purpose and features of tarlz
|
||||
* Invoking tarlz:: Command line interface
|
||||
* Invoking tarlz:: Command-line interface
|
||||
* Portable character set:: POSIX portable filename character set
|
||||
* File format:: Detailed format of the compressed archive
|
||||
* 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
|
||||
|
||||
@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,
|
||||
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
|
||||
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
|
||||
like any other tar.lz archive. Tarlz can append files to the end of such
|
||||
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
|
||||
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
|
||||
Make @option{--diff} ignore differences in mtime caused by overflow on 32-bit
|
||||
systems with a 32-bit time_t.
|
||||
|
@ -534,7 +540,7 @@ keyword appearing in the same block of extended records.
|
|||
@end table
|
||||
|
||||
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
|
||||
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).
|
||||
|
||||
@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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@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
|
||||
@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
|
||||
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
|
||||
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}
|
||||
@item GNU.crc32
|
||||
|
@ -815,7 +821,8 @@ table shows the symbolic name of each bit and its octal value:
|
|||
@anchor{ustar-uid-gid}
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@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}
|
||||
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
|
||||
@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
|
||||
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
|
||||
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.
|
||||
|
||||
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,
|
||||
without conversion to UTF-8 nor any other transformation. This prevents
|
||||
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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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( verbosity >= 2 )
|
||||
std::fprintf( stderr, "CRC32C = %08X\n", (unsigned)computed_crc );
|
||||
std::fprintf( stderr, "CRC32-C = %08X\n", (unsigned)computed_crc );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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
|
||||
|
||||
|
||||
bool Lzip_index::check_header_error( const Lzip_header & header,
|
||||
const bool first )
|
||||
bool Lzip_index::check_header( const Lzip_header & header, const bool first )
|
||||
{
|
||||
if( !header.check_magic() )
|
||||
{ error_ = bad_magic_msg; retval_ = 2; if( first ) bad_magic_ = true;
|
||||
return true; }
|
||||
return false; }
|
||||
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() ) )
|
||||
{ error_ = bad_dict_msg; retval_ = 2; return true; }
|
||||
return false;
|
||||
{ error_ = bad_dict_msg; retval_ = 2; return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
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,
|
||||
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; }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// If successful, push last member and set pos to member header.
|
||||
bool Lzip_index::skip_trailing_data( const int fd, unsigned long long & pos,
|
||||
const bool ignore_trailing,
|
||||
const bool loose_trailing )
|
||||
bool Lzip_index::skip_trailing_data( const int fd, unsigned long long & pos )
|
||||
{
|
||||
if( pos < min_member_size ) return false;
|
||||
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
|
||||
{
|
||||
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();
|
||||
if( member_size == 0 ) // skip trailing zeros
|
||||
{ while( i > Lzip_trailer::size && buffer[i-9] == 0 ) --i; continue; }
|
||||
if( member_size > ipos + i || !trailer.check_consistency() )
|
||||
continue;
|
||||
{ while( i > trailer.size && buffer[i-9] == 0 ) --i; continue; }
|
||||
if( member_size > ipos + i || !trailer.check_consistency() ) continue;
|
||||
Lzip_header header;
|
||||
if( !read_header( fd, header, ipos + i - member_size ) ) return false;
|
||||
if( !header.check() ) continue;
|
||||
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( !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.";
|
||||
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; }
|
||||
if( !ignore_trailing )
|
||||
{ error_ = trailing_msg; retval_ = 2; return false; }
|
||||
pos = ipos + i - member_size;
|
||||
pos = ipos + i - member_size; // good member
|
||||
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 )
|
||||
dictionary_size_ = dictionary_size;
|
||||
member_vector.push_back( Member( 0, trailer.data_size(), pos,
|
||||
member_size, dictionary_size ) );
|
||||
return true;
|
||||
}
|
||||
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,
|
||||
const bool loose_trailing )
|
||||
Lzip_index::Lzip_index( const int infd )
|
||||
: insize( lseek( infd, 0, SEEK_END ) ), retval_( 0 ), dictionary_size_( 0 ),
|
||||
bad_magic_( false )
|
||||
{
|
||||
|
@ -164,42 +157,38 @@ Lzip_index::Lzip_index( const int infd, const bool ignore_trailing,
|
|||
retval_ = 2; return; }
|
||||
|
||||
Lzip_header header;
|
||||
if( !read_header( infd, header, 0 ) ) return;
|
||||
if( check_header_error( header, true ) ) return;
|
||||
if( !read_header( infd, header, 0 ) ||
|
||||
!check_header( header, true ) ) return;
|
||||
|
||||
unsigned long long pos = insize; // always points to a header or to EOF
|
||||
while( pos >= min_member_size )
|
||||
{
|
||||
Lzip_trailer trailer;
|
||||
if( seek_read( infd, trailer.data, Lzip_trailer::size,
|
||||
pos - Lzip_trailer::size ) != Lzip_trailer::size )
|
||||
if( seek_read( infd, trailer.data, trailer.size, pos - trailer.size ) !=
|
||||
trailer.size )
|
||||
{ set_errno_error( "Error reading member trailer: " ); break; }
|
||||
const unsigned long long member_size = trailer.member_size();
|
||||
if( member_size > pos || !trailer.check_consistency() ) // bad trailer
|
||||
{
|
||||
if( member_vector.empty() )
|
||||
{ if( skip_trailing_data( infd, pos, ignore_trailing, loose_trailing ) )
|
||||
continue; else return; }
|
||||
set_num_error( "Bad trailer at pos ", pos - Lzip_trailer::size );
|
||||
break;
|
||||
{ if( skip_trailing_data( infd, pos ) ) continue; return; }
|
||||
set_num_error( "Bad trailer at pos ", pos - trailer.size ); break;
|
||||
}
|
||||
if( !read_header( infd, header, pos - member_size ) ) break;
|
||||
if( !header.check() ) // bad header
|
||||
{
|
||||
if( member_vector.empty() )
|
||||
{ if( skip_trailing_data( infd, pos, ignore_trailing, loose_trailing ) )
|
||||
continue; else return; }
|
||||
set_num_error( "Bad header at pos ", pos - member_size );
|
||||
break;
|
||||
{ if( skip_trailing_data( infd, pos ) ) continue; return; }
|
||||
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();
|
||||
member_vector.push_back( Member( 0, trailer.data_size(), pos,
|
||||
member_size, dictionary_size ) );
|
||||
if( 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();
|
||||
if( retval_ == 0 ) { error_ = "Can't create file index."; retval_ = 2; }
|
||||
|
|
20
lzip_index.h
20
lzip_index.h
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
class Block
|
||||
{
|
||||
long long pos_, size_; // pos + size <= INT64_MAX
|
||||
long long pos_, size_; // pos >= 0, size >= 0, pos + size <= INT64_MAX
|
||||
|
||||
public:
|
||||
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
|
||||
unsigned dictionary_size;
|
||||
|
||||
Member( const long long dp, const long long ds,
|
||||
const long long mp, const long long ms, const unsigned dict_size )
|
||||
: dblock( dp, ds ), mblock( mp, ms ), dictionary_size( dict_size ) {}
|
||||
Member( const long long dpos, const long long dsize,
|
||||
const long long mpos, const long long msize,
|
||||
const unsigned dict_size )
|
||||
: dblock( dpos, dsize ), mblock( mpos, msize ),
|
||||
dictionary_size( dict_size ) {}
|
||||
};
|
||||
|
||||
std::vector< Member > member_vector;
|
||||
|
@ -55,16 +57,14 @@ class Lzip_index
|
|||
unsigned dictionary_size_; // largest dictionary size in the file
|
||||
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_num_error( const char * const msg, unsigned long long num );
|
||||
bool read_header( const int fd, Lzip_header & header, const long long pos );
|
||||
bool skip_trailing_data( const int fd, unsigned long long & pos,
|
||||
const bool ignore_trailing, const bool loose_trailing );
|
||||
bool skip_trailing_data( const int fd, unsigned long long & pos );
|
||||
|
||||
public:
|
||||
Lzip_index( const int infd, const bool ignore_trailing,
|
||||
const bool loose_trailing );
|
||||
Lzip_index( const int infd );
|
||||
|
||||
long members() const { return member_vector.size(); }
|
||||
const std::string & error() const { return error_; }
|
||||
|
|
57
main.cc
57
main.cc
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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
|
||||
(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
|
||||
consistency error (e.g., bug) which caused tarlz to panic.
|
||||
*/
|
||||
|
@ -56,7 +56,7 @@ const char * const program_name = "tarlz";
|
|||
|
||||
namespace {
|
||||
|
||||
const char * const program_year = "2023";
|
||||
const char * const program_year = "2024";
|
||||
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"
|
||||
"the tar archiver and the lzip compressor. Tarlz uses the compression library\n"
|
||||
"lzlib.\n"
|
||||
"\nTarlz creates, lists, and extracts archives in a simplified and safer\n"
|
||||
"variant of the POSIX pax format compressed in lzip format, keeping the\n"
|
||||
"alignment between tar members and lzip members. The resulting multimember\n"
|
||||
"tar.lz archive is fully backward compatible with standard tar tools like GNU\n"
|
||||
"tar, which treat it like any other tar.lz archive. Tarlz can append files to\n"
|
||||
"the end of such compressed archives.\n"
|
||||
"\nTarlz creates tar archives using a simplified and safer variant of the POSIX\n"
|
||||
"pax format compressed in lzip format, keeping the alignment between tar\n"
|
||||
"members and lzip members. The resulting multimember tar.lz archive is\n"
|
||||
"backward compatible with standard tar tools like GNU tar, which treat it\n"
|
||||
"like any other tar.lz archive. Tarlz can append files to the end of such\n"
|
||||
"compressed archives.\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"
|
||||
"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"
|
||||
" --exclude=<pattern> exclude files matching a shell pattern\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"
|
||||
" --keep-damaged don't delete partially extracted files\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"
|
||||
"write it to standard output.\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"
|
||||
"consistency error (e.g., bug) which caused tarlz to panic.\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 '_'
|
||||
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 binary_prefix = "KMGTPEZYRQ";
|
||||
enum { buffers = 8, bufsize = 4 * sizeof num };
|
||||
static char buffer[buffers][bufsize]; // circle of static buffers for printf
|
||||
static int current = 0;
|
||||
|
||||
|
@ -221,14 +222,17 @@ const char * format_num3( long long num )
|
|||
char * p = buf + bufsize - 1; // fill the buffer backwards
|
||||
*p = 0; // terminator
|
||||
const bool negative = num < 0;
|
||||
char prefix = 0; // try binary first, then si
|
||||
for( int i = 0; i < 8 && num != 0 && ( num / 1024 ) * 1024 == num; ++i )
|
||||
{ num /= 1024; prefix = binary_prefix[i]; }
|
||||
if( prefix ) *(--p) = 'i';
|
||||
else
|
||||
for( int i = 0; i < 8 && num != 0 && ( num / 1000 ) * 1000 == num; ++i )
|
||||
{ num /= 1000; prefix = si_prefix[i]; }
|
||||
if( prefix ) *(--p) = prefix;
|
||||
if( num > 1024 || num < -1024 )
|
||||
{
|
||||
char prefix = 0; // try binary first, then si
|
||||
for( int i = 0; i < n && num != 0 && num % 1024 == 0; ++i )
|
||||
{ num /= 1024; prefix = binary_prefix[i]; }
|
||||
if( prefix ) *(--p) = 'i';
|
||||
else
|
||||
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;
|
||||
|
||||
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,
|
||||
const long long llimit = LLONG_MIN,
|
||||
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];
|
||||
|
||||
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_ofl, opt_out, opt_own, opt_per, opt_sol, opt_un, opt_wn };
|
||||
opt_dso, opt_exc, opt_grp, opt_hlp, opt_iid, opt_imd, opt_kd, opt_mti,
|
||||
opt_nso, opt_ofl, opt_out, opt_own, opt_per, opt_sol, opt_un, opt_wn };
|
||||
const Arg_parser::Option options[] =
|
||||
{
|
||||
{ '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_grp, "group", Arg_parser::yes },
|
||||
{ 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_crc, "missing-crc", Arg_parser::no },
|
||||
{ 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_grp: cl_opts.gid = parse_group( arg, pn ); break;
|
||||
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_mti: cl_opts.mtime = parse_mtime( arg, pn );
|
||||
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_un: cl_opts.set_level( -1 ); break;
|
||||
case opt_wn: cl_opts.warn_newer = true; break;
|
||||
default : internal_error( "uncaught option" );
|
||||
default: internal_error( "uncaught option." );
|
||||
}
|
||||
} // end process options
|
||||
|
||||
|
|
17
tarlz.h
17
tarlz.h
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
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 };
|
||||
class Arg_parser;
|
||||
|
||||
struct Cl_options // command line options
|
||||
struct Cl_options // command-line options
|
||||
{
|
||||
const Arg_parser & parser;
|
||||
std::string archive_name;
|
||||
|
@ -438,6 +438,7 @@ struct Cl_options // command line options
|
|||
bool dereference;
|
||||
bool filenames_given;
|
||||
bool ignore_ids;
|
||||
bool ignore_metadata;
|
||||
bool ignore_overflow;
|
||||
bool keep_damaged;
|
||||
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 ),
|
||||
solidity( bsolid ), data_size( 0 ), debug_level( 0 ), level( 6 ),
|
||||
num_files( 0 ), num_workers( -1 ), out_slots( 64 ), dereference( false ),
|
||||
filenames_given( false ), ignore_ids( false ), ignore_overflow( false ),
|
||||
keep_damaged( false ), level_set( false ), missing_crc( false ),
|
||||
mtime_set( false ), permissive( false ), preserve_permissions( false ),
|
||||
warn_newer( false ) {}
|
||||
filenames_given( false ), ignore_ids( false ), ignore_metadata( false ),
|
||||
ignore_overflow( false ), keep_damaged( false ), level_set( false ),
|
||||
missing_crc( false ), mtime_set( false ), permissive( false ),
|
||||
preserve_permissions( false ), warn_newer( false ) {}
|
||||
|
||||
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_dict_msg = "Invalid dictionary size in member header.";
|
||||
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 gblrec_msg = "Error in global 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 werr_msg = "Write error";
|
||||
const char * const chdir_msg = "Error changing working directory";
|
||||
const char * const intdir_msg = "Failed to create intermediate directory";
|
||||
|
||||
// defined in common.cc
|
||||
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,
|
||||
std::vector< char > & name_pending,
|
||||
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
|
||||
void exit_fail_mt( const int retval = 1 ); // terminate the program
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#! /bin/sh
|
||||
# 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
|
||||
# to copy, distribute, and modify it.
|
||||
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
objdir="`pwd`"
|
||||
testdir="`cd "$1" ; pwd`"
|
||||
objdir=`pwd`
|
||||
testdir=`cd "$1" ; pwd`
|
||||
TARLZ="${objdir}"/tarlz
|
||||
framework_failure() { echo "failure in testing framework" ; exit 1 ; }
|
||||
|
||||
|
@ -154,13 +154,13 @@ printf "testing tarlz-%s..." "$2"
|
|||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -q -x -C nx_dir "${test3_lz}"
|
||||
[ $? = 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
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
"${TARLZ}" -q -tf empty.tlz
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
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
|
||||
[ $? = 2 ] || 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 cbar bar || 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
|
||||
else printf "warning: some '--diff' tests will be skipped.\n"
|
||||
fi
|
||||
|
@ -290,10 +291,12 @@ for i in "${test3}" "${test3_lz}" ; do
|
|||
cmp cfoo dir1/foo || test_failed $LINENO "$i"
|
||||
cmp cbar dir2/bar || test_failed $LINENO "$i"
|
||||
cmp cbaz dir3/baz || test_failed $LINENO "$i"
|
||||
"${TARLZ}" -q -df "$i" -C dir1 foo -C ../dir2 --ignore-ids bar \
|
||||
-C ../dir3 baz || test_failed $LINENO "$i"
|
||||
"${TARLZ}" -q -df "$i" -C dir3 baz -C ../dir2 bar -C ../dir1 foo \
|
||||
--ignore-ids || test_failed $LINENO "$i"
|
||||
if [ "${d_works}" = yes ] ; then
|
||||
"${TARLZ}" -df "$i" -C dir1 foo -C ../dir2 --ignore-ids bar \
|
||||
-C ../dir3 baz || 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
|
||||
done
|
||||
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 cbar dir2/dir/bar || 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 \
|
||||
-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"
|
||||
if [ "${d_works}" = yes ] ; then
|
||||
"${TARLZ}" -q -df "$i" --ignore-ids -C dir1 dir/foo -C ../dir2 dir/bar \
|
||||
-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
|
||||
done
|
||||
|
||||
|
@ -768,7 +773,6 @@ rm -rf out.tar dir || framework_failure
|
|||
|
||||
printf "\ntesting --diff..."
|
||||
|
||||
# test --diff
|
||||
"${TARLZ}" -xf "${test3_lz}" || test_failed $LINENO
|
||||
"${TARLZ}" -cf out.tar foo || test_failed $LINENO
|
||||
"${TARLZ}" -cf aout.tar foo --anonymous || test_failed $LINENO
|
||||
|
@ -787,6 +791,8 @@ else
|
|||
rm -f bar || framework_failure
|
||||
"${TARLZ}" -n$i -df "${test3_lz}" --ignore-ids foo baz ||
|
||||
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 ||
|
||||
test_failed $LINENO $i
|
||||
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
|
||||
cmp out.tar.lz outz.tar.lz || test_failed $LINENO
|
||||
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 out3.tar.lz foo bar baz || test_failed $LINENO
|
||||
|
|
Loading…
Add table
Reference in a new issue