summaryrefslogtreecommitdiffstats
path: root/zupdate.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-01-23 05:54:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-01-23 05:54:13 +0000
commite50d8921980602c5569b31dd9d12a24b43a196e8 (patch)
treed7240fd2cd209b129f72dac13832b6cfce13dc76 /zupdate.cc
parentReleasing debian version 1.12-3. (diff)
downloadzutils-e50d8921980602c5569b31dd9d12a24b43a196e8.tar.xz
zutils-e50d8921980602c5569b31dd9d12a24b43a196e8.zip
Merging upstream version 1.13~rc1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'zupdate.cc')
-rw-r--r--zupdate.cc58
1 files changed, 28 insertions, 30 deletions
diff --git a/zupdate.cc b/zupdate.cc
index 6497a5e..15d91d6 100644
--- a/zupdate.cc
+++ b/zupdate.cc
@@ -57,15 +57,15 @@ void show_help()
"other files are ignored. Compressed files are decompressed and then\n"
"recompressed on the fly; no temporary files are created. The lzip format\n"
"is chosen as destination because it is the most appropriate for\n"
- "long-term data archiving.\n"
+ "long-term archiving.\n"
"\nIf no files are specified, recursive searches examine the current\n"
"working directory, and nonrecursive searches do nothing.\n"
- "\nIf the lzip compressed version of a file already exists, the file is\n"
- "skipped unless the option '--force' is given. In this case, if the\n"
- "comparison with the existing lzip version fails, an error is returned\n"
- "and the original file is not deleted. The operation of zupdate is meant\n"
- "to be safe and not cause any data loss. Therefore, existing lzip\n"
- "compressed files are never overwritten nor deleted.\n"
+ "\nIf the lzip-compressed version of a file already exists, the file is skipped\n"
+ "unless the option '--force' is given. In this case, if the comparison with\n"
+ "the existing lzip version fails, an error is returned and the original file\n"
+ "is not deleted. The operation of zupdate is meant to be safe and not cause\n"
+ "any data loss. Therefore, existing lzip-compressed files are never\n"
+ "overwritten nor deleted.\n"
"\nThe names of the original files must have one of the following extensions:\n"
"\n'.bz2', '.gz', '.xz', '.zst', or '.Z', which are recompressed to '.lz'.\n"
"\n'.tbz', '.tbz2', '.tgz', '.txz', or '.tzst', which are recompressed to '.tlz'.\n"
@@ -73,7 +73,7 @@ void show_help()
"\nExit status is 0 if all the compressed files were successfully recompressed\n"
"(if needed), compared, and deleted (if requested). 1 if a non-fatal error\n"
"occurred (file not found or not regular, or has invalid format, or can't be\n"
- "deleted). 2 if a fatal error occurred (invalid command line options,\n"
+ "deleted). 2 if a fatal error occurred (invalid command-line options,\n"
"compressor can't be run, or comparison fails).\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
@@ -120,28 +120,28 @@ void extract_srcdir_name( const std::string & name, std::string & srcdir )
bool make_dirs( const std::string & name )
{
static std::string cached_dirname;
- unsigned dirsize = name.size(); // size of dirname without last slash
-
- for( unsigned i = name.size(); i > 0; --i )
- if( name[i-1] == '/' ) { dirsize = i - 1; break; }
- if( dirsize >= name.size() ) return true; // no dirname
- if( dirsize == 0 ) return true; // dirname is '/'
+ unsigned i = name.size();
+ while( i > 0 && name[i-1] != '/' ) --i; // remove last component
+ while( i > 0 && name[i-1] == '/' ) --i; // remove slash(es)
+ if( i == 0 ) return true; // dirname is '/' or empty
+ const unsigned dirsize = i; // size of dirname without trailing slash(es)
if( cached_dirname.size() == dirsize &&
cached_dirname.compare( 0, dirsize, name ) == 0 ) return true;
- for( unsigned i = 0; i < dirsize; )
+ for( i = 0; i < dirsize; )
{
while( i < dirsize && name[i] == '/' ) ++i;
const unsigned first = i;
while( i < dirsize && name[i] != '/' ) ++i;
if( first < i )
{
- std::string partial( name, 0, i );
+ 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( stat( partial.c_str(), &st ) == 0 )
- { if( !S_ISDIR( st.st_mode ) ) return false; }
- else if( mkdir( partial.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH |
- S_IXOTH ) != 0 && errno != EEXIST ) return false;
+ { if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } }
+ else if( mkdir( partial.c_str(), mode ) != 0 && errno != EEXIST )
+ return false; // if EEXIST, another process created the dir
}
}
cached_dirname.assign( name, 0, dirsize );
@@ -168,7 +168,7 @@ void set_permissions( const char * const rname, const struct stat & in_stats )
{
bool warning = false;
const mode_t mode = in_stats.st_mode;
- // 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( chown( rname, in_stats.st_uid, in_stats.st_gid ) == 0 )
{ if( chmod( rname, mode ) != 0 ) warning = true; }
else
@@ -180,7 +180,8 @@ void set_permissions( const char * const rname, const struct stat & in_stats )
t.modtime = in_stats.st_mtime;
if( utime( rname, &t ) != 0 ) warning = true;
if( warning && verbosity >= 2 )
- show_file_error( rname, "Can't change output file attributes.", errno );
+ show_file_error( rname,
+ "warning: can't change output file attributes", errno );
}
@@ -204,7 +205,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
if( format_index == fmt_lz )
{
if( verbosity >= 2 )
- std::fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
+ std::fprintf( stderr, "%s: %s: Input file already has '%s' suffix.\n",
program_name, name.c_str(), extension_from( eindex ) );
return 0; // ignore this file
}
@@ -227,8 +228,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
if( !compressor_name )
{
if( verbosity >= 2 )
- std::fprintf( stderr, "%s: Unknown extension in file name '%s' -- ignored.\n",
- program_name, name.c_str() );
+ show_file_error( name.c_str(), "Unknown extension in file name -- ignored." );
return 0; // ignore this file
}
@@ -247,9 +247,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
const bool lz_lz_exists = ( stat( rname2.c_str(), &st ) == 0 );
if( lz_exists && !force )
{
- if( verbosity >= 0 )
- std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
- program_name, rname.c_str() );
+ show_file_error( rname.c_str(), "Output file already exists, skipping." );
return -1;
}
@@ -283,8 +281,8 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
if( verbosity >= 1 )
std::fprintf( stderr, "Recompressing file '%s'\n", name.c_str() );
if( destdir.size() && !make_dirs( rname ) )
- { show_file_error( rname.c_str(), "Error creating intermediate directory." );
- return 2; }
+ { show_file_error( rname.c_str(),
+ "Error creating intermediate directory", errno ); return 2; }
int fda[2]; // pipe between decompressor and compressor
if( pipe( fda ) < 0 )
{ show_error( "Can't create pipe", errno ); return 2; }
@@ -465,7 +463,7 @@ int main( const int argc, const char * const argv[] )
case lz_opt: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, pn, fmt_zst, 1 ); break;
- default : internal_error( "uncaught option." );
+ default: internal_error( "uncaught option." );
}
} // end process options