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 );
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 )
407 return _Log_Result( errno );
409 return _Log_Result( 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 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
601 int readdir( DirContent & retlist, const Pathname & path,
602 bool dots, PathInfo::Mode statmode )
606 std::list<string> content;
607 int res = readdir( content, path, dots );
610 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
611 PathInfo p( path + *it, statmode );
612 retlist.push_back( DirEntry( *it, p.fileType() ) );
619 ///////////////////////////////////////////////////////////////////
621 // METHOD NAME : is_empty_dir
624 int is_empty_dir(const Pathname & path)
626 DIR * dir = ::opendir( path.asString().c_str() );
628 return _Log_Result( errno );
631 struct dirent *entry;
632 while ( (entry = ::readdir( dir )) != NULL )
634 std::string name(entry->d_name);
636 if ( name == "." || name == "..")
643 return entry != NULL ? -1 : 0;
646 ///////////////////////////////////////////////////////////////////
648 // METHOD NAME : unlink
651 int unlink( const Pathname & path )
653 MIL << "unlink " << path;
654 if ( ::unlink( path.asString().c_str() ) == -1 ) {
655 return _Log_Result( errno );
657 return _Log_Result( 0 );
660 ///////////////////////////////////////////////////////////////////
662 // METHOD NAME : rename
665 int rename( const Pathname & oldpath, const Pathname & newpath )
667 MIL << "rename " << oldpath << " -> " << newpath;
668 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
669 return _Log_Result( errno );
671 return _Log_Result( 0 );
674 ///////////////////////////////////////////////////////////////////
676 // METHOD NAME : copy
679 int copy( const Pathname & file, const Pathname & dest )
681 MIL << "copy " << file << " -> " << dest << ' ';
684 if ( !sp.isFile() ) {
685 return _Log_Result( EINVAL );
690 return _Log_Result( EISDIR );
693 const char *const argv[] = {
696 file.asString().c_str(),
697 dest.asString().c_str(),
700 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
701 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
702 MIL << " " << output;
704 int ret = prog.close();
705 return _Log_Result( ret, "returned" );
708 ///////////////////////////////////////////////////////////////////
710 // METHOD NAME : symlink
713 int symlink( const Pathname & oldpath, const Pathname & newpath )
715 MIL << "symlink " << newpath << " -> " << oldpath;
716 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
717 return _Log_Result( errno );
719 return _Log_Result( 0 );
722 ///////////////////////////////////////////////////////////////////
724 // METHOD NAME : hardlink
727 int hardlink( const Pathname & oldpath, const Pathname & newpath )
729 MIL << "hardlink " << newpath << " -> " << oldpath;
730 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
731 return _Log_Result( errno );
733 return _Log_Result( 0 );
736 ///////////////////////////////////////////////////////////////////
738 // METHOD NAME : readlink
741 int readlink( const Pathname & symlink_r, Pathname & target_r )
743 static const ssize_t bufsiz = 2047;
744 static char buf[bufsiz+1];
745 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
748 target_r = Pathname();
749 MIL << "readlink " << symlink_r;
750 return _Log_Result( errno );
757 ///////////////////////////////////////////////////////////////////
759 // METHOD NAME : expandlink
760 // METHOD TYPE : Pathname
762 Pathname expandlink( const Pathname & path_r )
764 static const unsigned int level_limit = 256;
765 static unsigned int count;
766 Pathname path(path_r);
767 PathInfo info(path_r, PathInfo::LSTAT);
769 for (count = level_limit; info.isLink() && count; count--)
771 DBG << "following symlink " << path << std::endl;
772 path = readlink(path);
773 info = PathInfo(path, PathInfo::LSTAT);
776 // expand limit reached
779 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
783 else if (count < level_limit)
785 // check for a broken link
786 if (PathInfo(path).isExist())
788 // broken link, return and empty path
791 ERR << path << " is broken (expanded from " << path_r << ")" << endl;
796 // not a symlink, return the original pathname
797 DBG << "not a symlink" << endl;
801 ///////////////////////////////////////////////////////////////////
803 // METHOD NAME : copy_file2dir
806 int copy_file2dir( const Pathname & file, const Pathname & dest )
808 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
811 if ( !sp.isFile() ) {
812 return _Log_Result( EINVAL );
817 return _Log_Result( ENOTDIR );
820 const char *const argv[] = {
823 file.asString().c_str(),
824 dest.asString().c_str(),
827 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
828 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
829 MIL << " " << output;
831 int ret = prog.close();
832 return _Log_Result( ret, "returned" );
835 ///////////////////////////////////////////////////////////////////
837 // METHOD NAME : md5sum
838 // METHOD TYPE : std::string
840 std::string md5sum( const Pathname & file )
842 if ( ! PathInfo( file ).isFile() ) {
845 std::ifstream istr( file.asString().c_str() );
849 return Digest::digest( "MD5", istr );
852 ///////////////////////////////////////////////////////////////////
854 // METHOD NAME : sha1sum
855 // METHOD TYPE : std::string
857 std::string sha1sum( const Pathname & file )
859 return checksum(file, "SHA1");
862 ///////////////////////////////////////////////////////////////////
864 // METHOD NAME : checksum
865 // METHOD TYPE : std::string
867 std::string checksum( const Pathname & file, const std::string &algorithm )
869 if ( ! PathInfo( file ).isFile() ) {
872 std::ifstream istr( file.asString().c_str() );
876 return Digest::digest( algorithm, istr );
879 bool is_checksum( const Pathname & file, const CheckSum &checksum )
881 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
884 ///////////////////////////////////////////////////////////////////
886 // METHOD NAME : erase
889 int erase( const Pathname & path )
892 PathInfo p( path, PathInfo::LSTAT );
896 res = recursive_rmdir( path );
898 res = unlink( path );
903 ///////////////////////////////////////////////////////////////////
905 // METHOD NAME : chmod
908 int chmod( const Pathname & path, mode_t mode )
910 MIL << "chmod " << path << ' ' << str::octstring( mode );
911 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
912 return _Log_Result( errno );
914 return _Log_Result( 0 );
917 ///////////////////////////////////////////////////////////////////
919 // METHOD NAME : zipType
920 // METHOD TYPE : ZIP_TYPE
922 ZIP_TYPE zipType( const Pathname & file )
924 ZIP_TYPE ret = ZT_NONE;
926 int fd = open( file.asString().c_str(), O_RDONLY );
929 const int magicSize = 3;
930 unsigned char magic[magicSize];
931 memset( magic, 0, magicSize );
932 if ( read( fd, magic, magicSize ) == magicSize ) {
933 if ( magic[0] == 0037 && magic[1] == 0213 ) {
935 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
945 ///////////////////////////////////////////////////////////////////
948 // METHOD TYPE : ByteCount
950 ByteCount df( const Pathname & path_r )
954 if ( statvfs( path_r.c_str(), &sb ) == 0 )
956 ret = sb.f_bfree * sb.f_bsize;
961 ///////////////////////////////////////////////////////////////////
963 // METHOD NAME : getUmask
964 // METHOD TYPE : mode_t
968 mode_t mask = ::umask( 0022 );
973 ///////////////////////////////////////////////////////////////////
975 // METHOD NAME : touch
978 int touch (const Pathname & path)
980 MIL << "touch " << path;
981 struct ::utimbuf times;
982 times.actime = ::time( 0 );
983 times.modtime = ::time( 0 );
984 if ( ::utime( path.asString().c_str(), × ) == -1 ) {
985 return _Log_Result( errno );
987 return _Log_Result( 0 );
990 /////////////////////////////////////////////////////////////////
991 } // namespace filesystem
992 ///////////////////////////////////////////////////////////////////
993 /////////////////////////////////////////////////////////////////
995 ///////////////////////////////////////////////////////////////////