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