1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.cc
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/String.h"
19 #include "zypp/base/IOStream.h"
21 #include "zypp/ExternalProgram.h"
22 #include "zypp/PathInfo.h"
23 #include "zypp/Digest.h"
25 #include <sys/types.h> // for ::minor, ::major macros
29 ///////////////////////////////////////////////////////////////////
31 { /////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
36 /******************************************************************
38 ** FUNCTION NAME : operator<<
39 ** FUNCTION TYPE : std::ostream &
41 std::ostream & operator<<( std::ostream & str, FileType obj )
44 #define EMUMOUT(T) case T: return str << #T; break
45 EMUMOUT( FT_NOT_AVAIL );
46 EMUMOUT( FT_NOT_EXIST );
49 EMUMOUT( FT_CHARDEV );
50 EMUMOUT( FT_BLOCKDEV );
59 ///////////////////////////////////////////////////////////////////
61 // METHOD NAME : StatMode::fileType
62 // METHOD TYPE : FileType
64 FileType StatMode::fileType() const
84 /******************************************************************
86 ** FUNCTION NAME : operator<<
87 ** FUNCTION TYPE : std::ostream &
89 std::ostream & operator<<( std::ostream & str, const StatMode & obj )
91 iostr::IosFmtFlagsSaver autoResoreState( str );
96 else if ( obj.isDir() )
98 else if ( obj.isLink() )
100 else if ( obj.isChr() )
102 else if ( obj.isBlk() )
104 else if ( obj.isFifo() )
106 else if ( obj.isSock() )
109 str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
113 ///////////////////////////////////////////////////////////////////
117 ///////////////////////////////////////////////////////////////////
119 ///////////////////////////////////////////////////////////////////
121 // METHOD NAME : PathInfo::PathInfo
122 // METHOD TYPE : Constructor
129 ///////////////////////////////////////////////////////////////////
131 // METHOD NAME : PathInfo::PathInfo
132 // METHOD TYPE : Constructor
134 PathInfo::PathInfo( const Pathname & path, Mode initial )
142 ///////////////////////////////////////////////////////////////////
144 // METHOD NAME : PathInfo::PathInfo
145 // METHOD TYPE : Constructor
147 PathInfo::PathInfo( const std::string & path, Mode initial )
155 ///////////////////////////////////////////////////////////////////
157 // METHOD NAME : PathInfo::PathInfo
158 // METHOD TYPE : Constructor
160 PathInfo::PathInfo( const char * path, Mode initial )
168 ///////////////////////////////////////////////////////////////////
170 // METHOD NAME : PathInfo::~PathInfo
171 // METHOD TYPE : Destructor
173 PathInfo::~PathInfo()
177 ///////////////////////////////////////////////////////////////////
179 // METHOD NAME : PathInfo::operator()
180 // METHOD TYPE : bool
182 bool PathInfo::operator()()
184 if ( path_t.empty() ) {
189 error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
192 error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
201 ///////////////////////////////////////////////////////////////////
203 // METHOD NAME : PathInfo::fileType
204 // METHOD TYPE : File_type
206 FileType PathInfo::fileType() const
209 return asStatMode().fileType();
213 ///////////////////////////////////////////////////////////////////
215 // METHOD NAME : PathInfo::userMay
216 // METHOD TYPE : mode_t
218 mode_t PathInfo::userMay() const
222 if ( owner() == getuid() ) {
223 return( uperm()/0100 );
224 } else if ( group() == getgid() ) {
225 return( gperm()/010 );
230 /******************************************************************
232 ** FUNCTION NAME : PathInfo::major
233 ** FUNCTION TYPE : unsigned int
235 unsigned int PathInfo::major() const
237 return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
240 /******************************************************************
242 ** FUNCTION NAME : PathInfo::minor
243 ** FUNCTION TYPE : unsigned int
245 unsigned int PathInfo::minor() const
247 return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
250 /******************************************************************
252 ** FUNCTION NAME : operator<<
253 ** FUNCTION TYPE : std::ostream &
255 std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
257 iostr::IosFmtFlagsSaver autoResoreState( str );
259 str << obj.asString() << "{";
260 if ( !obj.isExist() ) {
261 str << "does not exist}";
263 str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
266 str << " size " << obj.size();
274 ///////////////////////////////////////////////////////////////////
276 // filesystem utilities
278 ///////////////////////////////////////////////////////////////////
280 /******************************************************************
282 ** FUNCTION NAME : _Log_Result
283 ** FUNCTION TYPE : int
285 ** DESCRIPTION : Helper function to log return values.
287 inline int _Log_Result( const int res, const char * rclass = "errno" )
290 DBG << " FAILED: " << rclass << " " << res;
295 ///////////////////////////////////////////////////////////////////
297 // METHOD NAME : PathInfo::mkdir
300 int mkdir( const Pathname & path, unsigned mode )
302 DBG << "mkdir " << path << ' ' << str::octstring( mode );
303 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
304 return _Log_Result( errno );
306 return _Log_Result( 0 );
309 ///////////////////////////////////////////////////////////////////
311 // METHOD NAME : assert_dir()
314 int assert_dir( const Pathname & path, unsigned mode )
316 string::size_type pos, lastpos = 0;
317 string spath = path.asString()+"/";
330 // DBG << "about to create " << spath << endl;
331 while((pos = spath.find('/',lastpos)) != string::npos )
333 string dir = spath.substr(0,pos);
334 ret = ::mkdir(dir.c_str(), mode);
337 // ignore errors about already existing directorys
343 // DBG << "creating directory " << dir << (ret?" failed":" succeeded") << endl;
349 ///////////////////////////////////////////////////////////////////
351 // METHOD NAME : rmdir
354 int rmdir( const Pathname & path )
356 DBG << "rmdir " << path;
357 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
358 return _Log_Result( errno );
360 return _Log_Result( 0 );
363 ///////////////////////////////////////////////////////////////////
365 // METHOD NAME : recursive_rmdir
368 int recursive_rmdir( const Pathname & path )
370 DBG << "recursive_rmdir " << path << ' ';
373 if ( !p.isExist() ) {
374 return _Log_Result( 0 );
378 return _Log_Result( ENOTDIR );
381 const char *const argv[] = {
386 path.asString().c_str(),
390 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
391 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
392 DBG << " " << output;
394 int ret = prog.close();
395 return _Log_Result( ret, "returned" );
398 ///////////////////////////////////////////////////////////////////
400 // METHOD NAME : clean_dir
403 int clean_dir( const Pathname & path )
405 DBG << "clean_dir " << path << ' ';
408 if ( !p.isExist() ) {
409 return _Log_Result( 0 );
413 return _Log_Result( ENOTDIR );
416 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
417 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
418 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
419 DBG << " " << output;
421 int ret = prog.close();
422 return _Log_Result( ret, "returned" );
425 ///////////////////////////////////////////////////////////////////
427 // METHOD NAME : copy_dir
430 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
432 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
434 PathInfo sp( srcpath );
436 return _Log_Result( ENOTDIR );
439 PathInfo dp( destpath );
441 return _Log_Result( ENOTDIR );
444 PathInfo tp( destpath + srcpath.basename() );
445 if ( tp.isExist() ) {
446 return _Log_Result( EEXIST );
450 const char *const argv[] = {
454 srcpath.asString().c_str(),
455 destpath.asString().c_str(),
458 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
459 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
460 DBG << " " << output;
462 int ret = prog.close();
463 return _Log_Result( ret, "returned" );
466 ///////////////////////////////////////////////////////////////////
468 // METHOD NAME : copy_dir_content
471 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
473 DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
475 PathInfo sp( srcpath );
477 return _Log_Result( ENOTDIR );
480 PathInfo dp( destpath );
482 return _Log_Result( ENOTDIR );
485 if ( srcpath == destpath ) {
486 return _Log_Result( EEXIST );
489 std::string src( srcpath.asString());
491 const char *const argv[] = {
496 destpath.asString().c_str(),
499 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
500 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
501 DBG << " " << output;
503 int ret = prog.close();
504 return _Log_Result( ret, "returned" );
507 ///////////////////////////////////////////////////////////////////
509 // METHOD NAME : readdir
512 int readdir( std::list<std::string> & retlist,
513 const Pathname & path, bool dots )
517 DBG << "readdir " << path << ' ';
519 DIR * dir = ::opendir( path.asString().c_str() );
521 return _Log_Result( errno );
524 struct dirent *entry;
525 while ( (entry = ::readdir( dir )) != 0 ) {
527 if ( entry->d_name[0] == '.' ) {
530 if ( entry->d_name[1] == '\0'
531 || ( entry->d_name[1] == '.'
532 && entry->d_name[2] == '\0' ) )
535 retlist.push_back( entry->d_name );
540 return _Log_Result( 0 );
544 ///////////////////////////////////////////////////////////////////
546 // METHOD NAME : readdir
549 int readdir( std::list<Pathname> & retlist,
550 const Pathname & path, bool dots )
554 std::list<string> content;
555 int res = readdir( content, path, dots );
558 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
559 retlist.push_back( path + *it );
566 ///////////////////////////////////////////////////////////////////
568 // METHOD NAME : readdir
571 int readdir( DirContent & retlist, const Pathname & path,
572 bool dots, PathInfo::Mode statmode )
576 std::list<string> content;
577 int res = readdir( content, path, dots );
580 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
581 PathInfo p( path + *it, statmode );
582 retlist.push_back( DirEntry( *it, p.fileType() ) );
589 ///////////////////////////////////////////////////////////////////
591 // METHOD NAME : is_empty_dir
594 int is_empty_dir(const Pathname & path)
596 DIR * dir = ::opendir( path.asString().c_str() );
598 return _Log_Result( errno );
601 struct dirent *entry;
602 while ( (entry = ::readdir( dir )) != NULL )
604 std::string name(entry->d_name);
606 if ( name == "." || name == "..")
613 return entry != NULL ? -1 : 0;
616 ///////////////////////////////////////////////////////////////////
618 // METHOD NAME : unlink
621 int unlink( const Pathname & path )
623 DBG << "unlink " << path;
624 if ( ::unlink( path.asString().c_str() ) == -1 ) {
625 return _Log_Result( errno );
627 return _Log_Result( 0 );
630 ///////////////////////////////////////////////////////////////////
632 // METHOD NAME : rename
635 int rename( const Pathname & oldpath, const Pathname & newpath )
637 DBG << "rename " << oldpath << " -> " << newpath;
638 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
639 return _Log_Result( errno );
641 return _Log_Result( 0 );
644 ///////////////////////////////////////////////////////////////////
646 // METHOD NAME : copy
649 int copy( const Pathname & file, const Pathname & dest )
651 DBG << "copy " << file << " -> " << dest << ' ';
654 if ( !sp.isFile() ) {
655 return _Log_Result( EINVAL );
660 return _Log_Result( EISDIR );
663 const char *const argv[] = {
666 file.asString().c_str(),
667 dest.asString().c_str(),
670 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
671 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
672 DBG << " " << output;
674 int ret = prog.close();
675 return _Log_Result( ret, "returned" );
678 ///////////////////////////////////////////////////////////////////
680 // METHOD NAME : symlink
683 int symlink( const Pathname & oldpath, const Pathname & newpath )
685 DBG << "symlink " << newpath << " -> " << oldpath;
686 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
687 return _Log_Result( errno );
689 return _Log_Result( 0 );
692 ///////////////////////////////////////////////////////////////////
694 // METHOD NAME : hardlink
697 int hardlink( const Pathname & oldpath, const Pathname & newpath )
699 DBG << "hardlink " << newpath << " -> " << oldpath;
700 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
701 return _Log_Result( errno );
703 return _Log_Result( 0 );
706 ///////////////////////////////////////////////////////////////////
708 // METHOD NAME : copy_file2dir
711 int copy_file2dir( const Pathname & file, const Pathname & dest )
713 DBG << "copy_file2dir " << file << " -> " << dest << ' ';
716 if ( !sp.isFile() ) {
717 return _Log_Result( EINVAL );
722 return _Log_Result( ENOTDIR );
725 const char *const argv[] = {
728 file.asString().c_str(),
729 dest.asString().c_str(),
732 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
733 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
734 DBG << " " << output;
736 int ret = prog.close();
737 return _Log_Result( ret, "returned" );
740 ///////////////////////////////////////////////////////////////////
742 // METHOD NAME : md5sum
743 // METHOD TYPE : std::string
745 std::string md5sum( const Pathname & file )
747 if ( ! PathInfo( file ).isFile() ) {
750 std::ifstream istr( file.asString().c_str() );
754 return Digest::digest( "MD5", istr );
757 ///////////////////////////////////////////////////////////////////
759 // METHOD NAME : sha1sum
760 // METHOD TYPE : std::string
762 std::string sha1sum( const Pathname & file )
764 if ( ! PathInfo( file ).isFile() ) {
767 std::ifstream istr( file.asString().c_str() );
771 return Digest::digest( "SHA1", istr );
774 ///////////////////////////////////////////////////////////////////
776 // METHOD NAME : erase
779 int erase( const Pathname & path )
782 PathInfo p( path, PathInfo::LSTAT );
786 res = recursive_rmdir( path );
788 res = unlink( path );
793 ///////////////////////////////////////////////////////////////////
795 // METHOD NAME : chmod
798 int chmod( const Pathname & path, mode_t mode )
800 DBG << "chmod " << path << ' ' << str::octstring( mode );
801 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
802 return _Log_Result( errno );
804 return _Log_Result( 0 );
807 ///////////////////////////////////////////////////////////////////
809 // METHOD NAME : zipType
810 // METHOD TYPE : ZIP_TYPE
812 ZIP_TYPE zipType( const Pathname & file )
814 ZIP_TYPE ret = ZT_NONE;
816 int fd = open( file.asString().c_str(), O_RDONLY );
819 const int magicSize = 3;
820 unsigned char magic[magicSize];
821 memset( magic, 0, magicSize );
822 if ( read( fd, magic, magicSize ) == magicSize ) {
823 if ( magic[0] == 0037 && magic[1] == 0213 ) {
825 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
835 /////////////////////////////////////////////////////////////////
836 } // namespace filesystem
837 ///////////////////////////////////////////////////////////////////
838 /////////////////////////////////////////////////////////////////
840 ///////////////////////////////////////////////////////////////////