libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00013 #include <sys/types.h> // for ::minor, ::major macros 00014 #include <utime.h> // for ::utime 00015 #include <sys/statvfs.h> 00016 00017 #include <iostream> 00018 #include <fstream> 00019 #include <iomanip> 00020 00021 #include "zypp/base/Logger.h" 00022 #include "zypp/base/String.h" 00023 #include "zypp/base/IOStream.h" 00024 00025 #include "zypp/ExternalProgram.h" 00026 #include "zypp/PathInfo.h" 00027 #include "zypp/Digest.h" 00028 #include "zypp/TmpPath.h" 00029 00030 using std::endl; 00031 using std::string; 00032 00034 namespace zypp 00035 { 00036 00037 namespace filesystem 00038 { 00039 00040 /****************************************************************** 00041 ** 00042 ** FUNCTION NAME : operator<< 00043 ** FUNCTION TYPE : std::ostream & 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 // METHOD NAME : StatMode::fileType 00066 // METHOD TYPE : FileType 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 ** FUNCTION NAME : operator<< 00091 ** FUNCTION TYPE : std::ostream & 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 // Class : PathInfo 00120 // 00122 00124 // 00125 // METHOD NAME : PathInfo::PathInfo 00126 // METHOD TYPE : Constructor 00127 // 00128 PathInfo::PathInfo() 00129 : mode_e( STAT ) 00130 , error_i( -1 ) 00131 {} 00132 00134 // 00135 // METHOD NAME : PathInfo::PathInfo 00136 // METHOD TYPE : Constructor 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 // METHOD NAME : PathInfo::PathInfo 00149 // METHOD TYPE : Constructor 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 // METHOD NAME : PathInfo::PathInfo 00162 // METHOD TYPE : Constructor 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 // METHOD NAME : PathInfo::~PathInfo 00175 // METHOD TYPE : Destructor 00176 // 00177 PathInfo::~PathInfo() 00178 { 00179 } 00180 00182 // 00183 // METHOD NAME : PathInfo::operator() 00184 // METHOD TYPE : bool 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 // METHOD NAME : PathInfo::fileType 00208 // METHOD TYPE : File_type 00209 // 00210 FileType PathInfo::fileType() const 00211 { 00212 if ( isExist() ) 00213 return asStatMode().fileType(); 00214 return FT_NOT_EXIST; 00215 } 00216 00218 // 00219 // METHOD NAME : PathInfo::userMay 00220 // METHOD TYPE : mode_t 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 ** FUNCTION NAME : PathInfo::major 00237 ** FUNCTION TYPE : unsigned int 00238 */ 00239 unsigned int PathInfo::major() const 00240 { 00241 return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0; 00242 } 00243 00244 /****************************************************************** 00245 ** 00246 ** FUNCTION NAME : PathInfo::minor 00247 ** FUNCTION TYPE : unsigned int 00248 */ 00249 unsigned int PathInfo::minor() const 00250 { 00251 return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0; 00252 } 00253 00254 /****************************************************************** 00255 ** 00256 ** FUNCTION NAME : operator<< 00257 ** FUNCTION TYPE : std::ostream & 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 // filesystem utilities 00281 // 00283 00284 /****************************************************************** 00285 ** 00286 ** FUNCTION NAME : _Log_Result 00287 ** FUNCTION TYPE : int 00288 ** 00289 ** DESCRIPTION : Helper function to log return values. 00290 */ 00291 #define _Log_Result MIL << endl, __Log_Result 00292 inline int __Log_Result( const int res, const char * rclass = 0 /*errno*/ ) 00293 { 00294 if ( res ) 00295 { 00296 if ( rclass ) 00297 WAR << " FAILED: " << rclass << " " << res << endl; 00298 else 00299 WAR << " FAILED: " << str::strerror( res ) << endl; 00300 } 00301 return res; 00302 } 00303 00305 // 00306 // METHOD NAME : PathInfo::mkdir 00307 // METHOD TYPE : int 00308 // 00309 int mkdir( const Pathname & path, unsigned mode ) 00310 { 00311 MIL << "mkdir " << path << ' ' << str::octstring( mode ); 00312 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) { 00313 return _Log_Result( errno ); 00314 } 00315 return _Log_Result( 0 ); 00316 } 00317 00319 // 00320 // METHOD NAME : assert_dir() 00321 // METHOD TYPE : int 00322 // 00323 int assert_dir( const Pathname & path, unsigned mode ) 00324 { 00325 if ( path.empty() ) 00326 return ENOENT; 00327 00328 { // Handle existing paths in advance. 00329 PathInfo pi( path ); 00330 if ( pi.isDir() ) 00331 return 0; 00332 if ( pi.isExist() ) 00333 return EEXIST; 00334 } 00335 00336 string spath = path.asString()+"/"; 00337 string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/' 00338 string::size_type pos = string::npos; 00339 int ret = 0; 00340 00341 while ( (pos = spath.find('/',lastpos)) != string::npos ) 00342 { 00343 string dir( spath.substr(0,pos) ); 00344 ret = ::mkdir( dir.c_str(), mode ); 00345 if ( ret == -1 ) 00346 { 00347 if ( errno == EEXIST ) // ignore errors about already existing paths 00348 ret = 0; 00349 else 00350 { 00351 ret = errno; 00352 WAR << " FAILED: mkdir " << dir << ' ' << str::octstring( mode ) << " errno " << ret << endl; 00353 } 00354 } 00355 else 00356 { 00357 MIL << "mkdir " << dir << ' ' << str::octstring( mode ) << endl; 00358 } 00359 lastpos = pos+1; 00360 } 00361 00362 return ret; 00363 } 00364 00366 // 00367 // METHOD NAME : rmdir 00368 // METHOD TYPE : int 00369 // 00370 int rmdir( const Pathname & path ) 00371 { 00372 MIL << "rmdir " << path; 00373 if ( ::rmdir( path.asString().c_str() ) == -1 ) { 00374 return _Log_Result( errno ); 00375 } 00376 return _Log_Result( 0 ); 00377 } 00378 00380 // 00381 // METHOD NAME : recursive_rmdir 00382 // METHOD TYPE : int 00383 // 00384 static int recursive_rmdir_1( const Pathname & dir ) 00385 { 00386 DIR * dp; 00387 struct dirent * d; 00388 00389 if ( ! (dp = opendir( dir.c_str() )) ) 00390 return _Log_Result( errno ); 00391 00392 while ( (d = readdir(dp)) ) 00393 { 00394 std::string direntry = d->d_name; 00395 if ( direntry == "." || direntry == ".." ) 00396 continue; 00397 Pathname new_path( dir / d->d_name ); 00398 00399 struct stat st; 00400 if ( ! lstat( new_path.c_str(), &st ) ) 00401 { 00402 if ( S_ISDIR( st.st_mode ) ) 00403 recursive_rmdir_1( new_path ); 00404 else 00405 ::unlink( new_path.c_str() ); 00406 } 00407 } 00408 closedir( dp ); 00409 00410 if ( ::rmdir( dir.c_str() ) < 0 ) 00411 return errno; 00412 00413 return 0; 00414 } 00416 int recursive_rmdir( const Pathname & path ) 00417 { 00418 MIL << "recursive_rmdir " << path << ' '; 00419 PathInfo p( path ); 00420 00421 if ( !p.isExist() ) { 00422 return _Log_Result( 0 ); 00423 } 00424 00425 if ( !p.isDir() ) { 00426 return _Log_Result( ENOTDIR ); 00427 } 00428 00429 return _Log_Result( recursive_rmdir_1( path ) ); 00430 } 00431 00433 // 00434 // METHOD NAME : clean_dir 00435 // METHOD TYPE : int 00436 // 00437 int clean_dir( const Pathname & path ) 00438 { 00439 MIL << "clean_dir " << path << ' '; 00440 PathInfo p( path ); 00441 00442 if ( !p.isExist() ) { 00443 return _Log_Result( 0 ); 00444 } 00445 00446 if ( !p.isDir() ) { 00447 return _Log_Result( ENOTDIR ); 00448 } 00449 00450 string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) ); 00451 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout ); 00452 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) { 00453 MIL << " " << output; 00454 } 00455 int ret = prog.close(); 00456 return _Log_Result( ret, "returned" ); 00457 } 00458 00460 // 00461 // METHOD NAME : copy_dir 00462 // METHOD TYPE : int 00463 // 00464 int copy_dir( const Pathname & srcpath, const Pathname & destpath ) 00465 { 00466 MIL << "copy_dir " << srcpath << " -> " << destpath << ' '; 00467 00468 PathInfo sp( srcpath ); 00469 if ( !sp.isDir() ) { 00470 return _Log_Result( ENOTDIR ); 00471 } 00472 00473 PathInfo dp( destpath ); 00474 if ( !dp.isDir() ) { 00475 return _Log_Result( ENOTDIR ); 00476 } 00477 00478 PathInfo tp( destpath + srcpath.basename() ); 00479 if ( tp.isExist() ) { 00480 return _Log_Result( EEXIST ); 00481 } 00482 00483 00484 const char *const argv[] = { 00485 "/bin/cp", 00486 "-dR", 00487 "--", 00488 srcpath.asString().c_str(), 00489 destpath.asString().c_str(), 00490 NULL 00491 }; 00492 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout ); 00493 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) { 00494 MIL << " " << output; 00495 } 00496 int ret = prog.close(); 00497 return _Log_Result( ret, "returned" ); 00498 } 00499 00501 // 00502 // METHOD NAME : copy_dir_content 00503 // METHOD TYPE : int 00504 // 00505 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath) 00506 { 00507 MIL << "copy_dir " << srcpath << " -> " << destpath << ' '; 00508 00509 PathInfo sp( srcpath ); 00510 if ( !sp.isDir() ) { 00511 return _Log_Result( ENOTDIR ); 00512 } 00513 00514 PathInfo dp( destpath ); 00515 if ( !dp.isDir() ) { 00516 return _Log_Result( ENOTDIR ); 00517 } 00518 00519 if ( srcpath == destpath ) { 00520 return _Log_Result( EEXIST ); 00521 } 00522 00523 std::string src( srcpath.asString()); 00524 src += "/."; 00525 const char *const argv[] = { 00526 "/bin/cp", 00527 "-dR", 00528 "--", 00529 src.c_str(), 00530 destpath.asString().c_str(), 00531 NULL 00532 }; 00533 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout ); 00534 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) { 00535 MIL << " " << output; 00536 } 00537 int ret = prog.close(); 00538 return _Log_Result( ret, "returned" ); 00539 } 00540 00542 // 00543 // METHOD NAME : readdir 00544 // METHOD TYPE : int 00545 // 00546 int readdir( std::list<std::string> & retlist, 00547 const Pathname & path, bool dots ) 00548 { 00549 retlist.clear(); 00550 00551 MIL << "readdir " << path << ' '; 00552 00553 DIR * dir = ::opendir( path.asString().c_str() ); 00554 if ( ! dir ) { 00555 return _Log_Result( errno ); 00556 } 00557 00558 struct dirent *entry; 00559 while ( (entry = ::readdir( dir )) != 0 ) { 00560 00561 if ( entry->d_name[0] == '.' ) { 00562 if ( !dots ) 00563 continue; 00564 if ( entry->d_name[1] == '\0' 00565 || ( entry->d_name[1] == '.' 00566 && entry->d_name[2] == '\0' ) ) 00567 continue; 00568 } 00569 retlist.push_back( entry->d_name ); 00570 } 00571 00572 ::closedir( dir ); 00573 00574 return _Log_Result( 0 ); 00575 } 00576 00577 00579 // 00580 // METHOD NAME : readdir 00581 // METHOD TYPE : int 00582 // 00583 int readdir( std::list<Pathname> & retlist, 00584 const Pathname & path, bool dots ) 00585 { 00586 retlist.clear(); 00587 00588 std::list<string> content; 00589 int res = readdir( content, path, dots ); 00590 00591 if ( !res ) { 00592 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) { 00593 retlist.push_back( path + *it ); 00594 } 00595 } 00596 00597 return res; 00598 } 00599 00601 // 00602 // METHOD NAME : readdir 00603 // METHOD TYPE : int 00604 // 00605 00606 bool DirEntry::operator==( const DirEntry &rhs ) const 00607 { 00608 // if one of the types is not known, use the name only 00609 if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL ) 00610 return ( name == rhs.name ); 00611 return ((name == rhs.name ) && (type == rhs.type)); 00612 } 00613 00614 int readdir( DirContent & retlist, const Pathname & path, 00615 bool dots, PathInfo::Mode statmode ) 00616 { 00617 retlist.clear(); 00618 00619 std::list<string> content; 00620 int res = readdir( content, path, dots ); 00621 00622 if ( !res ) { 00623 for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) { 00624 PathInfo p( path + *it, statmode ); 00625 retlist.push_back( DirEntry( *it, p.fileType() ) ); 00626 } 00627 } 00628 00629 return res; 00630 } 00631 00633 // 00634 // METHOD NAME : is_empty_dir 00635 // METHOD TYPE : int 00636 // 00637 int is_empty_dir(const Pathname & path) 00638 { 00639 DIR * dir = ::opendir( path.asString().c_str() ); 00640 if ( ! dir ) { 00641 return _Log_Result( errno ); 00642 } 00643 00644 struct dirent *entry; 00645 while ( (entry = ::readdir( dir )) != NULL ) 00646 { 00647 std::string name(entry->d_name); 00648 00649 if ( name == "." || name == "..") 00650 continue; 00651 00652 break; 00653 } 00654 ::closedir( dir ); 00655 00656 return entry != NULL ? -1 : 0; 00657 } 00658 00660 // 00661 // METHOD NAME : unlink 00662 // METHOD TYPE : int 00663 // 00664 int unlink( const Pathname & path ) 00665 { 00666 MIL << "unlink " << path; 00667 if ( ::unlink( path.asString().c_str() ) == -1 ) { 00668 return _Log_Result( errno ); 00669 } 00670 return _Log_Result( 0 ); 00671 } 00672 00674 // 00675 // METHOD NAME : rename 00676 // METHOD TYPE : int 00677 // 00678 int rename( const Pathname & oldpath, const Pathname & newpath ) 00679 { 00680 MIL << "rename " << oldpath << " -> " << newpath; 00681 if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) { 00682 return _Log_Result( errno ); 00683 } 00684 return _Log_Result( 0 ); 00685 } 00686 00688 // 00689 // METHOD NAME : exchange 00690 // METHOD TYPE : int 00691 // 00692 int exchange( const Pathname & lpath, const Pathname & rpath ) 00693 { 00694 MIL << "exchange " << lpath << " <-> " << rpath; 00695 if ( lpath.empty() || rpath.empty() ) 00696 return _Log_Result( EINVAL ); 00697 00698 PathInfo linfo( lpath ); 00699 PathInfo rinfo( rpath ); 00700 00701 if ( ! linfo.isExist() ) 00702 { 00703 if ( ! rinfo.isExist() ) 00704 return _Log_Result( 0 ); // both don't exist. 00705 00706 // just rename rpath -> lpath 00707 int ret = assert_dir( lpath.dirname() ); 00708 if ( ret != 0 ) 00709 return _Log_Result( ret ); 00710 if ( ::rename( rpath.c_str(), lpath.c_str() ) == -1 ) { 00711 return _Log_Result( errno ); 00712 } 00713 return _Log_Result( 0 ); 00714 } 00715 00716 // HERE: lpath exists: 00717 if ( ! rinfo.isExist() ) 00718 { 00719 // just rename lpath -> rpath 00720 int ret = assert_dir( rpath.dirname() ); 00721 if ( ret != 0 ) 00722 return _Log_Result( ret ); 00723 if ( ::rename( lpath.c_str(), rpath.c_str() ) == -1 ) { 00724 return _Log_Result( errno ); 00725 } 00726 return _Log_Result( 0 ); 00727 } 00728 00729 // HERE: both exist 00730 TmpFile tmpfile( TmpFile::makeSibling( rpath ) ); 00731 if ( ! tmpfile ) 00732 return _Log_Result( errno ); 00733 Pathname tmp( tmpfile.path() ); 00734 ::unlink( tmp.c_str() ); 00735 00736 if ( ::rename( lpath.c_str(), tmp.c_str() ) == -1 ) { 00737 return _Log_Result( errno ); 00738 } 00739 if ( ::rename( rpath.c_str(), lpath.c_str() ) == -1 ) { 00740 ::rename( tmp.c_str(), lpath.c_str() ); 00741 return _Log_Result( errno ); 00742 } 00743 if ( ::rename( tmp.c_str(), rpath.c_str() ) == -1 ) { 00744 ::rename( lpath.c_str(), rpath.c_str() ); 00745 ::rename( tmp.c_str(), lpath.c_str() ); 00746 return _Log_Result( errno ); 00747 } 00748 return _Log_Result( 0 ); 00749 } 00750 00752 // 00753 // METHOD NAME : copy 00754 // METHOD TYPE : int 00755 // 00756 int copy( const Pathname & file, const Pathname & dest ) 00757 { 00758 MIL << "copy " << file << " -> " << dest << ' '; 00759 00760 PathInfo sp( file ); 00761 if ( !sp.isFile() ) { 00762 return _Log_Result( EINVAL ); 00763 } 00764 00765 PathInfo dp( dest ); 00766 if ( dp.isDir() ) { 00767 return _Log_Result( EISDIR ); 00768 } 00769 00770 const char *const argv[] = { 00771 "/bin/cp", 00772 "--remove-destination", 00773 "--", 00774 file.asString().c_str(), 00775 dest.asString().c_str(), 00776 NULL 00777 }; 00778 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout ); 00779 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) { 00780 MIL << " " << output; 00781 } 00782 int ret = prog.close(); 00783 return _Log_Result( ret, "returned" ); 00784 } 00785 00787 // 00788 // METHOD NAME : symlink 00789 // METHOD TYPE : int 00790 // 00791 int symlink( const Pathname & oldpath, const Pathname & newpath ) 00792 { 00793 MIL << "symlink " << newpath << " -> " << oldpath; 00794 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) { 00795 return _Log_Result( errno ); 00796 } 00797 return _Log_Result( 0 ); 00798 } 00799 00801 // 00802 // METHOD NAME : hardlink 00803 // METHOD TYPE : int 00804 // 00805 int hardlink( const Pathname & oldpath, const Pathname & newpath ) 00806 { 00807 MIL << "hardlink " << newpath << " -> " << oldpath; 00808 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) { 00809 return _Log_Result( errno ); 00810 } 00811 return _Log_Result( 0 ); 00812 } 00813 00815 // 00816 // METHOD NAME : hardlink 00817 // METHOD TYPE : int 00818 // 00819 int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath ) 00820 { 00821 MIL << "hardlinkCopy " << oldpath << " -> " << newpath; 00822 00823 PathInfo pi( oldpath, PathInfo::LSTAT ); 00824 if ( pi.isLink() ) 00825 { 00826 // dont hardlink symlinks! 00827 return copy( oldpath, newpath ); 00828 } 00829 00830 pi.lstat( newpath ); 00831 if ( pi.isExist() ) 00832 { 00833 int res = unlink( newpath ); 00834 if ( res != 0 ) 00835 return _Log_Result( res ); 00836 } 00837 00838 // Here: no symlink, no newpath 00839 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) 00840 { 00841 switch ( errno ) 00842 { 00843 case EXDEV: // oldpath and newpath are not on the same mounted file system 00844 return copy( oldpath, newpath ); 00845 break; 00846 } 00847 return _Log_Result( errno ); 00848 } 00849 return _Log_Result( 0 ); 00850 } 00851 00853 // 00854 // METHOD NAME : readlink 00855 // METHOD TYPE : int 00856 // 00857 int readlink( const Pathname & symlink_r, Pathname & target_r ) 00858 { 00859 static const ssize_t bufsiz = 2047; 00860 static char buf[bufsiz+1]; 00861 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz ); 00862 if ( ret == -1 ) 00863 { 00864 target_r = Pathname(); 00865 MIL << "readlink " << symlink_r; 00866 return _Log_Result( errno ); 00867 } 00868 buf[ret] = '\0'; 00869 target_r = buf; 00870 return 0; 00871 } 00872 00874 // 00875 // METHOD NAME : expandlink 00876 // METHOD TYPE : Pathname 00877 // 00878 Pathname expandlink( const Pathname & path_r ) 00879 { 00880 static const unsigned int level_limit = 256; 00881 static unsigned int count; 00882 Pathname path(path_r); 00883 PathInfo info(path_r, PathInfo::LSTAT); 00884 00885 for (count = level_limit; info.isLink() && count; count--) 00886 { 00887 DBG << "following symlink " << path; 00888 path = path.dirname() / readlink(path); 00889 DBG << "->" << path << std::endl; 00890 info = PathInfo(path, PathInfo::LSTAT); 00891 } 00892 00893 // expand limit reached 00894 if (count == 0) 00895 { 00896 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl; 00897 return Pathname(); 00898 } 00899 // symlink 00900 else if (count < level_limit) 00901 { 00902 // check for a broken link 00903 if (PathInfo(path).isExist()) 00904 return path; 00905 // broken link, return an empty path 00906 else 00907 { 00908 ERR << path << " is broken (expanded from " << path_r << ")" << endl; 00909 return Pathname(); 00910 } 00911 } 00912 00913 // not a symlink, return the original pathname 00914 DBG << "not a symlink" << endl; 00915 return path; 00916 } 00917 00919 // 00920 // METHOD NAME : copy_file2dir 00921 // METHOD TYPE : int 00922 // 00923 int copy_file2dir( const Pathname & file, const Pathname & dest ) 00924 { 00925 MIL << "copy_file2dir " << file << " -> " << dest << ' '; 00926 00927 PathInfo sp( file ); 00928 if ( !sp.isFile() ) { 00929 return _Log_Result( EINVAL ); 00930 } 00931 00932 PathInfo dp( dest ); 00933 if ( !dp.isDir() ) { 00934 return _Log_Result( ENOTDIR ); 00935 } 00936 00937 const char *const argv[] = { 00938 "/bin/cp", 00939 "--", 00940 file.asString().c_str(), 00941 dest.asString().c_str(), 00942 NULL 00943 }; 00944 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout ); 00945 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) { 00946 MIL << " " << output; 00947 } 00948 int ret = prog.close(); 00949 return _Log_Result( ret, "returned" ); 00950 } 00951 00953 // 00954 // METHOD NAME : md5sum 00955 // METHOD TYPE : std::string 00956 // 00957 std::string md5sum( const Pathname & file ) 00958 { 00959 if ( ! PathInfo( file ).isFile() ) { 00960 return string(); 00961 } 00962 std::ifstream istr( file.asString().c_str() ); 00963 if ( ! istr ) { 00964 return string(); 00965 } 00966 return Digest::digest( "MD5", istr ); 00967 } 00968 00970 // 00971 // METHOD NAME : sha1sum 00972 // METHOD TYPE : std::string 00973 // 00974 std::string sha1sum( const Pathname & file ) 00975 { 00976 return checksum(file, "SHA1"); 00977 } 00978 00980 // 00981 // METHOD NAME : checksum 00982 // METHOD TYPE : std::string 00983 // 00984 std::string checksum( const Pathname & file, const std::string &algorithm ) 00985 { 00986 if ( ! PathInfo( file ).isFile() ) { 00987 return string(); 00988 } 00989 std::ifstream istr( file.asString().c_str() ); 00990 if ( ! istr ) { 00991 return string(); 00992 } 00993 return Digest::digest( algorithm, istr ); 00994 } 00995 00996 bool is_checksum( const Pathname & file, const CheckSum &checksum ) 00997 { 00998 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() ); 00999 } 01000 01002 // 01003 // METHOD NAME : erase 01004 // METHOD TYPE : int 01005 // 01006 int erase( const Pathname & path ) 01007 { 01008 int res = 0; 01009 PathInfo p( path, PathInfo::LSTAT ); 01010 if ( p.isExist() ) 01011 { 01012 if ( p.isDir() ) 01013 res = recursive_rmdir( path ); 01014 else 01015 res = unlink( path ); 01016 } 01017 return res; 01018 } 01019 01021 // 01022 // METHOD NAME : chmod 01023 // METHOD TYPE : int 01024 // 01025 int chmod( const Pathname & path, mode_t mode ) 01026 { 01027 MIL << "chmod " << path << ' ' << str::octstring( mode ); 01028 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) { 01029 return _Log_Result( errno ); 01030 } 01031 return _Log_Result( 0 ); 01032 } 01033 01034 int addmod( const Pathname & path, mode_t mode ) 01035 { 01036 mode_t omode( PathInfo( path ).st_mode() ); 01037 mode_t tmode( omode | mode ); 01038 if ( omode != mode ) 01039 return chmod( path, tmode ); 01040 return 0; 01041 } 01042 01043 int delmod( const Pathname & path, mode_t mode ) 01044 { 01045 mode_t omode( PathInfo( path ).st_mode() ); 01046 mode_t tmode( omode & ~mode ); 01047 if ( omode != mode ) 01048 return chmod( path, tmode ); 01049 return 0; 01050 } 01051 01053 // 01054 // METHOD NAME : zipType 01055 // METHOD TYPE : ZIP_TYPE 01056 // 01057 ZIP_TYPE zipType( const Pathname & file ) 01058 { 01059 ZIP_TYPE ret = ZT_NONE; 01060 01061 int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC ); 01062 01063 if ( fd != -1 ) { 01064 const int magicSize = 3; 01065 unsigned char magic[magicSize]; 01066 memset( magic, 0, magicSize ); 01067 if ( read( fd, magic, magicSize ) == magicSize ) { 01068 if ( magic[0] == 0037 && magic[1] == 0213 ) { 01069 ret = ZT_GZ; 01070 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) { 01071 ret = ZT_BZ2; 01072 } 01073 } 01074 close( fd ); 01075 } 01076 01077 return ret; 01078 } 01079 01081 // 01082 // METHOD NAME : df 01083 // METHOD TYPE : ByteCount 01084 // 01085 ByteCount df( const Pathname & path_r ) 01086 { 01087 ByteCount ret( -1 ); 01088 struct statvfs sb; 01089 if ( statvfs( path_r.c_str(), &sb ) == 0 ) 01090 { 01091 ret = sb.f_bfree * sb.f_bsize; 01092 } 01093 return ret; 01094 } 01095 01097 // 01098 // METHOD NAME : getUmask 01099 // METHOD TYPE : mode_t 01100 // 01101 mode_t getUmask() 01102 { 01103 mode_t mask = ::umask( 0022 ); 01104 ::umask( mask ); 01105 return mask; 01106 } 01107 01109 // 01110 // METHOD NAME : getUmask 01111 // METHOD TYPE : mode_t 01112 // 01113 int assert_file( const Pathname & path, unsigned mode ) 01114 { 01115 int ret = assert_dir( path.dirname() ); 01116 MIL << "assert_file " << str::octstring( mode ) << " " << path; 01117 if ( ret != 0 ) 01118 return _Log_Result( ret ); 01119 01120 PathInfo pi( path ); 01121 if ( pi.isExist() ) 01122 return _Log_Result( pi.isFile() ? 0 : EEXIST ); 01123 01124 int fd = ::creat( path.c_str(), mode ); 01125 if ( fd == -1 ) 01126 return _Log_Result( errno ); 01127 01128 ::close( fd ); 01129 return _Log_Result( 0 ); 01130 } 01131 01133 // 01134 // METHOD NAME : touch 01135 // METHOD TYPE : int 01136 // 01137 int touch (const Pathname & path) 01138 { 01139 MIL << "touch " << path; 01140 struct ::utimbuf times; 01141 times.actime = ::time( 0 ); 01142 times.modtime = ::time( 0 ); 01143 if ( ::utime( path.asString().c_str(), × ) == -1 ) { 01144 return _Log_Result( errno ); 01145 } 01146 return _Log_Result( 0 ); 01147 } 01148 01150 } // namespace filesystem 01153 } // namespace zypp