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