#include <fstream>
#include <iomanip>
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/exception.hpp>
-
-#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"
+#include "zypp/TmpPath.h"
using std::endl;
using std::string;
{
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;
}
/******************************************************************
**
- ** 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;
}
+ unsigned int PathInfo::major() const
+ { INT << "Cleanup the code: This method is deprecated" << endl; return devMajor(); }
+ unsigned int PathInfo::minor() const
+ { INT << "Cleanup the code: This method is deprecated" << endl; return devMinor(); }
+
/******************************************************************
**
** FUNCTION NAME : operator<<
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 << "}";
}
///////////////////////////////////////////////////////////////////
**
** DESCRIPTION : Helper function to log return values.
*/
- inline int _Log_Result( const int res, const char * rclass = "errno" )
+#define _Log_Result MIL << endl, __Log_Result
+ inline int __Log_Result( const int res, const char * rclass = 0 /*errno*/ )
{
- MIL << endl;
if ( res )
- WAR << " FAILED: " << rclass << " " << res << endl;
+ {
+ if ( rclass )
+ WAR << " FAILED: " << rclass << " " << res << endl;
+ else
+ WAR << " FAILED: " << str::strerror( res ) << endl;
+ }
return res;
}
//
int assert_dir( const Pathname & path, unsigned mode )
{
- string::size_type pos, lastpos = 0;
- string spath = path.asString()+"/";
- int ret = 0;
-
- if(path.empty())
+ if ( path.empty() )
return ENOENT;
- // skip ./
- if(path.relative())
- lastpos=2;
- // skip /
- else
- lastpos=1;
+ { // Handle existing paths in advance.
+ PathInfo pi( path );
+ if ( pi.isDir() )
+ return 0;
+ if ( pi.isExist() )
+ return EEXIST;
+ }
+
+ string spath = path.asString()+"/";
+ string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/'
+ string::size_type pos = string::npos;
+ int ret = 0;
- // MIL << "about to create " << spath << endl;
- while((pos = spath.find('/',lastpos)) != string::npos )
+ while ( (pos = spath.find('/',lastpos)) != string::npos )
+ {
+ string dir( spath.substr(0,pos) );
+ ret = ::mkdir( dir.c_str(), mode );
+ if ( ret == -1 )
{
- string dir = spath.substr(0,pos);
- ret = ::mkdir(dir.c_str(), mode);
- if(ret == -1)
- {
- // ignore errors about already existing directorys
- if(errno == EEXIST)
- ret=0;
- else
- {
- ret=errno;
- WAR << " FAILED: mkdir " << path << ' ' << str::octstring( mode ) << " errno " << ret << endl;
- }
- }
+ if ( errno == EEXIST ) // ignore errors about already existing paths
+ ret = 0;
else
{
- MIL << "mkdir " << path << ' ' << str::octstring( mode ) << endl;
+ ret = errno;
+ WAR << " FAILED: mkdir " << dir << ' ' << str::octstring( mode ) << " errno " << ret << endl;
}
- lastpos = pos+1;
}
+ else
+ {
+ MIL << "mkdir " << dir << ' ' << str::octstring( mode ) << endl;
+ }
+ lastpos = pos+1;
+ }
+
return ret;
}
closedir( dp );
if ( ::rmdir( dir.c_str() ) < 0 )
- return _Log_Result( errno );
+ return errno;
- return _Log_Result( 0 );
+ return 0;
}
///////////////////////////////////////////////////////////////////
int recursive_rmdir( const Pathname & path )
return _Log_Result( ENOTDIR );
}
- return recursive_rmdir_1( path );
+ return _Log_Result( recursive_rmdir_1( path ) );
}
///////////////////////////////////////////////////////////////////
return _Log_Result( 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 _Log_Result( 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;
}
-
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : readdir
- // METHOD TYPE : int
- //
- int readdir( std::list<Pathname> & retlist,
- const Pathname & path, bool dots )
+ int dirForEach( const Pathname & dir_r, const StrMatcher & matcher_r, function<bool( const Pathname &, const char *const)> fnc_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 ) {
- retlist.push_back( path + *it );
- }
- }
-
- return res;
+ 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( DirContent & retlist, const Pathname & path,
- bool dots, PathInfo::Mode statmode )
- {
- 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 ) {
- PathInfo p( path + *it, statmode );
- retlist.push_back( DirEntry( *it, p.fileType() ) );
- }
- }
- 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 : is_empty_dir
- // METHOD TYPE : int
- //
- int is_empty_dir(const Pathname & path)
+ bool DirEntry::operator==( const DirEntry &rhs ) const
{
- DIR * dir = ::opendir( path.asString().c_str() );
- if ( ! dir ) {
- return _Log_Result( errno );
- }
+ // if one of the types is not known, use the name only
+ if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
+ return ( name == rhs.name );
+ return ((name == rhs.name ) && (type == rhs.type));
+ }
- struct dirent *entry;
- while ( (entry = ::readdir( dir )) != NULL )
- {
- std::string name(entry->d_name);
+ int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_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( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
+ return true;
+ } );
+ }
- 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; } );
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//
+ // METHOD NAME : exchange
+ // METHOD TYPE : int
+ //
+ int exchange( const Pathname & lpath, const Pathname & rpath )
+ {
+ MIL << "exchange " << lpath << " <-> " << rpath;
+ if ( lpath.empty() || rpath.empty() )
+ return _Log_Result( EINVAL );
+
+ PathInfo linfo( lpath );
+ PathInfo rinfo( rpath );
+
+ if ( ! linfo.isExist() )
+ {
+ if ( ! rinfo.isExist() )
+ return _Log_Result( 0 ); // both don't exist.
+
+ // just rename rpath -> lpath
+ int ret = assert_dir( lpath.dirname() );
+ if ( ret != 0 )
+ return _Log_Result( ret );
+ if ( ::rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
+ return _Log_Result( errno );
+ }
+ return _Log_Result( 0 );
+ }
+
+ // HERE: lpath exists:
+ if ( ! rinfo.isExist() )
+ {
+ // just rename lpath -> rpath
+ int ret = assert_dir( rpath.dirname() );
+ if ( ret != 0 )
+ return _Log_Result( ret );
+ if ( ::rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
+ return _Log_Result( errno );
+ }
+ return _Log_Result( 0 );
+ }
+
+ // HERE: both exist
+ TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
+ if ( ! tmpfile )
+ return _Log_Result( errno );
+ Pathname tmp( tmpfile.path() );
+ ::unlink( tmp.c_str() );
+
+ if ( ::rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
+ return _Log_Result( errno );
+ }
+ if ( ::rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
+ ::rename( tmp.c_str(), lpath.c_str() );
+ return _Log_Result( 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 _Log_Result( 0 );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ //
// METHOD NAME : copy
// METHOD TYPE : int
//
const char *const argv[] = {
"/bin/cp",
+ "--remove-destination",
"--",
file.asString().c_str(),
dest.asString().c_str(),
///////////////////////////////////////////////////////////////////
//
+ // METHOD NAME : hardlink
+ // METHOD TYPE : int
+ //
+ int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath )
+ {
+ MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
+
+ PathInfo pi( oldpath, PathInfo::LSTAT );
+ if ( pi.isLink() )
+ {
+ // dont hardlink symlinks!
+ return copy( oldpath, newpath );
+ }
+
+ pi.lstat( newpath );
+ if ( pi.isExist() )
+ {
+ int res = unlink( newpath );
+ if ( res != 0 )
+ return _Log_Result( res );
+ }
+
+ // Here: no symlink, no newpath
+ if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
+ {
+ 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 _Log_Result( 0 );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ //
// METHOD NAME : readlink
// METHOD TYPE : int
//
return _Log_Result( 0 );
}
- ///////////////////////////////////////////////////////////////////
+ int addmod( const Pathname & path, mode_t mode )
+ {
+ mode_t omode( PathInfo( path ).st_mode() );
+ mode_t tmode( omode | mode );
+ if ( omode != mode )
+ return chmod( path, tmode );
+ return 0;
+ }
+
+ int delmod( const Pathname & path, mode_t mode )
+ {
+ mode_t omode( PathInfo( path ).st_mode() );
+ mode_t tmode( omode & ~mode );
+ if ( omode != mode )
+ return chmod( path, tmode );
+ return 0;
+ }
+
+ //////////////////////////////////////////////////////////////////
//
// METHOD NAME : zipType
// METHOD TYPE : ZIP_TYPE
{
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;
///////////////////////////////////////////////////////////////////
//
+ // METHOD NAME : getUmask
+ // METHOD TYPE : mode_t
+ //
+ int assert_file( const Pathname & path, unsigned mode )
+ {
+ int ret = assert_dir( path.dirname() );
+ MIL << "assert_file " << str::octstring( mode ) << " " << path;
+ if ( ret != 0 )
+ return _Log_Result( ret );
+
+ PathInfo pi( path );
+ if ( pi.isExist() )
+ return _Log_Result( pi.isFile() ? 0 : EEXIST );
+
+ int fd = ::creat( path.c_str(), mode );
+ if ( fd == -1 )
+ return _Log_Result( errno );
+
+ ::close( fd );
+ return _Log_Result( 0 );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ //
// METHOD NAME : touch
// METHOD TYPE : int
//