#include <fstream>
#include <iomanip>
-#include "zypp/base/Logger.h"
+#include "zypp/base/LogTools.h"
#include "zypp/base/String.h"
#include "zypp/base/IOStream.h"
+#include "zypp/base/StrMatcher.h"
+#include "zypp/base/Errno.h"
+#include "zypp/AutoDispose.h"
#include "zypp/ExternalProgram.h"
#include "zypp/PathInfo.h"
#include "zypp/Digest.h"
{
if ( !isExist() )
return 0;
- if ( owner() == getuid() ) {
+ if ( owner() == geteuid() ) {
return( uperm()/0100 );
- } else if ( group() == getgid() ) {
+ } else if ( group() == getegid() ) {
return( gperm()/010 );
}
return operm();
/******************************************************************
**
- ** FUNCTION NAME : PathInfo::major
+ ** FUNCTION NAME : PathInfo::devMajor
** FUNCTION TYPE : unsigned int
*/
- unsigned int PathInfo::major() const
+ unsigned int PathInfo::devMajor() const
{
- return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
+ return isBlk() || isChr() ? major(statbuf_C.st_rdev) : 0;
}
/******************************************************************
**
- ** FUNCTION NAME : PathInfo::minor
+ ** FUNCTION NAME : PathInfo::devMinor
** FUNCTION TYPE : unsigned int
*/
- unsigned int PathInfo::minor() const
+ unsigned int PathInfo::devMinor() const
{
- return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
+ return isBlk() || isChr() ? minor(statbuf_C.st_rdev) : 0;
}
/******************************************************************
str << obj.asString() << "{";
if ( !obj.isExist() ) {
- str << "does not exist}";
+ str << Errno( obj.error() );
} else {
str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
if ( obj.isFile() )
str << " size " << obj.size();
-
- str << "}";
}
- return str;
+ return str << "}";
}
///////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////
- /******************************************************************
- **
- ** FUNCTION NAME : _Log_Result
- ** FUNCTION TYPE : int
- **
- ** DESCRIPTION : Helper function to log return values.
- */
-#define _Log_Result MIL << endl, __Log_Result
- inline int __Log_Result( const int res, const char * rclass = 0 /*errno*/ )
- {
- if ( res )
+#define logResult MIL << endl, doLogResult
+ namespace {
+ /** Helper function to log return values. */
+ inline int doLogResult( const int res, const char * rclass = 0 /*errno*/ )
{
- if ( rclass )
- WAR << " FAILED: " << rclass << " " << res << endl;
- else
- WAR << " FAILED: " << str::strerror( res ) << endl;
+ if ( res )
+ {
+ if ( rclass )
+ WAR << " FAILED: " << rclass << " " << res << endl;
+ else
+ WAR << " FAILED: " << str::strerror( res ) << endl;
+ }
+ return res;
}
- return res;
- }
+ } // namespace
///////////////////////////////////////////////////////////////////
//
{
MIL << "mkdir " << path << ' ' << str::octstring( mode );
if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
{
MIL << "rmdir " << path;
if ( ::rmdir( path.asString().c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
// METHOD NAME : recursive_rmdir
// METHOD TYPE : int
//
- static int recursive_rmdir_1( const Pathname & dir )
+ static int recursive_rmdir_1( const Pathname & dir, bool removeDir = true )
{
DIR * dp;
struct dirent * d;
if ( ! (dp = opendir( dir.c_str() )) )
- return _Log_Result( errno );
+ return logResult( errno );
while ( (d = readdir(dp)) )
{
}
closedir( dp );
- if ( ::rmdir( dir.c_str() ) < 0 )
+ if ( removeDir && ::rmdir( dir.c_str() ) < 0 )
return errno;
return 0;
PathInfo p( path );
if ( !p.isExist() ) {
- return _Log_Result( 0 );
+ return logResult( 0 );
}
if ( !p.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
- return _Log_Result( recursive_rmdir_1( path ) );
+ return logResult( recursive_rmdir_1( path ) );
}
///////////////////////////////////////////////////////////////////
PathInfo p( path );
if ( !p.isExist() ) {
- return _Log_Result( 0 );
+ return logResult( 0 );
}
if ( !p.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
- string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
- ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
- for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
- MIL << " " << output;
- }
- int ret = prog.close();
- return _Log_Result( ret, "returned" );
+ return logResult( recursive_rmdir_1( path, false/* don't remove path itself */ ) );
}
///////////////////////////////////////////////////////////////////
PathInfo sp( srcpath );
if ( !sp.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
PathInfo dp( destpath );
if ( !dp.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
PathInfo tp( destpath + srcpath.basename() );
if ( tp.isExist() ) {
- return _Log_Result( EEXIST );
+ return logResult( EEXIST );
}
MIL << " " << output;
}
int ret = prog.close();
- return _Log_Result( ret, "returned" );
+ return logResult( ret, "returned" );
}
///////////////////////////////////////////////////////////////////
PathInfo sp( srcpath );
if ( !sp.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
PathInfo dp( destpath );
if ( !dp.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
if ( srcpath == destpath ) {
- return _Log_Result( EEXIST );
+ return logResult( EEXIST );
}
std::string src( srcpath.asString());
MIL << " " << output;
}
int ret = prog.close();
- return _Log_Result( ret, "returned" );
+ return logResult( ret, "returned" );
}
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : readdir
- // METHOD TYPE : int
- //
- int readdir( std::list<std::string> & retlist,
- const Pathname & path, bool dots )
+ ///////////////////////////////////////////////////////////////////////
+ // dirForEach
+ ///////////////////////////////////////////////////////////////////////
+
+ const StrMatcher & matchNoDots()
{
- retlist.clear();
+ static StrMatcher noDots( "[^.]*", Match::GLOB );
+ return noDots;
+ }
- MIL << "readdir " << path << ' ';
+ int dirForEach( const Pathname & dir_r, function<bool(const Pathname &, const char *const)> fnc_r )
+ {
+ if ( ! fnc_r )
+ return 0;
- DIR * dir = ::opendir( path.asString().c_str() );
- if ( ! dir ) {
- return _Log_Result( errno );
- }
+ AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
+ []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
- struct dirent *entry;
- while ( (entry = ::readdir( dir )) != 0 ) {
+ MIL << "readdir " << dir_r << ' ';
+ if ( ! dir )
+ return logResult( errno );
+ MIL << endl; // close line before callbacks are invoked.
- if ( entry->d_name[0] == '.' ) {
- if ( !dots )
- continue;
- if ( entry->d_name[1] == '\0'
- || ( entry->d_name[1] == '.'
- && entry->d_name[2] == '\0' ) )
- continue;
- }
- retlist.push_back( entry->d_name );
+ int ret = 0;
+ for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
+ {
+ if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
+ continue; // omitt . and ..
+
+ if ( ! fnc_r( dir_r, entry->d_name ) )
+ {
+ ret = -1;
+ break;
+ }
}
-
- ::closedir( dir );
-
- return _Log_Result( 0 );
+ return ret;
}
+ int dirForEach( const Pathname & dir_r, const StrMatcher & matcher_r, function<bool( const Pathname &, const char *const)> fnc_r )
+ {
+ if ( ! fnc_r )
+ return 0;
+
+ bool nodots = ( &matcher_r == &matchNoDots() );
+ return dirForEach( dir_r,
+ [&]( const Pathname & dir_r, const char *const name_r )->bool
+ {
+ if ( ( nodots && name_r[0] == '.' ) || ! matcher_r( name_r ) )
+ return true;
+ return fnc_r( dir_r, name_r );
+ } );
+ }
///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : readdir
- // METHOD TYPE : int
- //
- int readdir( std::list<Pathname> & retlist,
- const Pathname & path, bool dots )
- {
- retlist.clear();
+ // readdir
+ ///////////////////////////////////////////////////////////////////
- std::list<string> content;
- int res = readdir( content, path, dots );
+ int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
+ {
+ retlist_r.clear();
+ return dirForEach( path_r,
+ [&]( const Pathname & dir_r, const char *const name_r )->bool
+ {
+ if ( dots_r || name_r[0] != '.' )
+ retlist_r.push_back( name_r );
+ return true;
+ } );
+ }
- if ( !res ) {
- for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
- retlist.push_back( path + *it );
- }
- }
- return res;
+ int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
+ {
+ retlist_r.clear();
+ return dirForEach( path_r,
+ [&]( const Pathname & dir_r, const char *const name_r )->bool
+ {
+ if ( dots_r || name_r[0] != '.' )
+ retlist_r.push_back( dir_r/name_r );
+ return true;
+ } );
}
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : readdir
- // METHOD TYPE : int
- //
-
bool DirEntry::operator==( const DirEntry &rhs ) const
{
// if one of the types is not known, use the name only
return ((name == rhs.name ) && (type == rhs.type));
}
- int readdir( DirContent & retlist, const Pathname & path,
- bool dots, PathInfo::Mode statmode )
+ int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_r )
{
- retlist.clear();
-
- std::list<string> content;
- int res = readdir( content, path, dots );
-
- if ( !res ) {
- for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
- PathInfo p( path + *it, statmode );
- retlist.push_back( DirEntry( *it, p.fileType() ) );
- }
- }
-
- return res;
+ retlist_r.clear();
+ return dirForEach( path_r,
+ [&]( const Pathname & dir_r, const char *const name_r )->bool
+ {
+ if ( dots_r || name_r[0] != '.' )
+ retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
+ return true;
+ } );
}
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : is_empty_dir
- // METHOD TYPE : int
- //
- int is_empty_dir(const Pathname & path)
- {
- DIR * dir = ::opendir( path.asString().c_str() );
- if ( ! dir ) {
- return _Log_Result( errno );
- }
-
- struct dirent *entry;
- while ( (entry = ::readdir( dir )) != NULL )
- {
- std::string name(entry->d_name);
-
- if ( name == "." || name == "..")
- continue;
+ std::ostream & operator<<( std::ostream & str, const DirContent & obj )
+ { return dumpRange( str, obj.begin(), obj.end() ); }
- break;
- }
- ::closedir( dir );
+ ///////////////////////////////////////////////////////////////////
+ // is_empty_dir
+ ///////////////////////////////////////////////////////////////////
- return entry != NULL ? -1 : 0;
+ int is_empty_dir( const Pathname & path_r )
+ {
+ return dirForEach( path_r,
+ [&]( const Pathname & dir_r, const char *const name_r )->bool
+ { return false; } );
}
///////////////////////////////////////////////////////////////////
{
MIL << "unlink " << path;
if ( ::unlink( path.asString().c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
{
MIL << "rename " << oldpath << " -> " << newpath;
if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
{
MIL << "exchange " << lpath << " <-> " << rpath;
if ( lpath.empty() || rpath.empty() )
- return _Log_Result( EINVAL );
+ return logResult( EINVAL );
PathInfo linfo( lpath );
PathInfo rinfo( rpath );
if ( ! linfo.isExist() )
{
if ( ! rinfo.isExist() )
- return _Log_Result( 0 ); // both don't exist.
+ return logResult( 0 ); // both don't exist.
// just rename rpath -> lpath
int ret = assert_dir( lpath.dirname() );
if ( ret != 0 )
- return _Log_Result( ret );
+ return logResult( ret );
if ( ::rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
// HERE: lpath exists:
// just rename lpath -> rpath
int ret = assert_dir( rpath.dirname() );
if ( ret != 0 )
- return _Log_Result( ret );
+ return logResult( ret );
if ( ::rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
// HERE: both exist
TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
if ( ! tmpfile )
- return _Log_Result( errno );
+ return logResult( errno );
Pathname tmp( tmpfile.path() );
::unlink( tmp.c_str() );
if ( ::rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
if ( ::rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
::rename( tmp.c_str(), lpath.c_str() );
- return _Log_Result( errno );
+ return logResult( errno );
}
if ( ::rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
::rename( lpath.c_str(), rpath.c_str() );
::rename( tmp.c_str(), lpath.c_str() );
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
PathInfo sp( file );
if ( !sp.isFile() ) {
- return _Log_Result( EINVAL );
+ return logResult( EINVAL );
}
PathInfo dp( dest );
if ( dp.isDir() ) {
- return _Log_Result( EISDIR );
+ return logResult( EISDIR );
}
const char *const argv[] = {
MIL << " " << output;
}
int ret = prog.close();
- return _Log_Result( ret, "returned" );
+ return logResult( ret, "returned" );
}
///////////////////////////////////////////////////////////////////
{
MIL << "symlink " << newpath << " -> " << oldpath;
if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
{
MIL << "hardlink " << newpath << " -> " << oldpath;
if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
{
int res = unlink( newpath );
if ( res != 0 )
- return _Log_Result( res );
+ return logResult( res );
}
// Here: no symlink, no newpath
{
switch ( errno )
{
+ case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
case EXDEV: // oldpath and newpath are not on the same mounted file system
return copy( oldpath, newpath );
break;
}
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
{
target_r = Pathname();
MIL << "readlink " << symlink_r;
- return _Log_Result( errno );
+ return logResult( errno );
}
buf[ret] = '\0';
target_r = buf;
PathInfo sp( file );
if ( !sp.isFile() ) {
- return _Log_Result( EINVAL );
+ return logResult( EINVAL );
}
PathInfo dp( dest );
if ( !dp.isDir() ) {
- return _Log_Result( ENOTDIR );
+ return logResult( ENOTDIR );
}
const char *const argv[] = {
MIL << " " << output;
}
int ret = prog.close();
- return _Log_Result( ret, "returned" );
+ return logResult( ret, "returned" );
}
///////////////////////////////////////////////////////////////////
{
MIL << "chmod " << path << ' ' << str::octstring( mode );
if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
int addmod( const Pathname & path, mode_t mode )
{
ZIP_TYPE ret = ZT_NONE;
- int fd = open( file.asString().c_str(), O_RDONLY );
+ int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
if ( fd != -1 ) {
const int magicSize = 3;
int ret = assert_dir( path.dirname() );
MIL << "assert_file " << str::octstring( mode ) << " " << path;
if ( ret != 0 )
- return _Log_Result( ret );
+ return logResult( ret );
PathInfo pi( path );
if ( pi.isExist() )
- return _Log_Result( pi.isFile() ? 0 : EEXIST );
+ return logResult( pi.isFile() ? 0 : EEXIST );
int fd = ::creat( path.c_str(), mode );
if ( fd == -1 )
- return _Log_Result( errno );
+ return logResult( errno );
::close( fd );
- return _Log_Result( 0 );
+ return logResult( 0 );
}
///////////////////////////////////////////////////////////////////
times.actime = ::time( 0 );
times.modtime = ::time( 0 );
if ( ::utime( path.asString().c_str(), × ) == -1 ) {
- return _Log_Result( errno );
+ return logResult( errno );
}
- return _Log_Result( 0 );
+ return logResult( 0 );
}
/////////////////////////////////////////////////////////////////