1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.cc
13 #include <sys/types.h> // for ::minor, ::major macros
14 #include <sys/statvfs.h>
20 #include <boost/filesystem/operations.hpp>
21 #include <boost/filesystem/exception.hpp>
23 #include "zypp/base/Logger.h"
24 #include "zypp/base/String.h"
25 #include "zypp/base/IOStream.h"
27 #include "zypp/ExternalProgram.h"
28 #include "zypp/PathInfo.h"
29 #include "zypp/Digest.h"
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////
39 { /////////////////////////////////////////////////////////////////
41 /******************************************************************
43 ** FUNCTION NAME : operator<<
44 ** FUNCTION TYPE : std::ostream &
46 std::ostream & operator<<( std::ostream & str, FileType obj )
49 #define EMUMOUT(T) case T: return str << #T; break
50 EMUMOUT( FT_NOT_AVAIL );
51 EMUMOUT( FT_NOT_EXIST );
54 EMUMOUT( FT_CHARDEV );
55 EMUMOUT( FT_BLOCKDEV );
64 ///////////////////////////////////////////////////////////////////
66 // METHOD NAME : StatMode::fileType
67 // METHOD TYPE : FileType
69 FileType StatMode::fileType() const
89 /******************************************************************
91 ** FUNCTION NAME : operator<<
92 ** FUNCTION TYPE : std::ostream &
94 std::ostream & operator<<( std::ostream & str, const StatMode & obj )
96 iostr::IosFmtFlagsSaver autoResoreState( str );
101 else if ( obj.isDir() )
103 else if ( obj.isLink() )
105 else if ( obj.isChr() )
107 else if ( obj.isBlk() )
109 else if ( obj.isFifo() )
111 else if ( obj.isSock() )
114 str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
118 ///////////////////////////////////////////////////////////////////
122 ///////////////////////////////////////////////////////////////////
124 ///////////////////////////////////////////////////////////////////
126 // METHOD NAME : PathInfo::PathInfo
127 // METHOD TYPE : Constructor
134 ///////////////////////////////////////////////////////////////////
136 // METHOD NAME : PathInfo::PathInfo
137 // METHOD TYPE : Constructor
139 PathInfo::PathInfo( const Pathname & path, Mode initial )
147 ///////////////////////////////////////////////////////////////////
149 // METHOD NAME : PathInfo::PathInfo
150 // METHOD TYPE : Constructor
152 PathInfo::PathInfo( const std::string & path, Mode initial )
160 ///////////////////////////////////////////////////////////////////
162 // METHOD NAME : PathInfo::PathInfo
163 // METHOD TYPE : Constructor
165 PathInfo::PathInfo( const char * path, Mode initial )
173 ///////////////////////////////////////////////////////////////////
175 // METHOD NAME : PathInfo::~PathInfo
176 // METHOD TYPE : Destructor
178 PathInfo::~PathInfo()
182 ///////////////////////////////////////////////////////////////////
184 // METHOD NAME : PathInfo::operator()
185 // METHOD TYPE : bool
187 bool PathInfo::operator()()
189 if ( path_t.empty() ) {
194 error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
197 error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
206 ///////////////////////////////////////////////////////////////////
208 // METHOD NAME : PathInfo::fileType
209 // METHOD TYPE : File_type
211 FileType PathInfo::fileType() const
214 return asStatMode().fileType();
218 ///////////////////////////////////////////////////////////////////
220 // METHOD NAME : PathInfo::userMay
221 // METHOD TYPE : mode_t
223 mode_t PathInfo::userMay() const
227 if ( owner() == getuid() ) {
228 return( uperm()/0100 );
229 } else if ( group() == getgid() ) {
230 return( gperm()/010 );
235 /******************************************************************
237 ** FUNCTION NAME : PathInfo::major
238 ** FUNCTION TYPE : unsigned int
240 unsigned int PathInfo::major() const
242 return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
245 /******************************************************************
247 ** FUNCTION NAME : PathInfo::minor
248 ** FUNCTION TYPE : unsigned int
250 unsigned int PathInfo::minor() const
252 return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
255 /******************************************************************
257 ** FUNCTION NAME : operator<<
258 ** FUNCTION TYPE : std::ostream &
260 std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
262 iostr::IosFmtFlagsSaver autoResoreState( str );
264 str << obj.asString() << "{";
265 if ( !obj.isExist() ) {
266 str << "does not exist}";
268 str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
271 str << " size " << obj.size();
279 ///////////////////////////////////////////////////////////////////
281 // filesystem utilities
283 ///////////////////////////////////////////////////////////////////
285 /******************************************************************
287 ** FUNCTION NAME : _Log_Result
288 ** FUNCTION TYPE : int
290 ** DESCRIPTION : Helper function to log return values.
292 inline int _Log_Result( const int res, const char * rclass = "errno" )
295 WAR << " FAILED: " << rclass << " " << res << std::endl;
301 ///////////////////////////////////////////////////////////////////
303 // METHOD NAME : PathInfo::mkdir
306 int mkdir( const Pathname & path, unsigned mode )
308 DBG << "mkdir " << path << ' ' << str::octstring( mode );
309 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
310 return _Log_Result( errno );
312 return _Log_Result( 0 );
315 ///////////////////////////////////////////////////////////////////
317 // METHOD NAME : assert_dir()
320 int assert_dir( const Pathname & path, unsigned mode )
322 string::size_type pos, lastpos = 0;
323 string spath = path.asString()+"/";
336 // DBG << "about to create " << spath << endl;
337 while((pos = spath.find('/',lastpos)) != string::npos )
339 string dir = spath.substr(0,pos);
340 ret = ::mkdir(dir.c_str(), mode);
343 // ignore errors about already existing directorys
349 // DBG << "creating directory " << dir << (ret?" failed":" succeeded") << endl;
355 ///////////////////////////////////////////////////////////////////
357 // METHOD NAME : rmdir
360 int rmdir( const Pathname & path )
362 DBG << "rmdir " << path;
363 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
364 return _Log_Result( errno );
366 return _Log_Result( 0 );
369 ///////////////////////////////////////////////////////////////////
371 // METHOD NAME : recursive_rmdir
374 int recursive_rmdir( const Pathname & path )
376 DBG << "recursive_rmdir " << path << ' ';
379 if ( !p.isExist() ) {
380 return _Log_Result( 0 );
384 return _Log_Result( ENOTDIR );
389 boost::filesystem::path bp( path.asString(), boost::filesystem::native );
390 boost::filesystem::remove_all( bp );
392 catch ( boost::filesystem::filesystem_error & excpt )
394 WAR << " FAILED: " << excpt.what() << std::endl;
398 return _Log_Result( 0 );
401 ///////////////////////////////////////////////////////////////////
403 // METHOD NAME : clean_dir
406 int clean_dir( const Pathname & path )
408 DBG << "clean_dir " << path << ' ';
411 if ( !p.isExist() ) {
412 return _Log_Result( 0 );
416 return _Log_Result( ENOTDIR );
419 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
420 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
421 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
422 DBG << " " << output;
424 int ret = prog.close();
425 return _Log_Result( ret, "returned" );
428 ///////////////////////////////////////////////////////////////////
430 // METHOD NAME : copy_dir
433 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
435 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
437 PathInfo sp( srcpath );
439 return _Log_Result( ENOTDIR );
442 PathInfo dp( destpath );
444 return _Log_Result( ENOTDIR );
447 PathInfo tp( destpath + srcpath.basename() );
448 if ( tp.isExist() ) {
449 return _Log_Result( EEXIST );
453 const char *const argv[] = {
457 srcpath.asString().c_str(),
458 destpath.asString().c_str(),
461 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
462 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
463 DBG << " " << output;
465 int ret = prog.close();
466 return _Log_Result( ret, "returned" );
469 ///////////////////////////////////////////////////////////////////
471 // METHOD NAME : copy_dir_content
474 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
476 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
478 PathInfo sp( srcpath );
480 return _Log_Result( ENOTDIR );
483 PathInfo dp( destpath );
485 return _Log_Result( ENOTDIR );
488 if ( srcpath == destpath ) {
489 return _Log_Result( EEXIST );
492 std::string src( srcpath.asString());
494 const char *const argv[] = {
499 destpath.asString().c_str(),
502 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
503 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
504 DBG << " " << output;
506 int ret = prog.close();
507 return _Log_Result( ret, "returned" );
510 ///////////////////////////////////////////////////////////////////
512 // METHOD NAME : readdir
515 int readdir( std::list<std::string> & retlist,
516 const Pathname & path, bool dots )
520 DBG << "readdir " << path << ' ';
522 DIR * dir = ::opendir( path.asString().c_str() );
524 return _Log_Result( errno );
527 struct dirent *entry;
528 while ( (entry = ::readdir( dir )) != 0 ) {
530 if ( entry->d_name[0] == '.' ) {
533 if ( entry->d_name[1] == '\0'
534 || ( entry->d_name[1] == '.'
535 && entry->d_name[2] == '\0' ) )
538 retlist.push_back( entry->d_name );
543 return _Log_Result( 0 );
547 ///////////////////////////////////////////////////////////////////
549 // METHOD NAME : readdir
552 int readdir( std::list<Pathname> & retlist,
553 const Pathname & path, bool dots )
557 std::list<string> content;
558 int res = readdir( content, path, dots );
561 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
562 retlist.push_back( path + *it );
569 ///////////////////////////////////////////////////////////////////
571 // METHOD NAME : readdir
574 int readdir( DirContent & retlist, const Pathname & path,
575 bool dots, PathInfo::Mode statmode )
579 std::list<string> content;
580 int res = readdir( content, path, dots );
583 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
584 PathInfo p( path + *it, statmode );
585 retlist.push_back( DirEntry( *it, p.fileType() ) );
592 ///////////////////////////////////////////////////////////////////
594 // METHOD NAME : is_empty_dir
597 int is_empty_dir(const Pathname & path)
599 DIR * dir = ::opendir( path.asString().c_str() );
601 return _Log_Result( errno );
604 struct dirent *entry;
605 while ( (entry = ::readdir( dir )) != NULL )
607 std::string name(entry->d_name);
609 if ( name == "." || name == "..")
616 return entry != NULL ? -1 : 0;
619 ///////////////////////////////////////////////////////////////////
621 // METHOD NAME : unlink
624 int unlink( const Pathname & path )
626 DBG << "unlink " << path;
627 if ( ::unlink( path.asString().c_str() ) == -1 ) {
628 return _Log_Result( errno );
630 return _Log_Result( 0 );
633 ///////////////////////////////////////////////////////////////////
635 // METHOD NAME : rename
638 int rename( const Pathname & oldpath, const Pathname & newpath )
640 DBG << "rename " << oldpath << " -> " << newpath;
641 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
642 return _Log_Result( errno );
644 return _Log_Result( 0 );
647 ///////////////////////////////////////////////////////////////////
649 // METHOD NAME : copy
652 int copy( const Pathname & file, const Pathname & dest )
654 DBG << "copy " << file << " -> " << dest << ' ';
657 if ( !sp.isFile() ) {
658 return _Log_Result( EINVAL );
663 return _Log_Result( EISDIR );
666 const char *const argv[] = {
669 file.asString().c_str(),
670 dest.asString().c_str(),
673 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
674 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
675 DBG << " " << output;
677 int ret = prog.close();
678 return _Log_Result( ret, "returned" );
681 ///////////////////////////////////////////////////////////////////
683 // METHOD NAME : symlink
686 int symlink( const Pathname & oldpath, const Pathname & newpath )
688 DBG << "symlink " << newpath << " -> " << oldpath;
689 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
690 return _Log_Result( errno );
692 return _Log_Result( 0 );
695 ///////////////////////////////////////////////////////////////////
697 // METHOD NAME : hardlink
700 int hardlink( const Pathname & oldpath, const Pathname & newpath )
702 DBG << "hardlink " << newpath << " -> " << oldpath;
703 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
704 return _Log_Result( errno );
706 return _Log_Result( 0 );
709 ///////////////////////////////////////////////////////////////////
711 // METHOD NAME : copy_file2dir
714 int copy_file2dir( const Pathname & file, const Pathname & dest )
716 DBG << "copy_file2dir " << file << " -> " << dest << ' ';
719 if ( !sp.isFile() ) {
720 return _Log_Result( EINVAL );
725 return _Log_Result( ENOTDIR );
728 const char *const argv[] = {
731 file.asString().c_str(),
732 dest.asString().c_str(),
735 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
736 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
737 DBG << " " << output;
739 int ret = prog.close();
740 return _Log_Result( ret, "returned" );
743 ///////////////////////////////////////////////////////////////////
745 // METHOD NAME : md5sum
746 // METHOD TYPE : std::string
748 std::string md5sum( const Pathname & file )
750 if ( ! PathInfo( file ).isFile() ) {
753 std::ifstream istr( file.asString().c_str() );
757 return Digest::digest( "MD5", istr );
760 ///////////////////////////////////////////////////////////////////
762 // METHOD NAME : sha1sum
763 // METHOD TYPE : std::string
765 std::string sha1sum( const Pathname & file )
767 return checksum(file, "SHA1");
770 ///////////////////////////////////////////////////////////////////
772 // METHOD NAME : checksum
773 // METHOD TYPE : std::string
775 std::string checksum( const Pathname & file, const std::string &algorithm )
777 if ( ! PathInfo( file ).isFile() ) {
780 std::ifstream istr( file.asString().c_str() );
784 return Digest::digest( algorithm, istr );
787 bool is_checksum( const Pathname & file, const CheckSum &checksum )
789 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
792 ///////////////////////////////////////////////////////////////////
794 // METHOD NAME : erase
797 int erase( const Pathname & path )
800 PathInfo p( path, PathInfo::LSTAT );
804 res = recursive_rmdir( path );
806 res = unlink( path );
811 ///////////////////////////////////////////////////////////////////
813 // METHOD NAME : chmod
816 int chmod( const Pathname & path, mode_t mode )
818 DBG << "chmod " << path << ' ' << str::octstring( mode );
819 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
820 return _Log_Result( errno );
822 return _Log_Result( 0 );
825 ///////////////////////////////////////////////////////////////////
827 // METHOD NAME : zipType
828 // METHOD TYPE : ZIP_TYPE
830 ZIP_TYPE zipType( const Pathname & file )
832 ZIP_TYPE ret = ZT_NONE;
834 int fd = open( file.asString().c_str(), O_RDONLY );
837 const int magicSize = 3;
838 unsigned char magic[magicSize];
839 memset( magic, 0, magicSize );
840 if ( read( fd, magic, magicSize ) == magicSize ) {
841 if ( magic[0] == 0037 && magic[1] == 0213 ) {
843 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
853 ///////////////////////////////////////////////////////////////////
856 // METHOD TYPE : ByteCount
858 ByteCount df( const Pathname & path_r )
862 if ( statvfs( path_r.c_str(), &sb ) == 0 )
864 ret = sb.f_bfree * sb.f_bsize;
869 ///////////////////////////////////////////////////////////////////
871 // METHOD NAME : getUmask
872 // METHOD TYPE : mode_t
876 mode_t mask = ::umask( 0022 );
881 /////////////////////////////////////////////////////////////////
882 } // namespace filesystem
883 ///////////////////////////////////////////////////////////////////
884 /////////////////////////////////////////////////////////////////
886 ///////////////////////////////////////////////////////////////////