00001
00002
00003
00004
00005
00006
00007
00008
00013 #include <iostream>
00014
00015 #include "zypp/base/Logger.h"
00016 #include "zypp/ExternalProgram.h"
00017 #include "zypp/base/String.h"
00018
00019 #include "zypp/media/MediaCurl.h"
00020 #include "zypp/media/proxyinfo/ProxyInfos.h"
00021 #include "zypp/media/ProxyInfo.h"
00022 #include "zypp/thread/Once.h"
00023 #include <cstdlib>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <sys/mount.h>
00027 #include <errno.h>
00028 #include <dirent.h>
00029 #include <unistd.h>
00030
00031 #include "config.h"
00032
00033 #define DETECT_DIR_INDEX 0
00034
00035 using namespace std;
00036 using namespace zypp::base;
00037
00038 namespace
00039 {
00040 zypp::thread::OnceFlag g_InitOnceFlag = PTHREAD_ONCE_INIT;
00041 zypp::thread::OnceFlag g_FreeOnceFlag = PTHREAD_ONCE_INIT;
00042
00043 extern "C" void _do_free_once()
00044 {
00045 curl_global_cleanup();
00046 }
00047
00048 extern "C" void globalFreeOnce()
00049 {
00050 zypp::thread::callOnce(g_FreeOnceFlag, _do_free_once);
00051 }
00052
00053 extern "C" void _do_init_once()
00054 {
00055 CURLcode ret = curl_global_init( CURL_GLOBAL_ALL );
00056 if ( ret != 0 )
00057 {
00058 WAR << "curl global init failed" << endl;
00059 }
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 }
00070
00071 inline void globalInitOnce()
00072 {
00073 zypp::thread::callOnce(g_InitOnceFlag, _do_init_once);
00074 }
00075 }
00076
00077 namespace zypp {
00078 namespace media {
00079
00080 Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
00081 std::string MediaCurl::_agent = "Novell ZYPP Installer";
00082
00084
00085 static inline void escape( string & str_r,
00086 const char char_r, const string & escaped_r ) {
00087 for ( string::size_type pos = str_r.find( char_r );
00088 pos != string::npos; pos = str_r.find( char_r, pos ) ) {
00089 str_r.replace( pos, 1, escaped_r );
00090 }
00091 }
00092
00093 static inline string escapedPath( string path_r ) {
00094 escape( path_r, ' ', "%20" );
00095 return path_r;
00096 }
00097
00098 static inline string unEscape( string text_r ) {
00099 char * tmp = curl_unescape( text_r.c_str(), 0 );
00100 string ret( tmp );
00101 curl_free( tmp );
00102 return ret;
00103 }
00104
00106
00107
00108
00110
00111 MediaCurl::MediaCurl( const Url & url_r,
00112 const Pathname & attach_point_hint_r )
00113 : MediaHandler( url_r, attach_point_hint_r,
00114 "/",
00115 true ),
00116 _curl( NULL )
00117 {
00118 _curlError[0] = '\0';
00119
00120 MIL << "MediaCurl::MediaCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00121
00122 globalInitOnce();
00123
00124 if( !attachPoint().empty())
00125 {
00126 PathInfo ainfo(attachPoint());
00127 Pathname apath(attachPoint() + "XXXXXX");
00128 char *atemp = ::strdup( apath.asString().c_str());
00129 char *atest = NULL;
00130 if( !ainfo.isDir() || !ainfo.userMayRWX() ||
00131 atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
00132 {
00133 WAR << "attach point " << ainfo.path()
00134 << " is not useable for " << url_r.getScheme() << endl;
00135 setAttachPoint("", true);
00136 }
00137 else if( atest != NULL)
00138 ::rmdir(atest);
00139
00140 if( atemp != NULL)
00141 ::free(atemp);
00142 }
00143 }
00144
00145 void MediaCurl::setCookieFile( const Pathname &fileName )
00146 {
00147 _cookieFile = fileName;
00148 }
00149
00151
00152
00153
00154
00155
00156
00157
00158 void MediaCurl::attachTo (bool next)
00159 {
00160 if ( next )
00161 ZYPP_THROW(MediaNotSupportedException(_url));
00162
00163 if ( !_url.isValid() )
00164 ZYPP_THROW(MediaBadUrlException(_url));
00165
00166 curl_version_info_data *curl_info = NULL;
00167 curl_info = curl_version_info(CURLVERSION_NOW);
00168
00169 if (curl_info->protocols)
00170 {
00171 const char * const *proto;
00172 std::string scheme( _url.getScheme());
00173 bool found = false;
00174 for(proto=curl_info->protocols; !found && *proto; ++proto)
00175 {
00176 if( scheme == std::string((const char *)*proto))
00177 found = true;
00178 }
00179 if( !found)
00180 {
00181 std::string msg("Unsupported protocol '");
00182 msg += scheme;
00183 msg += "'";
00184 ZYPP_THROW(MediaBadUrlException(_url, msg));
00185 }
00186 }
00187
00188 if( !isUseableAttachPoint(attachPoint()))
00189 {
00190 std::string mountpoint = createAttachPoint().asString();
00191
00192 if( mountpoint.empty())
00193 ZYPP_THROW( MediaBadAttachPointException(url()));
00194
00195 setAttachPoint( mountpoint, true);
00196 }
00197
00198 disconnectFrom();
00199 _curl = curl_easy_init();
00200 if ( !_curl ) {
00201 ZYPP_THROW(MediaCurlInitException(_url));
00202 }
00203
00204 CURLcode ret = curl_easy_setopt( _curl, CURLOPT_ERRORBUFFER, _curlError );
00205 if ( ret != 0 ) {
00206 disconnectFrom();
00207 ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer"));
00208 }
00209
00210 ret = curl_easy_setopt( _curl, CURLOPT_FAILONERROR, true );
00211 if ( ret != 0 ) {
00212 disconnectFrom();
00213 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00214 }
00215
00216 ret = curl_easy_setopt( _curl, CURLOPT_NOSIGNAL, 1 );
00217 if ( ret != 0 ) {
00218 disconnectFrom();
00219 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 if ( _url.getScheme() == "http" ) {
00240
00241
00242 ret = curl_easy_setopt ( _curl, CURLOPT_FOLLOWLOCATION, true );
00243 if ( ret != 0) {
00244 disconnectFrom();
00245 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00246 }
00247 ret = curl_easy_setopt ( _curl, CURLOPT_MAXREDIRS, 3L );
00248 if ( ret != 0) {
00249 disconnectFrom();
00250 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00251 }
00252 ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, _agent.c_str() );
00253 if ( ret != 0) {
00254 disconnectFrom();
00255 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00256 }
00257 }
00258
00259 if ( _url.getScheme() == "https" ) {
00260 ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYPEER, 1 );
00261 if ( ret != 0 ) {
00262 disconnectFrom();
00263 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00264 }
00265 ret = curl_easy_setopt( _curl, CURLOPT_CAPATH, "/etc/ssl/certs/" );
00266 if ( ret != 0 ) {
00267 disconnectFrom();
00268 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00269 }
00270 ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYHOST, 2 );
00271 if ( ret != 0 ) {
00272 disconnectFrom();
00273 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00274 }
00275 ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, _agent.c_str() );
00276 if ( ret != 0) {
00277 disconnectFrom();
00278 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00279 }
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 if ( _url.getUsername().empty() ) {
00291 if ( _url.getScheme() == "ftp" ) {
00292 string id = "yast2@";
00293 id += VERSION;
00294 DBG << "Anonymous FTP identification: '" << id << "'" << endl;
00295 _userpwd = "anonymous:" + id;
00296 }
00297 } else {
00298 _userpwd = _url.getUsername();
00299 if ( _url.getPassword().size() ) {
00300 _userpwd += ":" + _url.getPassword();
00301 }
00302 }
00303
00304 if ( _userpwd.size() ) {
00305 _userpwd = unEscape( _userpwd );
00306 ret = curl_easy_setopt( _curl, CURLOPT_USERPWD, _userpwd.c_str() );
00307 if ( ret != 0 ) {
00308 disconnectFrom();
00309 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00310 }
00311
00312 if( !_url.getQueryParam("auth").empty() &&
00313 (_url.getScheme() == "http" || _url.getScheme() == "https"))
00314 {
00315 std::vector<std::string> list;
00316 std::vector<std::string>::const_iterator it;
00317 str::split(_url.getQueryParam("auth"), std::back_inserter(list), ",");
00318
00319 long auth = CURLAUTH_NONE;
00320 for(it = list.begin(); it != list.end(); ++it)
00321 {
00322 if(*it == "basic")
00323 {
00324 auth |= CURLAUTH_BASIC;
00325 }
00326 else
00327 if(*it == "digest")
00328 {
00329 auth |= CURLAUTH_DIGEST;
00330 }
00331 else
00332 if((curl_info && (curl_info->features & CURL_VERSION_NTLM)) &&
00333 (*it == "ntlm"))
00334 {
00335 auth |= CURLAUTH_NTLM;
00336 }
00337 else
00338 if((curl_info && (curl_info->features & CURL_VERSION_SPNEGO)) &&
00339 (*it == "spnego" || *it == "negotiate"))
00340 {
00341
00342 auth |= CURLAUTH_GSSNEGOTIATE;
00343 }
00344 else
00345 if((curl_info && (curl_info->features & CURL_VERSION_GSSNEGOTIATE)) &&
00346 (*it == "gssnego" || *it == "negotiate"))
00347 {
00348 auth |= CURLAUTH_GSSNEGOTIATE;
00349 }
00350 else
00351 {
00352 std::string msg("Unsupported HTTP authentication method '");
00353 msg += *it;
00354 msg += "'";
00355 disconnectFrom();
00356 ZYPP_THROW(MediaBadUrlException(_url, msg));
00357 }
00358 }
00359
00360 if( auth != CURLAUTH_NONE)
00361 {
00362 DBG << "Enabling HTTP authentication methods: "
00363 << _url.getQueryParam("auth") << std::endl;
00364
00365 ret = curl_easy_setopt( _curl, CURLOPT_HTTPAUTH, auth);
00366 if ( ret != 0 ) {
00367 disconnectFrom();
00368 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00369 }
00370 }
00371 }
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381 _proxy = _url.getQueryParam( "proxy" );
00382
00383 if ( ! _proxy.empty() ) {
00384 string proxyport( _url.getQueryParam( "proxyport" ) );
00385 if ( ! proxyport.empty() ) {
00386 _proxy += ":" + proxyport;
00387 }
00388 } else {
00389
00390 ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy")));
00391
00392 if ( proxy_info.enabled())
00393 {
00394 bool useproxy = true;
00395
00396 std::list<std::string> nope = proxy_info.noProxy();
00397 for (ProxyInfo::NoProxyIterator it = proxy_info.noProxyBegin();
00398 it != proxy_info.noProxyEnd();
00399 it++)
00400 {
00401 std::string host( str::toLower(_url.getHost()));
00402 std::string temp( str::toLower(*it));
00403
00404
00405
00406
00407 if( temp.size() > 1 && temp.at(0) == '.')
00408 {
00409 if(host.size() > temp.size() &&
00410 host.compare(host.size() - temp.size(), temp.size(), temp) == 0)
00411 {
00412 DBG << "NO_PROXY: '" << *it << "' matches host '"
00413 << host << "'" << endl;
00414 useproxy = false;
00415 break;
00416 }
00417 }
00418 else
00419
00420 if( host == temp)
00421 {
00422 DBG << "NO_PROXY: '" << *it << "' matches host '"
00423 << host << "'" << endl;
00424 useproxy = false;
00425 break;
00426 }
00427 }
00428
00429 if ( useproxy ) {
00430 _proxy = proxy_info.proxy(_url.getScheme());
00431 }
00432 }
00433 }
00434
00435
00436 DBG << "Proxy: " << (_proxy.empty() ? "-none-" : _proxy) << endl;
00437
00438 if ( ! _proxy.empty() ) {
00439
00440 ret = curl_easy_setopt( _curl, CURLOPT_PROXY, _proxy.c_str() );
00441 if ( ret != 0 ) {
00442 disconnectFrom();
00443 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453 _proxyuserpwd = _url.getQueryParam( "proxyuser" );
00454
00455 if ( ! _proxyuserpwd.empty() ) {
00456
00457 string proxypassword( _url.getQueryParam( "proxypassword" ) );
00458 if ( ! proxypassword.empty() ) {
00459 _proxyuserpwd += ":" + proxypassword;
00460 }
00461
00462 } else {
00463 char *home = getenv("HOME");
00464 if( home && *home)
00465 {
00466 Pathname curlrcFile = string( home ) + string( "/.curlrc" );
00467
00468 PathInfo h_info(string(home), PathInfo::LSTAT);
00469 PathInfo c_info(curlrcFile, PathInfo::LSTAT);
00470
00471 if( h_info.isDir() && h_info.owner() == getuid() &&
00472 c_info.isFile() && c_info.owner() == getuid())
00473 {
00474 map<string,string> rc_data = proxyinfo::sysconfigRead(curlrcFile);
00475
00476 map<string,string>::const_iterator it = rc_data.find("proxy-user");
00477 if (it != rc_data.end())
00478 _proxyuserpwd = it->second;
00479 }
00480 else
00481 {
00482 WAR << "Not allowed to parse '" << curlrcFile
00483 << "': bad file owner" << std::endl;
00484 }
00485 }
00486 }
00487
00488 _proxyuserpwd = unEscape( _proxyuserpwd );
00489 ret = curl_easy_setopt( _curl, CURLOPT_PROXYUSERPWD, _proxyuserpwd.c_str() );
00490 if ( ret != 0 ) {
00491 disconnectFrom();
00492 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00493 }
00494 }
00495
00496
00497
00498
00499 _currentCookieFile = _cookieFile.asString();
00500
00501 ret = curl_easy_setopt( _curl, CURLOPT_COOKIEFILE,
00502 _currentCookieFile.c_str() );
00503 if ( ret != 0 ) {
00504 disconnectFrom();
00505 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00506 }
00507
00508 ret = curl_easy_setopt( _curl, CURLOPT_COOKIEJAR,
00509 _currentCookieFile.c_str() );
00510 if ( ret != 0 ) {
00511 disconnectFrom();
00512 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00513 }
00514
00515 ret = curl_easy_setopt( _curl, CURLOPT_PROGRESSFUNCTION,
00516 &progressCallback );
00517 if ( ret != 0 ) {
00518 disconnectFrom();
00519 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00520 }
00521
00522 ret = curl_easy_setopt( _curl, CURLOPT_NOPROGRESS, false );
00523 if ( ret != 0 ) {
00524 disconnectFrom();
00525 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00526 }
00527
00528
00529 MediaSourceRef media( new MediaSource(_url.getScheme(), _url.asString()));
00530 setMediaSource(media);
00531 }
00532
00533 bool
00534 MediaCurl::checkAttachPoint(const Pathname &apoint) const
00535 {
00536 return MediaHandler::checkAttachPoint( apoint, true, true);
00537 }
00538
00540
00541
00542
00543
00544
00545 void MediaCurl::disconnectFrom()
00546 {
00547 if ( _curl )
00548 {
00549 curl_easy_cleanup( _curl );
00550 _curl = NULL;
00551 }
00552 }
00553
00555
00556
00557
00558
00559
00560
00561
00562 void MediaCurl::releaseFrom( bool eject )
00563 {
00564 disconnect();
00565 }
00566
00567
00569
00570
00571
00572
00573
00574 void MediaCurl::getFile( const Pathname & filename ) const
00575 {
00576
00577
00578 getFileCopy(filename, localPath(filename).absolutename());
00579 }
00580
00581
00582 void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target) const
00583 {
00584 callback::SendReport<DownloadProgressReport> report;
00585
00586 Url url( _url );
00587
00588 try {
00589 doGetFileCopy(filename, target, report);
00590 }
00591 catch (MediaException & excpt_r)
00592 {
00593
00594
00595 report->finish(url, zypp::media::DownloadProgressReport::NOT_FOUND, excpt_r.msg());
00596 ZYPP_RETHROW(excpt_r);
00597 }
00598 report->finish(url, zypp::media::DownloadProgressReport::NO_ERROR, "");
00599 }
00600
00601 void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport<DownloadProgressReport> & report) const
00602 {
00603 DBG << filename.asString() << endl;
00604
00605 if(!_url.isValid())
00606 ZYPP_THROW(MediaBadUrlException(_url));
00607
00608 if(_url.getHost().empty())
00609 ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
00610
00611 string path = _url.getPathName();
00612 if ( !path.empty() && path != "/" && *path.rbegin() == '/' &&
00613 filename.absolute() ) {
00614
00615
00616 path += filename.asString().substr( 1, filename.asString().size() - 1 );
00617 } else if ( filename.relative() ) {
00618
00619 if ( !path.empty() && *path.rbegin() != '/' ) path += "/";
00620
00621 path += filename.asString().substr( 2, filename.asString().size() - 2 );
00622 } else {
00623 path += filename.asString();
00624 }
00625
00626 Url url( _url );
00627 url.setPathName( path );
00628
00629 Pathname dest = target.absolutename();
00630 if( assert_dir( dest.dirname() ) )
00631 {
00632 DBG << "assert_dir " << dest.dirname() << " failed" << endl;
00633 ZYPP_THROW( MediaSystemException(url, "System error on " + dest.dirname().asString()) );
00634 }
00635
00636 DBG << "URL: " << url.asString() << endl;
00637
00638
00639
00640
00641 Url curlUrl( url );
00642
00643
00644 curlUrl.setUsername( "" );
00645 curlUrl.setPassword( "" );
00646 curlUrl.setPathParams( "" );
00647 curlUrl.setQueryString( "" );
00648 curlUrl.setFragment( "" );
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 string urlBuffer( curlUrl.asString());
00659 CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
00660 urlBuffer.c_str() );
00661 if ( ret != 0 ) {
00662 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00663 }
00664
00665 string destNew = target.asString() + ".new.zypp.XXXXXX";
00666 char *buf = ::strdup( destNew.c_str());
00667 if( !buf)
00668 {
00669 ERR << "out of memory for temp file name" << endl;
00670 ZYPP_THROW(MediaSystemException(
00671 url, "out of memory for temp file name"
00672 ));
00673 }
00674
00675 int tmp_fd = ::mkstemp( buf );
00676 if( tmp_fd == -1)
00677 {
00678 free( buf);
00679 ERR << "mkstemp failed for file '" << destNew << "'" << endl;
00680 ZYPP_THROW(MediaWriteException(destNew));
00681 }
00682 destNew = buf;
00683 free( buf);
00684
00685 FILE *file = ::fdopen( tmp_fd, "w" );
00686 if ( !file ) {
00687 ::close( tmp_fd);
00688 filesystem::unlink( destNew );
00689 ERR << "fopen failed for file '" << destNew << "'" << endl;
00690 ZYPP_THROW(MediaWriteException(destNew));
00691 }
00692
00693 DBG << "dest: " << dest << endl;
00694 DBG << "temp: " << destNew << endl;
00695
00696 ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
00697 if ( ret != 0 ) {
00698 ::fclose( file );
00699 filesystem::unlink( destNew );
00700 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00701 }
00702
00703
00704 report->start(url, dest);
00705 if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &report ) != 0 ) {
00706 WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
00707 }
00708
00709 ret = curl_easy_perform( _curl );
00710
00711 if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
00712 WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
00713 }
00714
00715 if ( ret != 0 ) {
00716 ::fclose( file );
00717 filesystem::unlink( destNew );
00718 ERR << "curl error: " << ret << ": " << _curlError << endl;
00719 std::string err;
00720 try {
00721 bool err_file_not_found = false;
00722 switch ( ret ) {
00723 case CURLE_UNSUPPORTED_PROTOCOL:
00724 case CURLE_URL_MALFORMAT:
00725 case CURLE_URL_MALFORMAT_USER:
00726 err = " Bad URL";
00727 case CURLE_HTTP_RETURNED_ERROR:
00728 {
00729 long httpReturnCode = 0;
00730 CURLcode infoRet = curl_easy_getinfo( _curl,
00731 CURLINFO_RESPONSE_CODE,
00732 &httpReturnCode );
00733 if ( infoRet == CURLE_OK ) {
00734 string msg = "HTTP response: " +
00735 str::numstring( httpReturnCode );
00736 if ( httpReturnCode == 401 )
00737 {
00738 err = " Login failed";
00739 }
00740 else
00741 if ( httpReturnCode == 404)
00742 {
00743 ZYPP_THROW(MediaFileNotFoundException(_url, filename));
00744 }
00745
00746 msg += err;
00747 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00748 ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00749 }
00750 else
00751 {
00752 string msg = "Unable to retrieve HTTP response:";
00753 msg += err;
00754 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00755 ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00756 }
00757 }
00758 break;
00759 case CURLE_FTP_COULDNT_RETR_FILE:
00760 case CURLE_FTP_ACCESS_DENIED:
00761 err = "File not found";
00762 err_file_not_found = true;
00763 break;
00764 case CURLE_BAD_PASSWORD_ENTERED:
00765 case CURLE_FTP_USER_PASSWORD_INCORRECT:
00766 err = "Login failed";
00767 break;
00768 case CURLE_COULDNT_RESOLVE_PROXY:
00769 case CURLE_COULDNT_RESOLVE_HOST:
00770 case CURLE_COULDNT_CONNECT:
00771 case CURLE_FTP_CANT_GET_HOST:
00772 err = "Connection failed";
00773 break;
00774 case CURLE_WRITE_ERROR:
00775 err = "Write error";
00776 break;
00777 case CURLE_ABORTED_BY_CALLBACK:
00778 err = "User abort";
00779 break;
00780 case CURLE_SSL_PEER_CERTIFICATE:
00781 default:
00782 err = "Unrecognized error";
00783 break;
00784 }
00785 if( err_file_not_found)
00786 {
00787 ZYPP_THROW(MediaFileNotFoundException(_url, filename));
00788 }
00789 else
00790 {
00791 ZYPP_THROW(MediaCurlException(url, err, _curlError));
00792 }
00793 }
00794 catch (const MediaException & excpt_r)
00795 {
00796 ZYPP_RETHROW(excpt_r);
00797 }
00798 }
00799 #if DETECT_DIR_INDEX
00800 else
00801 if(curlUrl.getScheme() == "http" ||
00802 curlUrl.getScheme() == "https")
00803 {
00804
00805
00806
00807
00808
00809
00810
00811
00812 bool not_a_file = false;
00813 char *ptr = NULL;
00814 CURLcode ret = curl_easy_getinfo( _curl,
00815 CURLINFO_EFFECTIVE_URL,
00816 &ptr);
00817 if ( ret == CURLE_OK && ptr != NULL)
00818 {
00819 try
00820 {
00821 Url eurl( ptr);
00822 std::string path( eurl.getPathName());
00823 if( !path.empty() && path != "/" && *path.rbegin() == '/')
00824 {
00825 DBG << "Effective url ("
00826 << eurl
00827 << ") seems to provide the index of a directory"
00828 << endl;
00829 not_a_file = true;
00830 }
00831 }
00832 catch( ... )
00833 {}
00834 }
00835
00836 if( not_a_file)
00837 {
00838 ::fclose( file );
00839 filesystem::unlink( destNew );
00840 ZYPP_THROW(MediaNotAFileException(_url, filename));
00841 }
00842 }
00843 #endif // DETECT_DIR_INDEX
00844
00845 mode_t mask;
00846
00847
00848 mask = ::umask(0022); ::umask(mask);
00849 if ( ::fchmod( ::fileno(file), 0644 & ~mask))
00850 {
00851 ERR << "Failed to chmod file " << destNew << endl;
00852 }
00853 ::fclose( file );
00854
00855 if ( rename( destNew, dest ) != 0 ) {
00856 ERR << "Rename failed" << endl;
00857 ZYPP_THROW(MediaWriteException(dest));
00858 }
00859 }
00860
00861
00863
00864
00865
00866
00867
00868
00869
00870 void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
00871 {
00872 filesystem::DirContent content;
00873 getDirInfo( content, dirname, false );
00874
00875 for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
00876 Pathname filename = dirname + it->name;
00877 int res = 0;
00878
00879 switch ( it->type ) {
00880 case filesystem::FT_NOT_AVAIL:
00881 case filesystem::FT_FILE:
00882 getFile( filename );
00883 break;
00884 case filesystem::FT_DIR:
00885 if ( recurse_r ) {
00886 getDir( filename, recurse_r );
00887 } else {
00888 res = assert_dir( localPath( filename ) );
00889 if ( res ) {
00890 WAR << "Ignore error (" << res << ") on creating local directory '" << localPath( filename ) << "'" << endl;
00891 }
00892 }
00893 break;
00894 default:
00895
00896 break;
00897 }
00898 }
00899 }
00900
00902
00903
00904
00905
00906
00907
00908
00909 void MediaCurl::getDirInfo( std::list<std::string> & retlist,
00910 const Pathname & dirname, bool dots ) const
00911 {
00912 getDirectoryYast( retlist, dirname, dots );
00913 }
00914
00916
00917
00918
00919
00920
00921
00922
00923 void MediaCurl::getDirInfo( filesystem::DirContent & retlist,
00924 const Pathname & dirname, bool dots ) const
00925 {
00926 getDirectoryYast( retlist, dirname, dots );
00927 }
00928
00930
00931
00932
00933
00934
00935
00936
00937 int MediaCurl::progressCallback( void *clientp, double dltotal, double dlnow,
00938 double ultotal, double ulnow )
00939 {
00940 callback::SendReport<DownloadProgressReport> *report
00941 = reinterpret_cast<callback::SendReport<DownloadProgressReport>*>( clientp );
00942 if (report)
00943 {
00944
00945 if (! (*report)->progress(int( dlnow * 100 / dltotal ), Url() ))
00946 return 1;
00947 }
00948 return 0;
00949 }
00950
00951
00952 }
00953 }