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