summaryrefslogtreecommitdiffstats
path: root/compress.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compress.cc')
-rw-r--r--compress.cc69
1 files changed, 43 insertions, 26 deletions
diff --git a/compress.cc b/compress.cc
index 4e74efa..3091889 100644
--- a/compress.cc
+++ b/compress.cc
@@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression
- Copyright (C) 2013-2022 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
@@ -20,7 +20,6 @@
#include <cerrno>
#include <csignal>
#include <cstdio>
-#include <cstdlib>
#include <stdint.h> // for lzlib.h
#include <unistd.h>
#include <utime.h>
@@ -54,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 );
}
@@ -104,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
@@ -113,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 )
@@ -127,11 +123,12 @@ 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 );
}
-bool archive_write( const uint8_t * const buf, const long long size,
+bool archive_write( const uint8_t * const buf, const int size,
LZ_Encoder * const encoder )
{
static bool flushed = true; // avoid flushing empty lzip members
@@ -140,13 +137,12 @@ bool archive_write( const uint8_t * const buf, const long long size,
flushed = ( size <= 0 );
enum { obuf_size = 65536 };
uint8_t obuf[obuf_size];
- long long sz = 0;
+ int sz = 0;
if( flushed ) LZ_compress_finish( encoder ); // flush encoder
while( sz < size || flushed )
{
if( sz < size )
- { const int wr = LZ_compress_write( encoder, buf + sz,
- std::min( size - sz, (long long)max_dictionary_size ) );
+ { const int wr = LZ_compress_write( encoder, buf + sz, size - sz );
if( wr < 0 ) internal_error( "library error (LZ_compress_write)." );
sz += wr; }
if( sz >= size && !flushed ) break; // minimize dictionary size
@@ -216,26 +212,37 @@ int compress_archive( const Cl_options & cl_opts,
Resizable_buffer rbuf; // headers and extended records buffer
if( !rbuf.size() ) { show_error( mem_msg ); return 1; }
const char * const rderr_msg = "Read error";
+ bool first_header = true;
while( true ) // process one tar member per iteration
{
- int total_header_size = header_size; // size of header(s) read
+ int total_header_size = header_size; // e_header + edata + u_header
const int rd = readblock( infd, rbuf.u8(), header_size );
- if( rd == 0 && errno == 0 ) break; // missing EOA blocks
+ if( rd == 0 && errno == 0 ) // missing EOA blocks
+ { if( !first_header ) break;
+ show_file_error( filename, "Archive is empty." );
+ close( infd ); return 2; }
if( rd != header_size )
{ show_file_error( filename, rderr_msg, errno ); close( infd ); return 1; }
+ first_header = false;
- if( to_file && outfd < 0 ) // open outfd after verifying infd
+ const bool is_header = check_ustar_chksum( rbuf.u8() );
+ const bool is_zero = !is_header && block_is_zero( rbuf.u8(), header_size );
+ 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; }
delete_output_on_interrupt = true;
}
- if( !verify_ustar_chksum( rbuf.u8() ) ) // maybe EOA block
+ if( !is_header ) // maybe EOA block
{
- if( block_is_zero( rbuf.u8(), header_size ) ) // first EOA block
+ if( is_zero ) // first EOA block
{ tail_compress( cl_opts, infd, rbuf.u8(), encoder ); break; }
show_file_error( filename, bad_hdr_msg ); close( infd ); return 2;
}
@@ -246,7 +253,7 @@ int compress_archive( const Cl_options & cl_opts,
const long long edsize = parse_octal( rbuf.u8() + size_o, size_l );
const long long bufsize = round_up( edsize );
// overflow or no extended data
- if( edsize <= 0 || edsize >= 1LL << 33 || bufsize >= INT_MAX )
+ if( edsize <= 0 || edsize >= 1LL << 33 || bufsize > max_edata_size )
{ show_file_error( filename, bad_hdr_msg ); close( infd ); return 2; }
if( !rbuf.resize( total_header_size + bufsize ) )
{ show_file_error( filename, mem_msg ); close( infd ); return 1; }
@@ -263,7 +270,7 @@ int compress_archive( const Cl_options & cl_opts,
if( readblock( infd, rbuf.u8() + total_header_size, header_size ) != header_size )
{ show_file_error( filename, errno ? rderr_msg : end_msg, errno );
close( infd ); return errno ? 1 : 2; }
- if( !verify_ustar_chksum( rbuf.u8() ) )
+ if( !check_ustar_chksum( rbuf.u8() ) )
{ show_file_error( filename, bad_hdr_msg ); close( infd ); return 2; }
const Typeflag typeflag2 = (Typeflag)(rbuf() + total_header_size)[typeflag_o];
if( typeflag2 == tf_extended || typeflag2 == tf_global )
@@ -294,9 +301,7 @@ int compress_archive( const Cl_options & cl_opts,
rest -= rd;
if( rd != size )
{
- if( verbosity >= 0 )
- std::fprintf( stderr, "'%s' ends unexpectedly at pos %llu\n",
- filename, file_size - rest );
+ show_atpos_error( filename, file_size - rest, true );
close( infd ); return 1;
}
if( !archive_write( buf, size, encoder ) ) { close( infd ); return 1; }
@@ -321,6 +326,18 @@ int compress_archive( const Cl_options & cl_opts,
} // end namespace
+void show_atpos_error( const char * const filename, const long long pos,
+ const bool isarchive )
+ {
+ if( verbosity < 0 ) return;
+ std::fprintf( stderr, "%s: %s: %s %s at pos %llu%s%s\n", program_name,
+ filename, isarchive ? "Archive" : "File",
+ ( errno > 0 ) ? "read error" : "ends unexpectedly", pos,
+ ( errno > 0 ) ? ": " : "",
+ ( errno > 0 ) ? std::strerror( errno ) : "" );
+ }
+
+
int compress( const Cl_options & cl_opts )
{
if( cl_opts.num_files > 1 && cl_opts.output_filename.size() )