1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.cc
13 #include <sys/types.h> // for ::minor, ::major macros
19 #include <boost/filesystem/operations.hpp>
20 #include <boost/filesystem/exception.hpp>
22 #include "zypp/base/Logger.h"
23 #include "zypp/base/String.h"
24 #include "zypp/base/IOStream.h"
26 #include "zypp/ExternalProgram.h"
27 #include "zypp/PathInfo.h"
28 #include "zypp/Digest.h"
33 ///////////////////////////////////////////////////////////////////
35 { /////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////
38 { /////////////////////////////////////////////////////////////////
40 /******************************************************************
42 ** FUNCTION NAME : operator<<
43 ** FUNCTION TYPE : std::ostream &
45 std::ostream & operator<<( std::ostream & str, FileType obj )
48 #define EMUMOUT(T) case T: return str << #T; break
49 EMUMOUT( FT_NOT_AVAIL );
50 EMUMOUT( FT_NOT_EXIST );
53 EMUMOUT( FT_CHARDEV );
54 EMUMOUT( FT_BLOCKDEV );
63 ///////////////////////////////////////////////////////////////////
65 // METHOD NAME : StatMode::fileType
66 // METHOD TYPE : FileType
68 FileType StatMode::fileType() const
88 /******************************************************************
90 ** FUNCTION NAME : operator<<
91 ** FUNCTION TYPE : std::ostream &
93 std::ostream & operator<<( std::ostream & str, const StatMode & obj )
95 iostr::IosFmtFlagsSaver autoResoreState( str );
100 else if ( obj.isDir() )
102 else if ( obj.isLink() )
104 else if ( obj.isChr() )
106 else if ( obj.isBlk() )
108 else if ( obj.isFifo() )
110 else if ( obj.isSock() )
113 str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
117 ///////////////////////////////////////////////////////////////////
121 ///////////////////////////////////////////////////////////////////
123 ///////////////////////////////////////////////////////////////////
125 // METHOD NAME : PathInfo::PathInfo
126 // METHOD TYPE : Constructor
133 ///////////////////////////////////////////////////////////////////
135 // METHOD NAME : PathInfo::PathInfo
136 // METHOD TYPE : Constructor
138 PathInfo::PathInfo( const Pathname & path, Mode initial )
146 ///////////////////////////////////////////////////////////////////
148 // METHOD NAME : PathInfo::PathInfo
149 // METHOD TYPE : Constructor
151 PathInfo::PathInfo( const std::string & path, Mode initial )
159 ///////////////////////////////////////////////////////////////////
161 // METHOD NAME : PathInfo::PathInfo
162 // METHOD TYPE : Constructor
164 PathInfo::PathInfo( const char * path, Mode initial )
172 ///////////////////////////////////////////////////////////////////
174 // METHOD NAME : PathInfo::~PathInfo
175 // METHOD TYPE : Destructor
177 PathInfo::~PathInfo()
181 ///////////////////////////////////////////////////////////////////
183 // METHOD NAME : PathInfo::operator()
184 // METHOD TYPE : bool
186 bool PathInfo::operator()()
188 if ( path_t.empty() ) {
193 error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
196 error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
205 ///////////////////////////////////////////////////////////////////
207 // METHOD NAME : PathInfo::fileType
208 // METHOD TYPE : File_type
210 FileType PathInfo::fileType() const
213 return asStatMode().fileType();
217 ///////////////////////////////////////////////////////////////////
219 // METHOD NAME : PathInfo::userMay
220 // METHOD TYPE : mode_t
222 mode_t PathInfo::userMay() const
226 if ( owner() == getuid() ) {
227 return( uperm()/0100 );
228 } else if ( group() == getgid() ) {
229 return( gperm()/010 );
234 /******************************************************************
236 ** FUNCTION NAME : PathInfo::major
237 ** FUNCTION TYPE : unsigned int
239 unsigned int PathInfo::major() const
241 return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
244 /******************************************************************
246 ** FUNCTION NAME : PathInfo::minor
247 ** FUNCTION TYPE : unsigned int
249 unsigned int PathInfo::minor() const
251 return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
254 /******************************************************************
256 ** FUNCTION NAME : operator<<
257 ** FUNCTION TYPE : std::ostream &
259 std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
261 iostr::IosFmtFlagsSaver autoResoreState( str );
263 str << obj.asString() << "{";
264 if ( !obj.isExist() ) {
265 str << "does not exist}";
267 str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
270 str << " size " << obj.size();
278 ///////////////////////////////////////////////////////////////////
280 // filesystem utilities
282 ///////////////////////////////////////////////////////////////////
284 /******************************************************************
286 ** FUNCTION NAME : _Log_Result
287 ** FUNCTION TYPE : int
289 ** DESCRIPTION : Helper function to log return values.
291 inline int _Log_Result( const int res, const char * rclass = "errno" )
294 DBG << " FAILED: " << rclass << " " << res;
299 ///////////////////////////////////////////////////////////////////
301 // METHOD NAME : PathInfo::mkdir
304 int mkdir( const Pathname & path, unsigned mode )
306 DBG << "mkdir " << path << ' ' << str::octstring( mode );
307 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
308 return _Log_Result( errno );
310 return _Log_Result( 0 );
313 ///////////////////////////////////////////////////////////////////
315 // METHOD NAME : assert_dir()
318 int assert_dir( const Pathname & path, unsigned mode )
320 string::size_type pos, lastpos = 0;
321 string spath = path.asString()+"/";
334 // DBG << "about to create " << spath << endl;
335 while((pos = spath.find('/',lastpos)) != string::npos )
337 string dir = spath.substr(0,pos);
338 ret = ::mkdir(dir.c_str(), mode);
341 // ignore errors about already existing directorys
347 // DBG << "creating directory " << dir << (ret?" failed":" succeeded") << endl;
353 ///////////////////////////////////////////////////////////////////
355 // METHOD NAME : rmdir
358 int rmdir( const Pathname & path )
360 DBG << "rmdir " << path;
361 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
362 return _Log_Result( errno );
364 return _Log_Result( 0 );
367 ///////////////////////////////////////////////////////////////////
369 // METHOD NAME : recursive_rmdir
372 int recursive_rmdir( const Pathname & path )
374 DBG << "recursive_rmdir " << path << ' ';
377 if ( !p.isExist() ) {
378 return _Log_Result( 0 );
382 return _Log_Result( ENOTDIR );
387 boost::filesystem::path bp( path.asString(), boost::filesystem::native );
388 boost::filesystem::remove_all( bp );
390 catch ( boost::filesystem::filesystem_error & excpt )
392 DBG << " FAILED: " << excpt.what() << std::endl;
396 return _Log_Result( 0 );
399 ///////////////////////////////////////////////////////////////////
401 // METHOD NAME : clean_dir
404 int clean_dir( const Pathname & path )
406 DBG << "clean_dir " << path << ' ';
409 if ( !p.isExist() ) {
410 return _Log_Result( 0 );
414 return _Log_Result( ENOTDIR );
417 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
418 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
419 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
420 DBG << " " << output;
422 int ret = prog.close();
423 return _Log_Result( ret, "returned" );
426 ///////////////////////////////////////////////////////////////////
428 // METHOD NAME : copy_dir
431 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
433 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
435 PathInfo sp( srcpath );
437 return _Log_Result( ENOTDIR );
440 PathInfo dp( destpath );
442 return _Log_Result( ENOTDIR );
445 PathInfo tp( destpath + srcpath.basename() );
446 if ( tp.isExist() ) {
447 return _Log_Result( EEXIST );
451 const char *const argv[] = {
455 srcpath.asString().c_str(),
456 destpath.asString().c_str(),
459 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
460 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
461 DBG << " " << output;
463 int ret = prog.close();
464 return _Log_Result( ret, "returned" );
467 ///////////////////////////////////////////////////////////////////
469 // METHOD NAME : copy_dir_content
472 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
474 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
476 PathInfo sp( srcpath );
478 return _Log_Result( ENOTDIR );
481 PathInfo dp( destpath );
483 return _Log_Result( ENOTDIR );
486 if ( srcpath == destpath ) {
487 return _Log_Result( EEXIST );
490 std::string src( srcpath.asString());
492 const char *const argv[] = {
497 destpath.asString().c_str(),
500 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
501 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
502 DBG << " " << output;
504 int ret = prog.close();
505 return _Log_Result( ret, "returned" );
508 ///////////////////////////////////////////////////////////////////
510 // METHOD NAME : readdir
513 int readdir( std::list<std::string> & retlist,
514 const Pathname & path, bool dots )
518 DBG << "readdir " << path << ' ';
520 DIR * dir = ::opendir( path.asString().c_str() );
522 return _Log_Result( errno );
525 struct dirent *entry;
526 while ( (entry = ::readdir( dir )) != 0 ) {
528 if ( entry->d_name[0] == '.' ) {
531 if ( entry->d_name[1] == '\0'
532 || ( entry->d_name[1] == '.'
533 && entry->d_name[2] == '\0' ) )
536 retlist.push_back( entry->d_name );
541 return _Log_Result( 0 );
545 ///////////////////////////////////////////////////////////////////
547 // METHOD NAME : readdir
550 int readdir( std::list<Pathname> & retlist,
551 const Pathname & path, bool dots )
555 std::list<string> content;
556 int res = readdir( content, path, dots );
559 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
560 retlist.push_back( path + *it );
567 ///////////////////////////////////////////////////////////////////
569 // METHOD NAME : readdir
572 int readdir( DirContent & retlist, const Pathname & path,
573 bool dots, PathInfo::Mode statmode )
577 std::list<string> content;
578 int res = readdir( content, path, dots );
581 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
582 PathInfo p( path + *it, statmode );
583 retlist.push_back( DirEntry( *it, p.fileType() ) );
590 ///////////////////////////////////////////////////////////////////
592 // METHOD NAME : is_empty_dir
595 int is_empty_dir(const Pathname & path)
597 DIR * dir = ::opendir( path.asString().c_str() );
599 return _Log_Result( errno );
602 struct dirent *entry;
603 while ( (entry = ::readdir( dir )) != NULL )
605 std::string name(entry->d_name);
607 if ( name == "." || name == "..")
614 return entry != NULL ? -1 : 0;
617 ///////////////////////////////////////////////////////////////////
619 // METHOD NAME : unlink
622 int unlink( const Pathname & path )
624 DBG << "unlink " << path;
625 if ( ::unlink( path.asString().c_str() ) == -1 ) {
626 return _Log_Result( errno );
628 return _Log_Result( 0 );
631 ///////////////////////////////////////////////////////////////////
633 // METHOD NAME : rename
636 int rename( const Pathname & oldpath, const Pathname & newpath )
638 DBG << "rename " << oldpath << " -> " << newpath;
639 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
640 return _Log_Result( errno );
642 return _Log_Result( 0 );
645 ///////////////////////////////////////////////////////////////////
647 // METHOD NAME : copy
650 int copy( const Pathname & file, const Pathname & dest )
652 DBG << "copy " << file << " -> " << dest << ' ';
655 if ( !sp.isFile() ) {
656 return _Log_Result( EINVAL );
661 return _Log_Result( EISDIR );
664 const char *const argv[] = {
667 file.asString().c_str(),
668 dest.asString().c_str(),
671 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
672 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
673 DBG << " " << output;
675 int ret = prog.close();
676 return _Log_Result( ret, "returned" );
679 ///////////////////////////////////////////////////////////////////
681 // METHOD NAME : symlink
684 int symlink( const Pathname & oldpath, const Pathname & newpath )
686 DBG << "symlink " << newpath << " -> " << oldpath;
687 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
688 return _Log_Result( errno );
690 return _Log_Result( 0 );
693 ///////////////////////////////////////////////////////////////////
695 // METHOD NAME : hardlink
698 int hardlink( const Pathname & oldpath, const Pathname & newpath )
700 DBG << "hardlink " << newpath << " -> " << oldpath;
701 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
702 return _Log_Result( errno );
704 return _Log_Result( 0 );
707 ///////////////////////////////////////////////////////////////////
709 // METHOD NAME : copy_file2dir
712 int copy_file2dir( const Pathname & file, const Pathname & dest )
714 DBG << "copy_file2dir " << file << " -> " << dest << ' ';
717 if ( !sp.isFile() ) {
718 return _Log_Result( EINVAL );
723 return _Log_Result( ENOTDIR );
726 const char *const argv[] = {
729 file.asString().c_str(),
730 dest.asString().c_str(),
733 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
734 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
735 DBG << " " << output;
737 int ret = prog.close();
738 return _Log_Result( ret, "returned" );
741 ///////////////////////////////////////////////////////////////////
743 // METHOD NAME : md5sum
744 // METHOD TYPE : std::string
746 std::string md5sum( const Pathname & file )
748 if ( ! PathInfo( file ).isFile() ) {
751 std::ifstream istr( file.asString().c_str() );
755 return Digest::digest( "MD5", istr );
758 ///////////////////////////////////////////////////////////////////
760 // METHOD NAME : sha1sum
761 // METHOD TYPE : std::string
763 std::string sha1sum( const Pathname & file )
765 if ( ! PathInfo( file ).isFile() ) {
768 std::ifstream istr( file.asString().c_str() );
772 return Digest::digest( "SHA1", istr );
775 ///////////////////////////////////////////////////////////////////
777 // METHOD NAME : erase
780 int erase( const Pathname & path )
783 PathInfo p( path, PathInfo::LSTAT );
787 res = recursive_rmdir( path );
789 res = unlink( path );
794 ///////////////////////////////////////////////////////////////////
796 // METHOD NAME : chmod
799 int chmod( const Pathname & path, mode_t mode )
801 DBG << "chmod " << path << ' ' << str::octstring( mode );
802 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
803 return _Log_Result( errno );
805 return _Log_Result( 0 );
808 ///////////////////////////////////////////////////////////////////
810 // METHOD NAME : zipType
811 // METHOD TYPE : ZIP_TYPE
813 ZIP_TYPE zipType( const Pathname & file )
815 ZIP_TYPE ret = ZT_NONE;
817 int fd = open( file.asString().c_str(), O_RDONLY );
820 const int magicSize = 3;
821 unsigned char magic[magicSize];
822 memset( magic, 0, magicSize );
823 if ( read( fd, magic, magicSize ) == magicSize ) {
824 if ( magic[0] == 0037 && magic[1] == 0213 ) {
826 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
836 /////////////////////////////////////////////////////////////////
837 } // namespace filesystem
838 ///////////////////////////////////////////////////////////////////
839 /////////////////////////////////////////////////////////////////
841 ///////////////////////////////////////////////////////////////////