00001
00002
00003
00004
00005
00006
00007
00008
00013 #include <sys/types.h>
00014 #include <utime.h>
00015 #include <sys/statvfs.h>
00016
00017 #include <iostream>
00018 #include <fstream>
00019 #include <iomanip>
00020
00021 #include <boost/filesystem/operations.hpp>
00022 #include <boost/filesystem/exception.hpp>
00023
00024 #include "zypp/base/Logger.h"
00025 #include "zypp/base/String.h"
00026 #include "zypp/base/IOStream.h"
00027
00028 #include "zypp/ExternalProgram.h"
00029 #include "zypp/PathInfo.h"
00030 #include "zypp/Digest.h"
00031
00032 using std::endl;
00033 using std::string;
00034
00036 namespace zypp
00037 {
00038
00039 namespace filesystem
00040 {
00041
00042
00043
00044
00045
00046
00047 std::ostream & operator<<( std::ostream & str, FileType obj )
00048 {
00049 switch ( obj ) {
00050 #define EMUMOUT(T) case T: return str << #T; break
00051 EMUMOUT( FT_NOT_AVAIL );
00052 EMUMOUT( FT_NOT_EXIST );
00053 EMUMOUT( FT_FILE );
00054 EMUMOUT( FT_DIR );
00055 EMUMOUT( FT_CHARDEV );
00056 EMUMOUT( FT_BLOCKDEV );
00057 EMUMOUT( FT_FIFO );
00058 EMUMOUT( FT_LINK );
00059 EMUMOUT( FT_SOCKET );
00060 #undef EMUMOUT
00061 }
00062 return str;
00063 }
00064
00066
00067
00068
00069
00070 FileType StatMode::fileType() const
00071 {
00072 if ( isFile() )
00073 return FT_FILE;
00074 if ( isDir() )
00075 return FT_DIR;
00076 if ( isLink() )
00077 return FT_LINK;
00078 if ( isChr() )
00079 return FT_CHARDEV;
00080 if ( isBlk() )
00081 return FT_BLOCKDEV;
00082 if ( isFifo() )
00083 return FT_FIFO;
00084 if ( isSock() )
00085 return FT_SOCKET ;
00086
00087 return FT_NOT_AVAIL;
00088 }
00089
00090
00091
00092
00093
00094
00095 std::ostream & operator<<( std::ostream & str, const StatMode & obj )
00096 {
00097 iostr::IosFmtFlagsSaver autoResoreState( str );
00098
00099 char t = '?';
00100 if ( obj.isFile() )
00101 t = '-';
00102 else if ( obj.isDir() )
00103 t = 'd';
00104 else if ( obj.isLink() )
00105 t = 'l';
00106 else if ( obj.isChr() )
00107 t = 'c';
00108 else if ( obj.isBlk() )
00109 t = 'b';
00110 else if ( obj.isFifo() )
00111 t = 'p';
00112 else if ( obj.isSock() )
00113 t = 's';
00114
00115 str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
00116 return str;
00117 }
00118
00120
00121
00122
00124
00126
00127
00128
00129
00130 PathInfo::PathInfo()
00131 : mode_e( STAT )
00132 , error_i( -1 )
00133 {}
00134
00136
00137
00138
00139
00140 PathInfo::PathInfo( const Pathname & path, Mode initial )
00141 : path_t( path )
00142 , mode_e( initial )
00143 , error_i( -1 )
00144 {
00145 operator()();
00146 }
00147
00149
00150
00151
00152
00153 PathInfo::PathInfo( const std::string & path, Mode initial )
00154 : path_t( path )
00155 , mode_e( initial )
00156 , error_i( -1 )
00157 {
00158 operator()();
00159 }
00160
00162
00163
00164
00165
00166 PathInfo::PathInfo( const char * path, Mode initial )
00167 : path_t( path )
00168 , mode_e( initial )
00169 , error_i( -1 )
00170 {
00171 operator()();
00172 }
00173
00175
00176
00177
00178
00179 PathInfo::~PathInfo()
00180 {
00181 }
00182
00184
00185
00186
00187
00188 bool PathInfo::operator()()
00189 {
00190 if ( path_t.empty() ) {
00191 error_i = -1;
00192 } else {
00193 switch ( mode_e ) {
00194 case STAT:
00195 error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
00196 break;
00197 case LSTAT:
00198 error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
00199 break;
00200 }
00201 if ( error_i == -1 )
00202 error_i = errno;
00203 }
00204 return !error_i;
00205 }
00206
00208
00209
00210
00211
00212 FileType PathInfo::fileType() const
00213 {
00214 if ( isExist() )
00215 return asStatMode().fileType();
00216 return FT_NOT_EXIST;
00217 }
00218
00220
00221
00222
00223
00224 mode_t PathInfo::userMay() const
00225 {
00226 if ( !isExist() )
00227 return 0;
00228 if ( owner() == getuid() ) {
00229 return( uperm()/0100 );
00230 } else if ( group() == getgid() ) {
00231 return( gperm()/010 );
00232 }
00233 return operm();
00234 }
00235
00236
00237
00238
00239
00240
00241 unsigned int PathInfo::major() const
00242 {
00243 return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
00244 }
00245
00246
00247
00248
00249
00250
00251 unsigned int PathInfo::minor() const
00252 {
00253 return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
00254 }
00255
00256
00257
00258
00259
00260
00261 std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
00262 {
00263 iostr::IosFmtFlagsSaver autoResoreState( str );
00264
00265 str << obj.asString() << "{";
00266 if ( !obj.isExist() ) {
00267 str << "does not exist}";
00268 } else {
00269 str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
00270
00271 if ( obj.isFile() )
00272 str << " size " << obj.size();
00273
00274 str << "}";
00275 }
00276
00277 return str;
00278 }
00279
00281
00282
00283
00285
00286
00287
00288
00289
00290
00291
00292
00293 inline int _Log_Result( const int res, const char * rclass = "errno" )
00294 {
00295 MIL << endl;
00296 if ( res )
00297 WAR << " FAILED: " << rclass << " " << res << endl;
00298 return res;
00299 }
00300
00302
00303
00304
00305
00306 int mkdir( const Pathname & path, unsigned mode )
00307 {
00308 MIL << "mkdir " << path << ' ' << str::octstring( mode );
00309 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
00310 return _Log_Result( errno );
00311 }
00312 return _Log_Result( 0 );
00313 }
00314
00316
00317
00318
00319
00320 int assert_dir( const Pathname & path, unsigned mode )
00321 {
00322 string::size_type pos, lastpos = 0;
00323 string spath = path.asString()+"/";
00324 int ret = 0;
00325
00326 if(path.empty())
00327 return ENOENT;
00328
00329
00330 if(path.relative())
00331 lastpos=2;
00332
00333 else
00334 lastpos=1;
00335
00336
00337 while((pos = spath.find('/',lastpos)) != string::npos )
00338 {
00339 string dir = spath.substr(0,pos);
00340 ret = ::mkdir(dir.c_str(), mode);
00341 if(ret == -1)
00342 {
00343
00344 if(errno == EEXIST)
00345 ret=0;
00346 else
00347 {
00348 ret=errno;
00349 WAR << " FAILED: mkdir " << path << ' ' << str::octstring( mode ) << " errno " << ret << endl;
00350 }
00351 }
00352 else
00353 {
00354 MIL << "mkdir " << path << ' ' << str::octstring( mode );
00355 }
00356 lastpos = pos+1;
00357 }
00358 return ret;
00359 }
00360
00362
00363
00364
00365
00366 int rmdir( const Pathname & path )
00367 {
00368 MIL << "rmdir " << path;
00369 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
00370 return _Log_Result( errno );
00371 }
00372 return _Log_Result( 0 );
00373 }
00374
00376
00377
00378
00379
00380 int recursive_rmdir( const Pathname & path )
00381 {
00382 MIL << "recursive_rmdir " << path << ' ';
00383 PathInfo p( path );
00384
00385 if ( !p.isExist() ) {
00386 return _Log_Result( 0 );
00387 }
00388
00389 if ( !p.isDir() ) {
00390 return _Log_Result( ENOTDIR );
00391 }
00392
00393 try
00394 {
00395 boost::filesystem::path bp( path.asString(), boost::filesystem::native );
00396 boost::filesystem::remove_all( bp );
00397 }
00398 catch ( boost::filesystem::filesystem_error & excpt )
00399 {
00400 WAR << " FAILED: " << excpt.what() << endl;
00401 return -1;
00402 }
00403
00404 return _Log_Result( 0 );
00405 }
00406
00408
00409
00410
00411
00412 int clean_dir( const Pathname & path )
00413 {
00414 MIL << "clean_dir " << path << ' ';
00415 PathInfo p( path );
00416
00417 if ( !p.isExist() ) {
00418 return _Log_Result( 0 );
00419 }
00420
00421 if ( !p.isDir() ) {
00422 return _Log_Result( ENOTDIR );
00423 }
00424
00425 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
00426 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
00427 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00428 MIL << " " << output;
00429 }
00430 int ret = prog.close();
00431 return _Log_Result( ret, "returned" );
00432 }
00433
00435
00436
00437
00438
00439 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
00440 {
00441 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
00442
00443 PathInfo sp( srcpath );
00444 if ( !sp.isDir() ) {
00445 return _Log_Result( ENOTDIR );
00446 }
00447
00448 PathInfo dp( destpath );
00449 if ( !dp.isDir() ) {
00450 return _Log_Result( ENOTDIR );
00451 }
00452
00453 PathInfo tp( destpath + srcpath.basename() );
00454 if ( tp.isExist() ) {
00455 return _Log_Result( EEXIST );
00456 }
00457
00458
00459 const char *const argv[] = {
00460 "/bin/cp",
00461 "-dR",
00462 "--",
00463 srcpath.asString().c_str(),
00464 destpath.asString().c_str(),
00465 NULL
00466 };
00467 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00468 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00469 MIL << " " << output;
00470 }
00471 int ret = prog.close();
00472 return _Log_Result( ret, "returned" );
00473 }
00474
00476
00477
00478
00479
00480 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
00481 {
00482 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
00483
00484 PathInfo sp( srcpath );
00485 if ( !sp.isDir() ) {
00486 return _Log_Result( ENOTDIR );
00487 }
00488
00489 PathInfo dp( destpath );
00490 if ( !dp.isDir() ) {
00491 return _Log_Result( ENOTDIR );
00492 }
00493
00494 if ( srcpath == destpath ) {
00495 return _Log_Result( EEXIST );
00496 }
00497
00498 std::string src( srcpath.asString());
00499 src += "/.";
00500 const char *const argv[] = {
00501 "/bin/cp",
00502 "-dR",
00503 "--",
00504 src.c_str(),
00505 destpath.asString().c_str(),
00506 NULL
00507 };
00508 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00509 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00510 MIL << " " << output;
00511 }
00512 int ret = prog.close();
00513 return _Log_Result( ret, "returned" );
00514 }
00515
00517
00518
00519
00520
00521 int readdir( std::list<std::string> & retlist,
00522 const Pathname & path, bool dots )
00523 {
00524 retlist.clear();
00525
00526 MIL << "readdir " << path << ' ';
00527
00528 DIR * dir = ::opendir( path.asString().c_str() );
00529 if ( ! dir ) {
00530 return _Log_Result( errno );
00531 }
00532
00533 struct dirent *entry;
00534 while ( (entry = ::readdir( dir )) != 0 ) {
00535
00536 if ( entry->d_name[0] == '.' ) {
00537 if ( !dots )
00538 continue;
00539 if ( entry->d_name[1] == '\0'
00540 || ( entry->d_name[1] == '.'
00541 && entry->d_name[2] == '\0' ) )
00542 continue;
00543 }
00544 retlist.push_back( entry->d_name );
00545 }
00546
00547 ::closedir( dir );
00548
00549 return _Log_Result( 0 );
00550 }
00551
00552
00554
00555
00556
00557
00558 int readdir( std::list<Pathname> & retlist,
00559 const Pathname & path, bool dots )
00560 {
00561 retlist.clear();
00562
00563 std::list<string> content;
00564 int res = readdir( content, path, dots );
00565
00566 if ( !res ) {
00567 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
00568 retlist.push_back( path + *it );
00569 }
00570 }
00571
00572 return res;
00573 }
00574
00576
00577
00578
00579
00580 int readdir( DirContent & retlist, const Pathname & path,
00581 bool dots, PathInfo::Mode statmode )
00582 {
00583 retlist.clear();
00584
00585 std::list<string> content;
00586 int res = readdir( content, path, dots );
00587
00588 if ( !res ) {
00589 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
00590 PathInfo p( path + *it, statmode );
00591 retlist.push_back( DirEntry( *it, p.fileType() ) );
00592 }
00593 }
00594
00595 return res;
00596 }
00597
00599
00600
00601
00602
00603 int is_empty_dir(const Pathname & path)
00604 {
00605 DIR * dir = ::opendir( path.asString().c_str() );
00606 if ( ! dir ) {
00607 return _Log_Result( errno );
00608 }
00609
00610 struct dirent *entry;
00611 while ( (entry = ::readdir( dir )) != NULL )
00612 {
00613 std::string name(entry->d_name);
00614
00615 if ( name == "." || name == "..")
00616 continue;
00617
00618 break;
00619 }
00620 ::closedir( dir );
00621
00622 return entry != NULL ? -1 : 0;
00623 }
00624
00626
00627
00628
00629
00630 int unlink( const Pathname & path )
00631 {
00632 MIL << "unlink " << path;
00633 if ( ::unlink( path.asString().c_str() ) == -1 ) {
00634 return _Log_Result( errno );
00635 }
00636 return _Log_Result( 0 );
00637 }
00638
00640
00641
00642
00643
00644 int rename( const Pathname & oldpath, const Pathname & newpath )
00645 {
00646 MIL << "rename " << oldpath << " -> " << newpath;
00647 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
00648 return _Log_Result( errno );
00649 }
00650 return _Log_Result( 0 );
00651 }
00652
00654
00655
00656
00657
00658 int copy( const Pathname & file, const Pathname & dest )
00659 {
00660 MIL << "copy " << file << " -> " << dest << ' ';
00661
00662 PathInfo sp( file );
00663 if ( !sp.isFile() ) {
00664 return _Log_Result( EINVAL );
00665 }
00666
00667 PathInfo dp( dest );
00668 if ( dp.isDir() ) {
00669 return _Log_Result( EISDIR );
00670 }
00671
00672 const char *const argv[] = {
00673 "/bin/cp",
00674 "--",
00675 file.asString().c_str(),
00676 dest.asString().c_str(),
00677 NULL
00678 };
00679 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00680 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00681 MIL << " " << output;
00682 }
00683 int ret = prog.close();
00684 return _Log_Result( ret, "returned" );
00685 }
00686
00688
00689
00690
00691
00692 int symlink( const Pathname & oldpath, const Pathname & newpath )
00693 {
00694 MIL << "symlink " << newpath << " -> " << oldpath;
00695 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
00696 return _Log_Result( errno );
00697 }
00698 return _Log_Result( 0 );
00699 }
00700
00702
00703
00704
00705
00706 int hardlink( const Pathname & oldpath, const Pathname & newpath )
00707 {
00708 MIL << "hardlink " << newpath << " -> " << oldpath;
00709 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
00710 return _Log_Result( errno );
00711 }
00712 return _Log_Result( 0 );
00713 }
00714
00716
00717
00718
00719
00720 int copy_file2dir( const Pathname & file, const Pathname & dest )
00721 {
00722 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
00723
00724 PathInfo sp( file );
00725 if ( !sp.isFile() ) {
00726 return _Log_Result( EINVAL );
00727 }
00728
00729 PathInfo dp( dest );
00730 if ( !dp.isDir() ) {
00731 return _Log_Result( ENOTDIR );
00732 }
00733
00734 const char *const argv[] = {
00735 "/bin/cp",
00736 "--",
00737 file.asString().c_str(),
00738 dest.asString().c_str(),
00739 NULL
00740 };
00741 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00742 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00743 MIL << " " << output;
00744 }
00745 int ret = prog.close();
00746 return _Log_Result( ret, "returned" );
00747 }
00748
00750
00751
00752
00753
00754 std::string md5sum( const Pathname & file )
00755 {
00756 if ( ! PathInfo( file ).isFile() ) {
00757 return string();
00758 }
00759 std::ifstream istr( file.asString().c_str() );
00760 if ( ! istr ) {
00761 return string();
00762 }
00763 return Digest::digest( "MD5", istr );
00764 }
00765
00767
00768
00769
00770
00771 std::string sha1sum( const Pathname & file )
00772 {
00773 return checksum(file, "SHA1");
00774 }
00775
00777
00778
00779
00780
00781 std::string checksum( const Pathname & file, const std::string &algorithm )
00782 {
00783 if ( ! PathInfo( file ).isFile() ) {
00784 return string();
00785 }
00786 std::ifstream istr( file.asString().c_str() );
00787 if ( ! istr ) {
00788 return string();
00789 }
00790 return Digest::digest( algorithm, istr );
00791 }
00792
00793 bool is_checksum( const Pathname & file, const CheckSum &checksum )
00794 {
00795 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
00796 }
00797
00799
00800
00801
00802
00803 int erase( const Pathname & path )
00804 {
00805 int res = 0;
00806 PathInfo p( path, PathInfo::LSTAT );
00807 if ( p.isExist() )
00808 {
00809 if ( p.isDir() )
00810 res = recursive_rmdir( path );
00811 else
00812 res = unlink( path );
00813 }
00814 return res;
00815 }
00816
00818
00819
00820
00821
00822 int chmod( const Pathname & path, mode_t mode )
00823 {
00824 MIL << "chmod " << path << ' ' << str::octstring( mode );
00825 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
00826 return _Log_Result( errno );
00827 }
00828 return _Log_Result( 0 );
00829 }
00830
00832
00833
00834
00835
00836 ZIP_TYPE zipType( const Pathname & file )
00837 {
00838 ZIP_TYPE ret = ZT_NONE;
00839
00840 int fd = open( file.asString().c_str(), O_RDONLY );
00841
00842 if ( fd != -1 ) {
00843 const int magicSize = 3;
00844 unsigned char magic[magicSize];
00845 memset( magic, 0, magicSize );
00846 if ( read( fd, magic, magicSize ) == magicSize ) {
00847 if ( magic[0] == 0037 && magic[1] == 0213 ) {
00848 ret = ZT_GZ;
00849 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
00850 ret = ZT_BZ2;
00851 }
00852 }
00853 close( fd );
00854 }
00855
00856 return ret;
00857 }
00858
00860
00861
00862
00863
00864 ByteCount df( const Pathname & path_r )
00865 {
00866 ByteCount ret( -1 );
00867 struct statvfs sb;
00868 if ( statvfs( path_r.c_str(), &sb ) == 0 )
00869 {
00870 ret = sb.f_bfree * sb.f_bsize;
00871 }
00872 return ret;
00873 }
00874
00876
00877
00878
00879
00880 mode_t getUmask()
00881 {
00882 mode_t mask = ::umask( 0022 );
00883 ::umask( mask );
00884 return mask;
00885 }
00886
00888
00889
00890
00891
00892 int touch (const Pathname & path)
00893 {
00894 MIL << "touch " << path;
00895 struct ::utimbuf times;
00896 times.actime = ::time( 0 );
00897 times.modtime = ::time( 0 );
00898 if ( ::utime( path.asString().c_str(), × ) == -1 ) {
00899 return _Log_Result( errno );
00900 }
00901 return _Log_Result( 0 );
00902 }
00903
00905 }
00908 }