1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.cc
13 #include <sys/types.h> // for ::minor, ::major macros
14 #include <utime.h> // for ::utime
15 #include <sys/statvfs.h>
21 #include <boost/filesystem/operations.hpp>
22 #include <boost/filesystem/exception.hpp>
24 #include "zypp/base/Logger.h"
25 #include "zypp/base/String.h"
26 #include "zypp/base/IOStream.h"
28 #include "zypp/ExternalProgram.h"
29 #include "zypp/PathInfo.h"
30 #include "zypp/Digest.h"
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////
40 { /////////////////////////////////////////////////////////////////
42 /******************************************************************
44 ** FUNCTION NAME : operator<<
45 ** FUNCTION TYPE : std::ostream &
47 std::ostream & operator<<( std::ostream & str, FileType obj )
50 #define EMUMOUT(T) case T: return str << #T; break
51 EMUMOUT( FT_NOT_AVAIL );
52 EMUMOUT( FT_NOT_EXIST );
55 EMUMOUT( FT_CHARDEV );
56 EMUMOUT( FT_BLOCKDEV );
65 ///////////////////////////////////////////////////////////////////
67 // METHOD NAME : StatMode::fileType
68 // METHOD TYPE : FileType
70 FileType StatMode::fileType() const
90 /******************************************************************
92 ** FUNCTION NAME : operator<<
93 ** FUNCTION TYPE : std::ostream &
95 std::ostream & operator<<( std::ostream & str, const StatMode & obj )
97 iostr::IosFmtFlagsSaver autoResoreState( str );
102 else if ( obj.isDir() )
104 else if ( obj.isLink() )
106 else if ( obj.isChr() )
108 else if ( obj.isBlk() )
110 else if ( obj.isFifo() )
112 else if ( obj.isSock() )
115 str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
119 ///////////////////////////////////////////////////////////////////
123 ///////////////////////////////////////////////////////////////////
125 ///////////////////////////////////////////////////////////////////
127 // METHOD NAME : PathInfo::PathInfo
128 // METHOD TYPE : Constructor
135 ///////////////////////////////////////////////////////////////////
137 // METHOD NAME : PathInfo::PathInfo
138 // METHOD TYPE : Constructor
140 PathInfo::PathInfo( const Pathname & path, Mode initial )
148 ///////////////////////////////////////////////////////////////////
150 // METHOD NAME : PathInfo::PathInfo
151 // METHOD TYPE : Constructor
153 PathInfo::PathInfo( const std::string & path, Mode initial )
161 ///////////////////////////////////////////////////////////////////
163 // METHOD NAME : PathInfo::PathInfo
164 // METHOD TYPE : Constructor
166 PathInfo::PathInfo( const char * path, Mode initial )
174 ///////////////////////////////////////////////////////////////////
176 // METHOD NAME : PathInfo::~PathInfo
177 // METHOD TYPE : Destructor
179 PathInfo::~PathInfo()
183 ///////////////////////////////////////////////////////////////////
185 // METHOD NAME : PathInfo::operator()
186 // METHOD TYPE : bool
188 bool PathInfo::operator()()
190 if ( path_t.empty() ) {
195 error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
198 error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
207 ///////////////////////////////////////////////////////////////////
209 // METHOD NAME : PathInfo::fileType
210 // METHOD TYPE : File_type
212 FileType PathInfo::fileType() const
215 return asStatMode().fileType();
219 ///////////////////////////////////////////////////////////////////
221 // METHOD NAME : PathInfo::userMay
222 // METHOD TYPE : mode_t
224 mode_t PathInfo::userMay() const
228 if ( owner() == getuid() ) {
229 return( uperm()/0100 );
230 } else if ( group() == getgid() ) {
231 return( gperm()/010 );
236 /******************************************************************
238 ** FUNCTION NAME : PathInfo::major
239 ** FUNCTION TYPE : unsigned int
241 unsigned int PathInfo::major() const
243 return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
246 /******************************************************************
248 ** FUNCTION NAME : PathInfo::minor
249 ** FUNCTION TYPE : unsigned int
251 unsigned int PathInfo::minor() const
253 return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
256 /******************************************************************
258 ** FUNCTION NAME : operator<<
259 ** FUNCTION TYPE : std::ostream &
261 std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
263 iostr::IosFmtFlagsSaver autoResoreState( str );
265 str << obj.asString() << "{";
266 if ( !obj.isExist() ) {
267 str << "does not exist}";
269 str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
272 str << " size " << obj.size();
280 ///////////////////////////////////////////////////////////////////
282 // filesystem utilities
284 ///////////////////////////////////////////////////////////////////
286 /******************************************************************
288 ** FUNCTION NAME : _Log_Result
289 ** FUNCTION TYPE : int
291 ** DESCRIPTION : Helper function to log return values.
293 inline int _Log_Result( const int res, const char * rclass = "errno" )
297 WAR << " FAILED: " << rclass << " " << res << endl;
301 ///////////////////////////////////////////////////////////////////
303 // METHOD NAME : PathInfo::mkdir
306 int mkdir( const Pathname & path, unsigned mode )
308 MIL << "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 // MIL << "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 WAR << " FAILED: mkdir " << path << ' ' << str::octstring( mode ) << " errno " << ret << endl;
354 MIL << "mkdir " << path << ' ' << str::octstring( mode ) << endl;
361 ///////////////////////////////////////////////////////////////////
363 // METHOD NAME : rmdir
366 int rmdir( const Pathname & path )
368 MIL << "rmdir " << path;
369 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
370 return _Log_Result( errno );
372 return _Log_Result( 0 );
375 ///////////////////////////////////////////////////////////////////
377 // METHOD NAME : recursive_rmdir
380 static int recursive_rmdir_1( const Pathname & dir )
385 if ( ! (dp = opendir( dir.c_str() )) )
386 return _Log_Result( errno );
388 while ( (d = readdir(dp)) )
390 std::string direntry = d->d_name;
391 if ( direntry == "." || direntry == ".." )
393 Pathname new_path( dir / d->d_name );
396 if ( ! lstat( new_path.c_str(), &st ) )
398 if ( S_ISDIR( st.st_mode ) )
399 recursive_rmdir_1( new_path );
401 ::unlink( new_path.c_str() );
406 if ( ::rmdir( dir.c_str() ) < 0 )
411 ///////////////////////////////////////////////////////////////////
412 int recursive_rmdir( const Pathname & path )
414 MIL << "recursive_rmdir " << path << ' ';
417 if ( !p.isExist() ) {
418 return _Log_Result( 0 );
422 return _Log_Result( ENOTDIR );
425 return _Log_Result( recursive_rmdir_1( path ) );
428 ///////////////////////////////////////////////////////////////////
430 // METHOD NAME : clean_dir
433 int clean_dir( const Pathname & path )
435 MIL << "clean_dir " << path << ' ';
438 if ( !p.isExist() ) {
439 return _Log_Result( 0 );
443 return _Log_Result( ENOTDIR );
446 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
447 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
448 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
449 MIL << " " << output;
451 int ret = prog.close();
452 return _Log_Result( ret, "returned" );
455 ///////////////////////////////////////////////////////////////////
457 // METHOD NAME : copy_dir
460 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
462 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
464 PathInfo sp( srcpath );
466 return _Log_Result( ENOTDIR );
469 PathInfo dp( destpath );
471 return _Log_Result( ENOTDIR );
474 PathInfo tp( destpath + srcpath.basename() );
475 if ( tp.isExist() ) {
476 return _Log_Result( EEXIST );
480 const char *const argv[] = {
484 srcpath.asString().c_str(),
485 destpath.asString().c_str(),
488 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
489 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
490 MIL << " " << output;
492 int ret = prog.close();
493 return _Log_Result( ret, "returned" );
496 ///////////////////////////////////////////////////////////////////
498 // METHOD NAME : copy_dir_content
501 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
503 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
505 PathInfo sp( srcpath );
507 return _Log_Result( ENOTDIR );
510 PathInfo dp( destpath );
512 return _Log_Result( ENOTDIR );
515 if ( srcpath == destpath ) {
516 return _Log_Result( EEXIST );
519 std::string src( srcpath.asString());
521 const char *const argv[] = {
526 destpath.asString().c_str(),
529 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
530 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
531 MIL << " " << output;
533 int ret = prog.close();
534 return _Log_Result( ret, "returned" );
537 ///////////////////////////////////////////////////////////////////
539 // METHOD NAME : readdir
542 int readdir( std::list<std::string> & retlist,
543 const Pathname & path, bool dots )
547 MIL << "readdir " << path << ' ';
549 DIR * dir = ::opendir( path.asString().c_str() );
551 return _Log_Result( errno );
554 struct dirent *entry;
555 while ( (entry = ::readdir( dir )) != 0 ) {
557 if ( entry->d_name[0] == '.' ) {
560 if ( entry->d_name[1] == '\0'
561 || ( entry->d_name[1] == '.'
562 && entry->d_name[2] == '\0' ) )
565 retlist.push_back( entry->d_name );
570 return _Log_Result( 0 );
574 ///////////////////////////////////////////////////////////////////
576 // METHOD NAME : readdir
579 int readdir( std::list<Pathname> & retlist,
580 const Pathname & path, bool dots )
584 std::list<string> content;
585 int res = readdir( content, path, dots );
588 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
589 retlist.push_back( path + *it );
596 ///////////////////////////////////////////////////////////////////
598 // METHOD NAME : readdir
602 bool DirEntry::operator==( const DirEntry &rhs ) const
604 // if one of the types is not known, use the name only
605 if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
606 return ( name == rhs.name );
607 return ((name == rhs.name ) && (type == rhs.type));
610 int readdir( DirContent & retlist, const Pathname & path,
611 bool dots, PathInfo::Mode statmode )
615 std::list<string> content;
616 int res = readdir( content, path, dots );
619 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
620 PathInfo p( path + *it, statmode );
621 retlist.push_back( DirEntry( *it, p.fileType() ) );
628 ///////////////////////////////////////////////////////////////////
630 // METHOD NAME : is_empty_dir
633 int is_empty_dir(const Pathname & path)
635 DIR * dir = ::opendir( path.asString().c_str() );
637 return _Log_Result( errno );
640 struct dirent *entry;
641 while ( (entry = ::readdir( dir )) != NULL )
643 std::string name(entry->d_name);
645 if ( name == "." || name == "..")
652 return entry != NULL ? -1 : 0;
655 ///////////////////////////////////////////////////////////////////
657 // METHOD NAME : unlink
660 int unlink( const Pathname & path )
662 MIL << "unlink " << path;
663 if ( ::unlink( path.asString().c_str() ) == -1 ) {
664 return _Log_Result( errno );
666 return _Log_Result( 0 );
669 ///////////////////////////////////////////////////////////////////
671 // METHOD NAME : rename
674 int rename( const Pathname & oldpath, const Pathname & newpath )
676 MIL << "rename " << oldpath << " -> " << newpath;
677 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
678 return _Log_Result( errno );
680 return _Log_Result( 0 );
683 ///////////////////////////////////////////////////////////////////
685 // METHOD NAME : copy
688 int copy( const Pathname & file, const Pathname & dest )
690 MIL << "copy " << file << " -> " << dest << ' ';
693 if ( !sp.isFile() ) {
694 return _Log_Result( EINVAL );
699 return _Log_Result( EISDIR );
702 const char *const argv[] = {
705 file.asString().c_str(),
706 dest.asString().c_str(),
709 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
710 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
711 MIL << " " << output;
713 int ret = prog.close();
714 return _Log_Result( ret, "returned" );
717 ///////////////////////////////////////////////////////////////////
719 // METHOD NAME : symlink
722 int symlink( const Pathname & oldpath, const Pathname & newpath )
724 MIL << "symlink " << newpath << " -> " << oldpath;
725 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
726 return _Log_Result( errno );
728 return _Log_Result( 0 );
731 ///////////////////////////////////////////////////////////////////
733 // METHOD NAME : hardlink
736 int hardlink( const Pathname & oldpath, const Pathname & newpath )
738 MIL << "hardlink " << newpath << " -> " << oldpath;
739 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
740 return _Log_Result( errno );
742 return _Log_Result( 0 );
745 ///////////////////////////////////////////////////////////////////
747 // METHOD NAME : readlink
750 int readlink( const Pathname & symlink_r, Pathname & target_r )
752 static const ssize_t bufsiz = 2047;
753 static char buf[bufsiz+1];
754 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
757 target_r = Pathname();
758 MIL << "readlink " << symlink_r;
759 return _Log_Result( errno );
766 ///////////////////////////////////////////////////////////////////
768 // METHOD NAME : expandlink
769 // METHOD TYPE : Pathname
771 Pathname expandlink( const Pathname & path_r )
773 static const unsigned int level_limit = 256;
774 static unsigned int count;
775 Pathname path(path_r);
776 PathInfo info(path_r, PathInfo::LSTAT);
778 for (count = level_limit; info.isLink() && count; count--)
780 DBG << "following symlink " << path;
781 path = path.dirname() / readlink(path);
782 DBG << "->" << path << std::endl;
783 info = PathInfo(path, PathInfo::LSTAT);
786 // expand limit reached
789 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
793 else if (count < level_limit)
795 // check for a broken link
796 if (PathInfo(path).isExist())
798 // broken link, return an empty path
801 ERR << path << " is broken (expanded from " << path_r << ")" << endl;
806 // not a symlink, return the original pathname
807 DBG << "not a symlink" << endl;
811 ///////////////////////////////////////////////////////////////////
813 // METHOD NAME : copy_file2dir
816 int copy_file2dir( const Pathname & file, const Pathname & dest )
818 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
821 if ( !sp.isFile() ) {
822 return _Log_Result( EINVAL );
827 return _Log_Result( ENOTDIR );
830 const char *const argv[] = {
833 file.asString().c_str(),
834 dest.asString().c_str(),
837 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
838 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
839 MIL << " " << output;
841 int ret = prog.close();
842 return _Log_Result( ret, "returned" );
845 ///////////////////////////////////////////////////////////////////
847 // METHOD NAME : md5sum
848 // METHOD TYPE : std::string
850 std::string md5sum( const Pathname & file )
852 if ( ! PathInfo( file ).isFile() ) {
855 std::ifstream istr( file.asString().c_str() );
859 return Digest::digest( "MD5", istr );
862 ///////////////////////////////////////////////////////////////////
864 // METHOD NAME : sha1sum
865 // METHOD TYPE : std::string
867 std::string sha1sum( const Pathname & file )
869 return checksum(file, "SHA1");
872 ///////////////////////////////////////////////////////////////////
874 // METHOD NAME : checksum
875 // METHOD TYPE : std::string
877 std::string checksum( const Pathname & file, const std::string &algorithm )
879 if ( ! PathInfo( file ).isFile() ) {
882 std::ifstream istr( file.asString().c_str() );
886 return Digest::digest( algorithm, istr );
889 bool is_checksum( const Pathname & file, const CheckSum &checksum )
891 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
894 ///////////////////////////////////////////////////////////////////
896 // METHOD NAME : erase
899 int erase( const Pathname & path )
902 PathInfo p( path, PathInfo::LSTAT );
906 res = recursive_rmdir( path );
908 res = unlink( path );
913 ///////////////////////////////////////////////////////////////////
915 // METHOD NAME : chmod
918 int chmod( const Pathname & path, mode_t mode )
920 MIL << "chmod " << path << ' ' << str::octstring( mode );
921 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
922 return _Log_Result( errno );
924 return _Log_Result( 0 );
927 ///////////////////////////////////////////////////////////////////
929 // METHOD NAME : zipType
930 // METHOD TYPE : ZIP_TYPE
932 ZIP_TYPE zipType( const Pathname & file )
934 ZIP_TYPE ret = ZT_NONE;
936 int fd = open( file.asString().c_str(), O_RDONLY );
939 const int magicSize = 3;
940 unsigned char magic[magicSize];
941 memset( magic, 0, magicSize );
942 if ( read( fd, magic, magicSize ) == magicSize ) {
943 if ( magic[0] == 0037 && magic[1] == 0213 ) {
945 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
955 ///////////////////////////////////////////////////////////////////
958 // METHOD TYPE : ByteCount
960 ByteCount df( const Pathname & path_r )
964 if ( statvfs( path_r.c_str(), &sb ) == 0 )
966 ret = sb.f_bfree * sb.f_bsize;
971 ///////////////////////////////////////////////////////////////////
973 // METHOD NAME : getUmask
974 // METHOD TYPE : mode_t
978 mode_t mask = ::umask( 0022 );
983 ///////////////////////////////////////////////////////////////////
985 // METHOD NAME : touch
988 int touch (const Pathname & path)
990 MIL << "touch " << path;
991 struct ::utimbuf times;
992 times.actime = ::time( 0 );
993 times.modtime = ::time( 0 );
994 if ( ::utime( path.asString().c_str(), × ) == -1 ) {
995 return _Log_Result( errno );
997 return _Log_Result( 0 );
1000 /////////////////////////////////////////////////////////////////
1001 } // namespace filesystem
1002 ///////////////////////////////////////////////////////////////////
1003 /////////////////////////////////////////////////////////////////
1005 ///////////////////////////////////////////////////////////////////