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 DBG << " FAILED: " << rclass << " " << res;
300 ///////////////////////////////////////////////////////////////////
302 // METHOD NAME : PathInfo::mkdir
305 int mkdir( const Pathname & path, unsigned mode )
307 DBG << "mkdir " << path << ' ' << str::octstring( mode );
308 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
309 return _Log_Result( errno );
311 return _Log_Result( 0 );
314 ///////////////////////////////////////////////////////////////////
316 // METHOD NAME : assert_dir()
319 int assert_dir( const Pathname & path, unsigned mode )
321 string::size_type pos, lastpos = 0;
322 string spath = path.asString()+"/";
335 // DBG << "about to create " << spath << endl;
336 while((pos = spath.find('/',lastpos)) != string::npos )
338 string dir = spath.substr(0,pos);
339 ret = ::mkdir(dir.c_str(), mode);
342 // ignore errors about already existing directorys
348 // DBG << "creating directory " << dir << (ret?" failed":" succeeded") << endl;
354 ///////////////////////////////////////////////////////////////////
356 // METHOD NAME : rmdir
359 int rmdir( const Pathname & path )
361 DBG << "rmdir " << path;
362 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
363 return _Log_Result( errno );
365 return _Log_Result( 0 );
368 ///////////////////////////////////////////////////////////////////
370 // METHOD NAME : recursive_rmdir
373 int recursive_rmdir( const Pathname & path )
375 DBG << "recursive_rmdir " << path << ' ';
378 if ( !p.isExist() ) {
379 return _Log_Result( 0 );
383 return _Log_Result( ENOTDIR );
388 boost::filesystem::path bp( path.asString(), boost::filesystem::native );
389 boost::filesystem::remove_all( bp );
391 catch ( boost::filesystem::filesystem_error & excpt )
393 DBG << " FAILED: " << excpt.what() << std::endl;
397 return _Log_Result( 0 );
400 ///////////////////////////////////////////////////////////////////
402 // METHOD NAME : clean_dir
405 int clean_dir( const Pathname & path )
407 DBG << "clean_dir " << path << ' ';
410 if ( !p.isExist() ) {
411 return _Log_Result( 0 );
415 return _Log_Result( ENOTDIR );
418 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
419 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
420 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
421 DBG << " " << output;
423 int ret = prog.close();
424 return _Log_Result( ret, "returned" );
427 ///////////////////////////////////////////////////////////////////
429 // METHOD NAME : copy_dir
432 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
434 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
436 PathInfo sp( srcpath );
438 return _Log_Result( ENOTDIR );
441 PathInfo dp( destpath );
443 return _Log_Result( ENOTDIR );
446 PathInfo tp( destpath + srcpath.basename() );
447 if ( tp.isExist() ) {
448 return _Log_Result( EEXIST );
452 const char *const argv[] = {
456 srcpath.asString().c_str(),
457 destpath.asString().c_str(),
460 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
461 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
462 DBG << " " << output;
464 int ret = prog.close();
465 return _Log_Result( ret, "returned" );
468 ///////////////////////////////////////////////////////////////////
470 // METHOD NAME : copy_dir_content
473 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
475 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
477 PathInfo sp( srcpath );
479 return _Log_Result( ENOTDIR );
482 PathInfo dp( destpath );
484 return _Log_Result( ENOTDIR );
487 if ( srcpath == destpath ) {
488 return _Log_Result( EEXIST );
491 std::string src( srcpath.asString());
493 const char *const argv[] = {
498 destpath.asString().c_str(),
501 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
502 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
503 DBG << " " << output;
505 int ret = prog.close();
506 return _Log_Result( ret, "returned" );
509 ///////////////////////////////////////////////////////////////////
511 // METHOD NAME : readdir
514 int readdir( std::list<std::string> & retlist,
515 const Pathname & path, bool dots )
519 DBG << "readdir " << path << ' ';
521 DIR * dir = ::opendir( path.asString().c_str() );
523 return _Log_Result( errno );
526 struct dirent *entry;
527 while ( (entry = ::readdir( dir )) != 0 ) {
529 if ( entry->d_name[0] == '.' ) {
532 if ( entry->d_name[1] == '\0'
533 || ( entry->d_name[1] == '.'
534 && entry->d_name[2] == '\0' ) )
537 retlist.push_back( entry->d_name );
542 return _Log_Result( 0 );
546 ///////////////////////////////////////////////////////////////////
548 // METHOD NAME : readdir
551 int readdir( std::list<Pathname> & retlist,
552 const Pathname & path, bool dots )
556 std::list<string> content;
557 int res = readdir( content, path, dots );
560 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
561 retlist.push_back( path + *it );
568 ///////////////////////////////////////////////////////////////////
570 // METHOD NAME : readdir
573 int readdir( DirContent & retlist, const Pathname & path,
574 bool dots, PathInfo::Mode statmode )
578 std::list<string> content;
579 int res = readdir( content, path, dots );
582 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
583 PathInfo p( path + *it, statmode );
584 retlist.push_back( DirEntry( *it, p.fileType() ) );
591 ///////////////////////////////////////////////////////////////////
593 // METHOD NAME : is_empty_dir
596 int is_empty_dir(const Pathname & path)
598 DIR * dir = ::opendir( path.asString().c_str() );
600 return _Log_Result( errno );
603 struct dirent *entry;
604 while ( (entry = ::readdir( dir )) != NULL )
606 std::string name(entry->d_name);
608 if ( name == "." || name == "..")
615 return entry != NULL ? -1 : 0;
618 ///////////////////////////////////////////////////////////////////
620 // METHOD NAME : unlink
623 int unlink( const Pathname & path )
625 DBG << "unlink " << path;
626 if ( ::unlink( path.asString().c_str() ) == -1 ) {
627 return _Log_Result( errno );
629 return _Log_Result( 0 );
632 ///////////////////////////////////////////////////////////////////
634 // METHOD NAME : rename
637 int rename( const Pathname & oldpath, const Pathname & newpath )
639 DBG << "rename " << oldpath << " -> " << newpath;
640 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
641 return _Log_Result( errno );
643 return _Log_Result( 0 );
646 ///////////////////////////////////////////////////////////////////
648 // METHOD NAME : copy
651 int copy( const Pathname & file, const Pathname & dest )
653 DBG << "copy " << file << " -> " << dest << ' ';
656 if ( !sp.isFile() ) {
657 return _Log_Result( EINVAL );
662 return _Log_Result( EISDIR );
665 const char *const argv[] = {
668 file.asString().c_str(),
669 dest.asString().c_str(),
672 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
673 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
674 DBG << " " << output;
676 int ret = prog.close();
677 return _Log_Result( ret, "returned" );
680 ///////////////////////////////////////////////////////////////////
682 // METHOD NAME : symlink
685 int symlink( const Pathname & oldpath, const Pathname & newpath )
687 DBG << "symlink " << newpath << " -> " << oldpath;
688 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
689 return _Log_Result( errno );
691 return _Log_Result( 0 );
694 ///////////////////////////////////////////////////////////////////
696 // METHOD NAME : hardlink
699 int hardlink( const Pathname & oldpath, const Pathname & newpath )
701 DBG << "hardlink " << newpath << " -> " << oldpath;
702 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
703 return _Log_Result( errno );
705 return _Log_Result( 0 );
708 ///////////////////////////////////////////////////////////////////
710 // METHOD NAME : copy_file2dir
713 int copy_file2dir( const Pathname & file, const Pathname & dest )
715 DBG << "copy_file2dir " << file << " -> " << dest << ' ';
718 if ( !sp.isFile() ) {
719 return _Log_Result( EINVAL );
724 return _Log_Result( ENOTDIR );
727 const char *const argv[] = {
730 file.asString().c_str(),
731 dest.asString().c_str(),
734 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
735 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
736 DBG << " " << output;
738 int ret = prog.close();
739 return _Log_Result( ret, "returned" );
742 ///////////////////////////////////////////////////////////////////
744 // METHOD NAME : md5sum
745 // METHOD TYPE : std::string
747 std::string md5sum( const Pathname & file )
749 if ( ! PathInfo( file ).isFile() ) {
752 std::ifstream istr( file.asString().c_str() );
756 return Digest::digest( "MD5", istr );
759 ///////////////////////////////////////////////////////////////////
761 // METHOD NAME : sha1sum
762 // METHOD TYPE : std::string
764 std::string sha1sum( const Pathname & file )
766 return checksum(file, "SHA1");
769 ///////////////////////////////////////////////////////////////////
771 // METHOD NAME : checksum
772 // METHOD TYPE : std::string
774 std::string checksum( const Pathname & file, const std::string &algorithm )
776 if ( ! PathInfo( file ).isFile() ) {
779 std::ifstream istr( file.asString().c_str() );
783 return Digest::digest( algorithm, istr );
786 bool is_checksum( const Pathname & file, const CheckSum &checksum )
788 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
791 ///////////////////////////////////////////////////////////////////
793 // METHOD NAME : erase
796 int erase( const Pathname & path )
799 PathInfo p( path, PathInfo::LSTAT );
803 res = recursive_rmdir( path );
805 res = unlink( path );
810 ///////////////////////////////////////////////////////////////////
812 // METHOD NAME : chmod
815 int chmod( const Pathname & path, mode_t mode )
817 DBG << "chmod " << path << ' ' << str::octstring( mode );
818 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
819 return _Log_Result( errno );
821 return _Log_Result( 0 );
824 ///////////////////////////////////////////////////////////////////
826 // METHOD NAME : zipType
827 // METHOD TYPE : ZIP_TYPE
829 ZIP_TYPE zipType( const Pathname & file )
831 ZIP_TYPE ret = ZT_NONE;
833 int fd = open( file.asString().c_str(), O_RDONLY );
836 const int magicSize = 3;
837 unsigned char magic[magicSize];
838 memset( magic, 0, magicSize );
839 if ( read( fd, magic, magicSize ) == magicSize ) {
840 if ( magic[0] == 0037 && magic[1] == 0213 ) {
842 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
852 ///////////////////////////////////////////////////////////////////
855 // METHOD TYPE : ByteCount
857 ByteCount df( const Pathname & path_r )
861 if ( statvfs( path_r.c_str(), &sb ) == 0 )
863 ret = sb.f_bfree * sb.f_bsize;
868 /////////////////////////////////////////////////////////////////
869 } // namespace filesystem
870 ///////////////////////////////////////////////////////////////////
871 /////////////////////////////////////////////////////////////////
873 ///////////////////////////////////////////////////////////////////