diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-09-24 01:57:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-09-24 01:57:58 +0000 |
commit | d35175c9e68a3ad252bfa22d266b8311df99a718 (patch) | |
tree | 0ed6c60ad70805dbda31e05d43ee1b967c478938 /create.cc | |
parent | Releasing debian version 0.22-4. (diff) | |
download | tarlz-d35175c9e68a3ad252bfa22d266b8311df99a718.tar.xz tarlz-d35175c9e68a3ad252bfa22d266b8311df99a718.zip |
Merging upstream version 0.23.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | create.cc | 277 |
1 files changed, 159 insertions, 118 deletions
@@ -63,11 +63,11 @@ bool option_C_after_relative_filename( const Arg_parser & parser ) } -/* Check archive type. Return position of EOF blocks or -1 if failure. - If remove_eof, leave fd file pos at beginning of the EOF blocks. +/* Check archive type. Return position of EOA blocks or -1 if failure. + If remove_eoa, leave fd file pos at beginning of the EOA blocks. Else, leave fd file pos at 0. */ -long long check_appendable( const int fd, const bool remove_eof ) +long long check_compressed_appendable( const int fd, const bool remove_eoa ) { struct stat st; // fd must be regular if( fstat( fd, &st ) != 0 || !S_ISREG( st.st_mode ) ) return -1; @@ -85,24 +85,25 @@ long long check_appendable( const int fd, const bool remove_eof ) LZ_decompress_read( decoder, buf, header_size ) != header_size ) { LZ_decompress_close( decoder ); return -1; } LZ_decompress_close( decoder ); - const bool maybe_eof = block_is_zero( buf, header_size ); - if( !verify_ustar_chksum( buf ) && !maybe_eof ) return -1; + const bool maybe_eoa = block_is_zero( buf, header_size ); + if( !verify_ustar_chksum( buf ) && !maybe_eoa ) return -1; const long long end = lseek( fd, 0, SEEK_END ); if( end < min_member_size ) return -1; - Lzip_trailer trailer; + Lzip_trailer trailer; // read last trailer if( seek_read( fd, trailer.data, Lzip_trailer::size, end - Lzip_trailer::size ) != Lzip_trailer::size ) return -1; const long long member_size = trailer.member_size(); if( member_size < min_member_size || member_size > end || - ( maybe_eof && member_size != end ) ) return -1; + ( maybe_eoa && member_size != end ) ) return -1; // garbage after EOA? - Lzip_header header; + Lzip_header header; // read last header if( seek_read( fd, header.data, Lzip_header::size, end - member_size ) != Lzip_header::size ) return -1; if( !header.verify_magic() || !header.verify_version() || !isvalid_ds( header.dictionary_size() ) ) return -1; + // EOA marker in last member must contain between 512 and 32256 zeros alone const unsigned long long data_size = trailer.data_size(); if( data_size < header_size || data_size > 32256 ) return -1; const unsigned data_crc = trailer.data_crc(); @@ -112,33 +113,36 @@ long long check_appendable( const int fd, const bool remove_eof ) crc ^= 0xFFFFFFFFU; if( crc != data_crc ) return -1; - const long long pos = remove_eof ? end - member_size : 0; + const long long pos = remove_eoa ? end - member_size : 0; if( lseek( fd, pos, SEEK_SET ) != pos ) return -1; return end - member_size; } -/* Skip all tar headers. Return position of EOF blocks or -1 if failure. - If remove_eof, leave fd file pos at beginning of the EOF blocks. +/* Skip all tar headers. + Return position of EOA blocks, -1 if failure, -2 if out of memory. + If remove_eoa, leave fd file pos at beginning of the EOA blocks. Else, leave fd file pos at 0. */ -long long check_uncompressed_appendable( const int fd, const bool remove_eof ) +long long check_uncompressed_appendable( const int fd, const bool remove_eoa ) { struct stat st; // fd must be regular if( fstat( fd, &st ) != 0 || !S_ISREG( st.st_mode ) ) return -1; if( lseek( fd, 0, SEEK_SET ) != 0 ) return -1; if( st.st_size <= 0 ) return 0; // append to empty archive - long long eof_pos = 0; + long long eoa_pos = 0; // pos of EOA blocks Extended extended; // metadata from extended records Resizable_buffer rbuf; // extended records buffer bool prev_extended = false; // prev header was extended + if( !rbuf.size() ) return -2; + while( true ) // process one tar header per iteration { Tar_header header; const int rd = readblock( fd, header, header_size ); - if( rd == 0 && errno == 0 ) break; // missing EOF blocks + if( rd == 0 && errno == 0 ) break; // missing EOA blocks if( rd != header_size ) return -1; - if( !verify_ustar_chksum( header ) ) // maybe EOF + if( !verify_ustar_chksum( header ) ) // maybe EOA block { if( block_is_zero( header, header_size ) ) break; else return -1; } const Typeflag typeflag = (Typeflag)header[typeflag_o]; if( typeflag == tf_extended || typeflag == tf_global ) @@ -148,7 +152,7 @@ long long check_uncompressed_appendable( const int fd, const bool remove_eof ) const long long bufsize = round_up( edsize ); if( edsize <= 0 || edsize >= 1LL << 33 || bufsize >= INT_MAX ) return -1; // overflow or no extended data - if( !rbuf.resize( bufsize ) ) return -1; + if( !rbuf.resize( bufsize ) ) return -2; if( readblock( fd, rbuf.u8(), bufsize ) != bufsize ) return -1; if( typeflag == tf_extended ) @@ -158,15 +162,15 @@ long long check_uncompressed_appendable( const int fd, const bool remove_eof ) } prev_extended = false; - eof_pos = lseek( fd, round_up( extended.get_file_size_and_reset( header ) ), + eoa_pos = lseek( fd, round_up( extended.get_file_size_and_reset( header ) ), SEEK_CUR ); - if( eof_pos <= 0 ) return -1; + if( eoa_pos <= 0 ) return -1; } if( prev_extended ) return -1; - const long long pos = remove_eof ? eof_pos : 0; + const long long pos = remove_eoa ? eoa_pos : 0; if( lseek( fd, pos, SEEK_SET ) != pos ) return -1; - return eof_pos; + return eoa_pos; } @@ -202,8 +206,9 @@ bool archive_write( const uint8_t * const buf, const int size ) bool write_extended( const Extended & extended ) { - const long long ebsize = extended.format_block( grbuf ); - if( ebsize < 0 ) return false; + const long long ebsize = extended.format_block( grbuf ); // may be 0 + if( ebsize < 0 ) + { show_error( ( ebsize == -2 ) ? mem_msg2 : eferec_msg ); return false; } for( long long pos = 0; pos < ebsize; ) // write extended block to archive { int size = std::min( ebsize - pos, 1LL << 20 ); @@ -218,7 +223,8 @@ bool write_extended( const Extended & extended ) bool store_name( const char * const filename, Extended & extended, Tar_header header, const bool force_extended_name ) { - const char * const stored_name = remove_leading_dotslash( filename, true ); + const char * const stored_name = + remove_leading_dotslash( filename, &extended.removed_prefix, true ); if( !force_extended_name ) // try storing filename in the ustar header { @@ -250,6 +256,7 @@ int add_member( const char * const filename, const struct stat *, Extended extended; // metadata for extended records Tar_header header; if( !fill_headers( filename, extended, header, file_size, flag ) ) return 0; + print_removed_prefix( extended.removed_prefix ); const int infd = file_size ? open_instream( filename ) : -1; if( file_size && infd < 0 ) { set_error_status( 1 ); return 0; } @@ -286,7 +293,7 @@ int add_member( const char * const filename, const struct stat *, if( !archive_write( buf, size ) ) { close( infd ); return 1; } } if( close( infd ) != 0 ) - { show_file_error( filename, "Error closing file", errno ); return 1; } + { show_file_error( filename, eclosf_msg, errno ); return 1; } } if( encoder && gcl_opts->solidity == no_solid && !archive_write( 0, 0 ) ) return 1; @@ -297,6 +304,18 @@ int add_member( const char * const filename, const struct stat *, return 0; } + +bool check_tty_out( const char * const archive_namep, const int outfd, + const bool to_stdout ) + { + if( isatty( outfd ) ) // for example /dev/tty + { show_file_error( archive_namep, to_stdout ? + "I won't write archive data to a terminal (missing -f option?)" : + "I won't write archive data to a terminal." ); + return false; } + return true; + } + } // end namespace @@ -335,23 +354,23 @@ bool writeblock_wrapper( const int outfd, const uint8_t * const buffer, const int size ) { if( writeblock( outfd, buffer, size ) != size ) - { show_file_error( archive_namep, "Write error", errno ); return false; } + { show_file_error( archive_namep, werr_msg, errno ); return false; } return true; } // write End-Of-Archive records -bool write_eof_records( const int outfd, const bool compressed ) +bool write_eoa_records( const int outfd, const bool compressed ) { if( compressed ) { - enum { eof_member_size = 44 }; - const uint8_t eof_member[eof_member_size] = { + enum { eoa_member_size = 44 }; + const uint8_t eoa_member[eoa_member_size] = { 0x4C, 0x5A, 0x49, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x6F, 0xFD, 0xFF, 0xFF, 0xA3, 0xB7, 0x80, 0x0C, 0x82, 0xDB, 0xFF, 0xFF, 0x9F, 0xF0, 0x00, 0x00, 0x2E, 0xAF, 0xB5, 0xEF, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - return writeblock_wrapper( outfd, eof_member, eof_member_size ); + return writeblock_wrapper( outfd, eoa_member, eoa_member_size ); } enum { bufsize = 2 * header_size }; uint8_t buf[bufsize]; @@ -360,40 +379,52 @@ bool write_eof_records( const int outfd, const bool compressed ) } -/* Removes any amount of leading "./" and '/' strings from filename. - Optionally also removes prefixes containing a ".." component. +/* Remove any amount of leading "./" and '/' strings from filename. + Optionally also remove prefixes containing a ".." component. + Return the removed prefix in *removed_prefixp. */ const char * remove_leading_dotslash( const char * const filename, + std::string * const removed_prefixp, const bool dotdot ) { - // prevent two threads from modifying the list of prefixes at the same time - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - static std::vector< std::string > prefixes; // list of prefixes const char * p = filename; if( dotdot ) for( int i = 0; filename[i]; ++i ) if( dotdot_at_i( filename, i ) ) p = filename + i + 2; while( *p == '/' || ( *p == '.' && p[1] == '/' ) ) ++p; - if( p != filename ) - { - std::string msg( filename, p - filename ); - unsigned i = 0; - xlock( &mutex ); - while( i < prefixes.size() && prefixes[i] != msg ) ++i; - if( i >= prefixes.size() ) - { - prefixes.push_back( msg ); - msg.insert( 0, "Removing leading '" ); msg += "' from member names."; - show_error( msg.c_str() ); - } - xunlock( &mutex ); - } + if( p != filename ) removed_prefixp->assign( filename, p - filename ); + else removed_prefixp->clear(); // no prefix was removed if( *p == 0 && *filename != 0 ) p = "."; return p; } +/* If msgp is null, print the message, else return the message in *msgp. + If prefix is already in the list, print nothing or return empty *msgp. + Return true if a message is printed or returned in *msgp. */ +bool print_removed_prefix( const std::string & prefix, + std::string * const msgp ) + { + // prevent two threads from modifying the list of prefixes at the same time + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static std::vector< std::string > prefixes; // list of prefixes + + if( verbosity < 0 || prefix.empty() ) + { if( msgp ) msgp->clear(); return false; } + xlock( &mutex ); + for( unsigned i = 0; i < prefixes.size(); ++i ) + if( prefixes[i] == prefix ) + { xunlock( &mutex ); if( msgp ) msgp->clear(); return false; } + prefixes.push_back( prefix ); + std::string msg( "Removing leading '" ); msg += prefix; + msg += "' from member names."; + if( msgp ) *msgp = msg; else show_error( msg.c_str() ); + xunlock( &mutex ); // put here to prevent mixing calls to show_error + return true; + } + + // set file_size != 0 only for regular files bool fill_headers( const char * const filename, Extended & extended, Tar_header header, long long & file_size, const int flag ) @@ -403,7 +434,7 @@ bool fill_headers( const char * const filename, Extended & extended, { show_file_error( filename, cant_stat, errno ); set_error_status( 1 ); return false; } if( archive_attrs.is_the_archive( st ) ) - { show_file_error( archive_namep, "File is the archive; not dumped." ); + { show_file_error( archive_namep, "Archive can't contain itself; not dumped." ); return false; } init_tar_header( header ); bool force_extended_name = false; @@ -412,19 +443,17 @@ bool fill_headers( const char * const filename, Extended & extended, print_octal( header + mode_o, mode_l - 1, mode & ( S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO ) ); - const uid_t uid = (gcl_opts->owner >= 0) ? (uid_t)gcl_opts->owner : st.st_uid; - const gid_t gid = (gcl_opts->group >= 0) ? (gid_t)gcl_opts->group : st.st_gid; - if( uid >= 2 << 20 || gid >= 2 << 20 ) - { show_file_error( filename, "uid or gid is larger than 2_097_151." ); - set_error_status( 1 ); return false; } - print_octal( header + uid_o, uid_l - 1, uid ); - print_octal( header + gid_o, gid_l - 1, gid ); - const unsigned long long mtime = ( gcl_opts->mtime >= 0 ) ? gcl_opts->mtime : - ( ( st.st_mtime >= 0 ) ? st.st_mtime : 0 ); - if( mtime >= 1ULL << 33 ) - { show_file_error( filename, "mtime is out of ustar range [0, 8_589_934_591]." ); - set_error_status( 1 ); return false; } - print_octal( header + mtime_o, mtime_l - 1, mtime ); + const long long uid = ( gcl_opts->uid >= 0 ) ? gcl_opts->uid : st.st_uid; + const long long gid = ( gcl_opts->gid >= 0 ) ? gcl_opts->gid : st.st_gid; + if( uid_in_ustar_range( uid ) ) print_octal( header + uid_o, uid_l - 1, uid ); + else if( extended.set_uid( uid ) ) force_extended_name = true; + if( uid_in_ustar_range( gid ) ) print_octal( header + gid_o, gid_l - 1, gid ); + else if( extended.set_gid( gid ) ) force_extended_name = true; + const long long mtime = gcl_opts->mtime_set ? gcl_opts->mtime : st.st_mtime; + if( time_in_ustar_range( mtime ) ) + print_octal( header + mtime_o, mtime_l - 1, mtime ); + else { extended.set_atime( gcl_opts->mtime_set ? mtime : st.st_atime ); + extended.set_mtime( mtime ); force_extended_name = true; } Typeflag typeflag; if( S_ISREG( mode ) ) typeflag = tf_regular; else if( S_ISDIR( mode ) ) @@ -458,8 +487,16 @@ bool fill_headers( const char * const filename, Extended & extended, delete[] buf; } if( sz != st.st_size ) - { show_file_error( filename, "Error reading link", (sz < 0) ? errno : 0 ); - set_error_status( 1 ); return false; } + { + if( sz < 0 ) + show_file_error( filename, "Error reading symbolic link", errno ); + else + show_file_error( filename, "Wrong size reading symbolic link.\n" + "Please, send a bug report to the maintainers of your filesystem, " + "mentioning\n'wrong st_size of symbolic link'.\nSee " + "http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html" ); + set_error_status( 1 ); return false; + } } else if( S_ISCHR( mode ) || S_ISBLK( mode ) ) { @@ -475,18 +512,17 @@ bool fill_headers( const char * const filename, Extended & extended, else { show_file_error( filename, "Unknown file type." ); set_error_status( 2 ); return false; } header[typeflag_o] = typeflag; -// errno = 0; - const struct passwd * const pw = getpwuid( uid ); - if( pw && pw->pw_name ) - std::strncpy( (char *)header + uname_o, pw->pw_name, uname_l - 1 ); -/* else { show_file_error( filename, "Can't read user name from database", errno ); - set_error_status( 1 ); } */ // numerical only -// errno = 0; - const struct group * const gr = getgrgid( gid ); - if( gr && gr->gr_name ) - std::strncpy( (char *)header + gname_o, gr->gr_name, gname_l - 1 ); -/* else { show_file_error( filename, "Can't read group name from database", errno ); - set_error_status( 1 ); } */ // numerical only + + if( uid == (long long)( (uid_t)uid ) ) // get name if uid is in range + { const struct passwd * const pw = getpwuid( uid ); + if( pw && pw->pw_name ) + std::strncpy( (char *)header + uname_o, pw->pw_name, uname_l - 1 ); } + + if( gid == (long long)( (gid_t)gid ) ) // get name if gid is in range + { const struct group * const gr = getgrgid( gid ); + if( gr && gr->gr_name ) + std::strncpy( (char *)header + gname_o, gr->gr_name, gname_l - 1 ); } + file_size = ( typeflag == tf_regular && st.st_size > 0 && st.st_size <= max_file_size ) ? st.st_size : 0; if( file_size >= 1LL << 33 ) @@ -525,7 +561,7 @@ void set_error_status( const int retval ) int final_exit_status( int retval, const bool show_msg ) { - if( !retval && error_status ) + if( retval == 0 && error_status ) { if( show_msg ) show_error( "Exiting with failure status due to previous errors." ); retval = error_status; } @@ -564,6 +600,8 @@ int concatenate( const Cl_options & cl_opts ) const int outfd = to_stdout ? STDOUT_FILENO : open_outstream( cl_opts.archive_name, false ); if( outfd < 0 ) return 1; + if( !check_tty_out( archive_namep, outfd, to_stdout ) ) + { close( outfd ); return 1; } if( !to_stdout && !archive_attrs.init( outfd ) ) { show_file_error( archive_namep, "Can't stat", errno ); return 1; } int compressed; // tri-state bool @@ -571,22 +609,23 @@ int concatenate( const Cl_options & cl_opts ) else { compressed = has_lz_ext( cl_opts.archive_name ); // default value - long long pos = check_appendable( outfd, true ); + long long pos = check_compressed_appendable( outfd, true ); if( pos > 0 ) compressed = true; else if( pos < 0 ) { pos = check_uncompressed_appendable( outfd, true ); if( pos > 0 ) compressed = false; + else if( pos == -2 ) { show_error( mem_msg ); close( outfd ); return 1; } else if( pos < 0 ) { show_file_error( archive_namep, compressed ? "This does not look like an appendable tar.lz archive." : "This does not look like an appendable tar archive." ); - return 2; } + close( outfd ); return 2; } } } int retval = 0; - bool eof_pending = false; + bool eoa_pending = false; for( int i = 0; i < cl_opts.parser.arguments(); ++i ) // copy archives { if( !nonempty_arg( cl_opts.parser, i ) ) continue; // skip opts, empty names @@ -596,18 +635,21 @@ int concatenate( const Cl_options & cl_opts ) if( infd < 0 ) { retval = 1; break; } struct stat st; if( !to_stdout && fstat( infd, &st ) == 0 && archive_attrs.is_the_archive( st ) ) - { show_file_error( filename, "File is the archive; not concatenated." ); + { show_file_error( filename, "Archive can't contain itself; not concatenated." ); close( infd ); continue; } long long size; if( compressed < 0 ) // not initialized yet { - if( ( size = check_appendable( infd, false ) ) > 0 ) compressed = true; + if( ( size = check_compressed_appendable( infd, false ) ) > 0 ) + compressed = true; else if( ( size = check_uncompressed_appendable( infd, false ) ) > 0 ) compressed = false; - else { size = -1 ; compressed = has_lz_ext( filename ); } + else if( size != -2 ) { size = -1 ; compressed = has_lz_ext( filename ); } } - else size = compressed ? check_appendable( infd, false ) : + else size = compressed ? check_compressed_appendable( infd, false ) : check_uncompressed_appendable( infd, false ); + if( size == -2 ) + { show_error( mem_msg ); close( infd ); retval = 1; break; } if( size < 0 ) { show_file_error( filename, compressed ? "Not an appendable tar.lz archive." : @@ -615,22 +657,22 @@ int concatenate( const Cl_options & cl_opts ) close( infd ); retval = 2; break; } if( !copy_file( infd, outfd, size ) || close( infd ) != 0 ) { show_file_error( filename, "Error copying archive", errno ); - eof_pending = false; retval = 1; break; } - eof_pending = true; + eoa_pending = false; retval = 1; break; } + eoa_pending = true; if( verbosity >= 1 ) std::fprintf( stderr, "%s\n", filename ); } - if( eof_pending && !write_eof_records( outfd, compressed ) && !retval ) + if( eoa_pending && !write_eoa_records( outfd, compressed ) && retval == 0 ) retval = 1; - if( close( outfd ) != 0 && !retval ) - { show_file_error( archive_namep, "Error closing archive", errno ); - retval = 1; } + if( close( outfd ) != 0 && retval == 0 ) + { show_file_error( archive_namep, eclosa_msg, errno ); retval = 1; } return retval; } -int encode( Cl_options & cl_opts ) +int encode( const Cl_options & cl_opts ) { + if( !grbuf.size() ) { show_error( mem_msg ); return 1; } const bool compressed = ( cl_opts.level >= 0 && cl_opts.level <= 9 ); const bool to_stdout = cl_opts.archive_name.empty(); archive_namep = to_stdout ? "(stdout)" : cl_opts.archive_name.c_str(); @@ -652,31 +694,33 @@ int encode( Cl_options & cl_opts ) if( to_stdout ) // create/append to stdout goutfd = STDOUT_FILENO; - else if( !append ) // create archive - { if( ( goutfd = open_outstream( cl_opts.archive_name ) ) < 0 ) return 1; } - else // append to archive - { - if( ( goutfd = open_outstream( cl_opts.archive_name, false ) ) < 0 ) + else // create/append to archive + if( ( goutfd = open_outstream( cl_opts.archive_name, !append ) ) < 0 ) return 1; - if( compressed && check_appendable( goutfd, true ) < 0 ) - { show_file_error( archive_namep, - "This does not look like an appendable tar.lz archive." ); return 2; } - if( !compressed && check_uncompressed_appendable( goutfd, true ) < 0 ) + if( !check_tty_out( archive_namep, goutfd, to_stdout ) ) + { close( goutfd ); return 1; } + if( append && !to_stdout ) + { + if( compressed && check_compressed_appendable( goutfd, true ) < 0 ) { show_file_error( archive_namep, - "This does not look like an appendable tar archive." ); return 2; } + "This does not look like an appendable tar.lz archive." ); + close( goutfd ); return 2; } + if( !compressed ) + { + const long long pos = check_uncompressed_appendable( goutfd, true ); + if( pos == -2 ) { show_error( mem_msg ); close( goutfd ); return 1; } + if( pos < 0 ) { show_file_error( archive_namep, + "This does not look like an appendable tar archive." ); + close( goutfd ); return 2; } + } } if( !archive_attrs.init( goutfd ) ) - { show_file_error( archive_namep, "Can't stat", errno ); return 1; } + { show_file_error( archive_namep, "Can't stat", errno ); + close( goutfd ); return 1; } if( compressed ) { - const int dictionary_size = option_mapping[cl_opts.level].dictionary_size; - if( cl_opts.data_size <= 0 ) - { - if( cl_opts.level == 0 ) cl_opts.data_size = 1 << 20; - else cl_opts.data_size = 2 * dictionary_size; - } /* CWD is not per-thread; multi-threaded --create can't be used if a -C option appears after a relative filename in the command line. */ if( cl_opts.solidity != asolid && cl_opts.solidity != solid && @@ -684,10 +728,9 @@ int encode( Cl_options & cl_opts ) !option_C_after_relative_filename( cl_opts.parser ) ) { // show_file_error( archive_namep, "Multi-threaded --create" ); - return encode_lz( cl_opts, archive_namep, dictionary_size, - option_mapping[cl_opts.level].match_len_limit, goutfd ); + return encode_lz( cl_opts, archive_namep, goutfd ); } - encoder = LZ_compress_open( dictionary_size, + encoder = LZ_compress_open( option_mapping[cl_opts.level].dictionary_size, option_mapping[cl_opts.level].match_len_limit, LLONG_MAX ); if( !encoder || LZ_compress_errno( encoder ) != LZ_ok ) { @@ -695,7 +738,7 @@ int encode( Cl_options & cl_opts ) show_error( mem_msg2 ); else internal_error( "invalid argument to encoder." ); - return 1; + close( goutfd ); return 1; } } @@ -706,8 +749,7 @@ int encode( Cl_options & cl_opts ) const std::string & arg = cl_opts.parser.argument( i ); const char * filename = arg.c_str(); if( code == 'C' && chdir( filename ) != 0 ) - { show_file_error( filename, "Error changing working directory", errno ); - retval = 1; break; } + { show_file_error( filename, chdir_msg, errno ); retval = 1; break; } if( code ) continue; // skip options if( cl_opts.parser.argument( i ).empty() ) continue; // skip empty names std::string deslashed; // arg without trailing slashes @@ -726,7 +768,7 @@ int encode( Cl_options & cl_opts ) { retval = 1; break; } } - if( !retval ) // write End-Of-Archive records + if( retval == 0 ) // write End-Of-Archive records { enum { bufsize = 2 * header_size }; uint8_t buf[bufsize]; @@ -740,8 +782,7 @@ int encode( Cl_options & cl_opts ) } if( encoder && LZ_compress_close( encoder ) < 0 ) { show_error( "LZ_compress_close failed." ); retval = 1; } - if( close( goutfd ) != 0 && !retval ) - { show_file_error( archive_namep, "Error closing archive", errno ); - retval = 1; } + if( close( goutfd ) != 0 && retval == 0 ) + { show_file_error( archive_namep, eclosa_msg, errno ); retval = 1; } return final_exit_status( retval ); } |