summaryrefslogtreecommitdiffstats
path: root/zupdate.cc
diff options
context:
space:
mode:
Diffstat (limited to 'zupdate.cc')
-rw-r--r--zupdate.cc103
1 files changed, 44 insertions, 59 deletions
diff --git a/zupdate.cc b/zupdate.cc
index 02dfe29..2b88c79 100644
--- a/zupdate.cc
+++ b/zupdate.cc
@@ -37,24 +37,18 @@
#endif
#include "arg_parser.h"
-#include "zutils.h"
#include "rc.h"
-#if CHAR_BIT != 8
-#error "Environments where CHAR_BIT != 8 are not supported."
+#ifndef O_BINARY
+#define O_BINARY 0
#endif
namespace {
-#ifdef O_BINARY
-const int o_binary = O_BINARY;
-#else
-const int o_binary = 0;
-#endif
-
+#include "recursive.cc"
-void show_zupdate_help()
+void show_help()
{
std::printf( "Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.\n"
"The originals are compared with the new files and then deleted.\n"
@@ -77,6 +71,7 @@ void show_zupdate_help()
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" -f, --force do not skip a file even if the .lz exists\n"
+ " -k, --keep keep (don't delete) input files\n"
" -l, --lzip-verbose pass a -v option to the lzip compressor\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
@@ -97,10 +92,10 @@ int cant_execute( const std::string & command, const int status )
{
if( WIFEXITED( status ) )
std::fprintf( stderr, "%s: Error executing '%s'. Exit status = %d.\n",
- util_name, command.c_str(), WEXITSTATUS( status ) );
+ program_name, command.c_str(), WEXITSTATUS( status ) );
else
std::fprintf( stderr, "%s: Can't execute '%s'.\n",
- util_name, command.c_str() );
+ program_name, command.c_str() );
}
return 1;
}
@@ -136,11 +131,13 @@ struct { const char * from; const char * to; int format_index; } const
{ ".txz", ".tar", fmt_xz },
{ 0, 0, -1 } };
+int disable_xz = -1; // tri-state bool
+
// Returns 0 for success, -1 for file skipped, 1 for error.
int zupdate_file( const std::string & name, const char * const lzip_name,
const std::vector< std::string > & lzip_args2,
- const bool force )
+ const bool force, const bool keep_input_files )
{
int format_index = -1;
std::string dname; // decompressed_name
@@ -158,7 +155,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{
if( verbosity >= 2 )
std::fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
- util_name, name.c_str(), known_extensions[i].from );
+ program_name, name.c_str(), known_extensions[i].from );
return 0; // ignore this file
}
break;
@@ -169,7 +166,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{
if( verbosity >= 2 )
std::fprintf( stderr, "%s: Unknown extension in file name '%s' -- ignored.\n",
- util_name, name.c_str() );
+ program_name, name.c_str() );
return 0; // ignore this file
}
@@ -178,14 +175,14 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't stat input file '%s': %s.\n",
- util_name, name.c_str(), std::strerror( errno ) );
+ program_name, name.c_str(), std::strerror( errno ) );
return 1;
}
if( !S_ISREG( in_stats.st_mode ) )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Input file '%s' is not a regular file.\n",
- util_name, name.c_str() );
+ program_name, name.c_str() );
return 1;
}
@@ -196,10 +193,20 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
- util_name, rname.c_str() );
+ program_name, rname.c_str() );
return -1;
}
+ if( format_index == fmt_xz )
+ {
+ if( disable_xz < 0 )
+ {
+ std::string command( compressor_name ); command += " -V > /dev/null";
+ disable_xz = ( std::system( command.c_str() ) != 0 );
+ }
+ if( disable_xz ) return 0; // ignore this file if no xz installed
+ }
+
if( !lz_exists ) // recompress
{
if( verbosity >= 1 )
@@ -280,11 +287,11 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
return cant_execute( zcmp_command, status ); }
}
- if( std::remove( name.c_str() ) != 0 && errno != ENOENT )
+ if( !keep_input_files && std::remove( name.c_str() ) != 0 && errno != ENOENT )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't delete input file '%s': %s.\n",
- util_name, name.c_str(), std::strerror( errno ) );
+ program_name, name.c_str(), std::strerror( errno ) );
return 1;
}
return 0;
@@ -300,9 +307,10 @@ int main( const int argc, const char * const argv[] )
std::list< std::string > filenames;
std::vector< std::string > lzip_args2; // args to lzip, maybe empty
bool force = false;
+ bool keep_input_files = false;
bool recursive = false;
invocation_name = argv[0];
- util_name = "zupdate";
+ program_name = "zupdate";
const Arg_parser::Option options[] =
{
@@ -318,6 +326,7 @@ int main( const int argc, const char * const argv[] )
{ '9', 0, Arg_parser::no },
{ 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
+ { 'k', "keep", Arg_parser::no },
{ 'l', "lzip-verbose", Arg_parser::no },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
@@ -342,23 +351,24 @@ int main( const int argc, const char * const argv[] )
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
- switch( code ) // common options
+ switch( code )
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
lzip_args2.push_back( "-" ); lzip_args2.back() += code; break;
case 'f': force = true; break;
- case 'h': show_zupdate_help(); return 0;
+ case 'h': show_help(); return 0;
+ case 'k': keep_input_files = true; break;
case 'l': lzip_args2.push_back( "-v" ); break;
- case 'N': continue;
+ case 'N': break;
case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break;
case 'r': recursive = true; break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version( "Zupdate" ); return 0;
- case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); continue;
- case gz_opt: parse_compressor( arg, fmt_gz, 1 ); continue;
- case lz_opt: parse_compressor( arg, fmt_lz, 1 ); continue;
- case xz_opt: parse_compressor( arg, fmt_xz, 1 ); continue;
+ case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); break;
+ case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
+ case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
+ case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
default : internal_error( "uncaught option" );
}
} // end process options
@@ -376,40 +386,15 @@ int main( const int argc, const char * const argv[] )
filenames.push_back( parser.argument( argind ) );
int retval = 0;
- while( !filenames.empty() )
+ bool error = false;
+ while( next_filename( filenames, input_filename, error, recursive, true ) )
{
- input_filename = filenames.front();
- filenames.pop_front();
- if( !input_filename.size() || input_filename == "-" ) continue;
- if( recursive )
- {
- struct stat st;
- if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
- {
- DIR * const dirp = opendir( input_filename.c_str() );
- if( !dirp )
- {
- show_error2( "Can't open directory", input_filename.c_str() );
- if( retval < 1 ) retval = 1; continue;
- }
- std::list< std::string > tmp_list;
- while( true )
- {
- const struct dirent * const entryp = readdir( dirp );
- if( !entryp ) { closedir( dirp ); break; }
- std::string tmp_name( entryp->d_name );
- if( tmp_name != "." && tmp_name != ".." )
- tmp_list.push_back( input_filename + "/" + tmp_name );
- }
- filenames.splice( filenames.begin(), tmp_list );
- continue;
- }
- }
-
- int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force );
- if( tmp < 0 && retval < 1 ) retval = 1;
+ int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force,
+ keep_input_files );
+ if( tmp < 0 ) error = true;
if( tmp > retval ) retval = tmp;
if( tmp > 0 ) break;
}
+ if( error && retval == 0 ) retval = 1;
return retval;
}