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