MediaCurl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <iostream>
00014 #include <list>
00015 
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/ExternalProgram.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/Sysconfig.h"
00020 #include "zypp/base/Gettext.h"
00021 
00022 #include "zypp/media/MediaCurl.h"
00023 #include "zypp/media/proxyinfo/ProxyInfos.h"
00024 #include "zypp/media/ProxyInfo.h"
00025 #include "zypp/media/MediaUserAuth.h"
00026 #include "zypp/thread/Once.h"
00027 #include <cstdlib>
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #include <sys/mount.h>
00031 #include <errno.h>
00032 #include <dirent.h>
00033 #include <unistd.h>
00034 #include <boost/format.hpp>
00035 
00036 #define  DETECT_DIR_INDEX       0
00037 #define  CONNECT_TIMEOUT        60
00038 #define  TRANSFER_TIMEOUT       60 * 3
00039 #define  TRANSFER_TIMEOUT_MAX   60 * 60
00040 
00041 
00042 using namespace std;
00043 using namespace zypp::base;
00044 
00045 namespace
00046 {
00047   zypp::thread::OnceFlag g_InitOnceFlag = PTHREAD_ONCE_INIT;
00048   zypp::thread::OnceFlag g_FreeOnceFlag = PTHREAD_ONCE_INIT;
00049 
00050   extern "C" void _do_free_once()
00051   {
00052     curl_global_cleanup();
00053   }
00054 
00055   extern "C" void globalFreeOnce()
00056   {
00057     zypp::thread::callOnce(g_FreeOnceFlag, _do_free_once);
00058   }
00059 
00060   extern "C" void _do_init_once()
00061   {
00062     CURLcode ret = curl_global_init( CURL_GLOBAL_ALL );
00063     if ( ret != 0 )
00064     {
00065       WAR << "curl global init failed" << endl;
00066     }
00067 
00068     //
00069     // register at exit handler ?
00070     // this may cause trouble, because we can protect it
00071     // against ourself only.
00072     // if the app sets an atexit handler as well, it will
00073     // cause a double free while the second of them runs.
00074     //
00075     //std::atexit( globalFreeOnce);
00076   }
00077 
00078   inline void globalInitOnce()
00079   {
00080     zypp::thread::callOnce(g_InitOnceFlag, _do_init_once);
00081   }
00082 
00083   int log_curl(CURL *curl, curl_infotype info,
00084                char *ptr, size_t len, void *max_lvl)
00085   {
00086     std::string pfx(" ");
00087     long        lvl = 0;
00088     switch( info)
00089     {
00090       case CURLINFO_TEXT:       lvl = 1; pfx = "*"; break;
00091       case CURLINFO_HEADER_IN:  lvl = 2; pfx = "<"; break;
00092       case CURLINFO_HEADER_OUT: lvl = 2; pfx = ">"; break;
00093       default:                                      break;
00094     }
00095     if( lvl > 0 && max_lvl != NULL && lvl <= *((long *)max_lvl))
00096     {
00097       std::string                            msg(ptr, len);
00098       std::list<std::string>                 lines;
00099       std::list<std::string>::const_iterator line;
00100       zypp::str::split(msg, std::back_inserter(lines), "\r\n");
00101       for(line = lines.begin(); line != lines.end(); ++line)
00102       {
00103         DBG << pfx << " " << *line << endl;
00104       }
00105     }
00106     return 0;
00107   }
00108 }
00109 
00110 namespace zypp {
00111   namespace media {
00112 
00113   namespace {
00114     struct ProgressData
00115     {
00116       ProgressData(const long _timeout, const zypp::Url &_url = zypp::Url(),
00117                    callback::SendReport<DownloadProgressReport> *_report=NULL)
00118         : timeout(_timeout)
00119         , reached(false)
00120         , report(_report)
00121         , ltime( time(NULL))
00122         , dload( 0)
00123         , uload( 0)
00124         , url(_url)
00125       {}
00126       long                                          timeout;
00127       bool                                          reached;
00128       callback::SendReport<DownloadProgressReport> *report;
00129       time_t                                        ltime;
00130       double                                        dload;
00131       double                                        uload;
00132       zypp::Url                                     url;
00133     };
00134   }
00135 
00136 Pathname    MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
00137 std::string MediaCurl::_agent = "Novell ZYPP Installer";
00138 
00140 
00141 static inline void escape( string & str_r,
00142                            const char char_r, const string & escaped_r ) {
00143   for ( string::size_type pos = str_r.find( char_r );
00144         pos != string::npos; pos = str_r.find( char_r, pos ) ) {
00145     str_r.replace( pos, 1, escaped_r );
00146   }
00147 }
00148 
00149 static inline string escapedPath( string path_r ) {
00150   escape( path_r, ' ', "%20" );
00151   return path_r;
00152 }
00153 
00154 static inline string unEscape( string text_r ) {
00155   char * tmp = curl_unescape( text_r.c_str(), 0 );
00156   string ret( tmp );
00157   curl_free( tmp );
00158   return ret;
00159 }
00160 
00162 //
00163 //        CLASS NAME : MediaCurl
00164 //
00166 
00167 MediaCurl::MediaCurl( const Url &      url_r,
00168                       const Pathname & attach_point_hint_r )
00169     : MediaHandler( url_r, attach_point_hint_r,
00170                     "/", // urlpath at attachpoint
00171                     true ), // does_download
00172       _curl( NULL )
00173 {
00174   _curlError[0] = '\0';
00175   _curlDebug = 0L;
00176 
00177   MIL << "MediaCurl::MediaCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00178 
00179   globalInitOnce();
00180 
00181   if( !attachPoint().empty())
00182   {
00183     PathInfo ainfo(attachPoint());
00184     Pathname apath(attachPoint() + "XXXXXX");
00185     char    *atemp = ::strdup( apath.asString().c_str());
00186     char    *atest = NULL;
00187     if( !ainfo.isDir() || !ainfo.userMayRWX() ||
00188          atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
00189     {
00190       WAR << "attach point " << ainfo.path()
00191           << " is not useable for " << url_r.getScheme() << endl;
00192       setAttachPoint("", true);
00193     }
00194     else if( atest != NULL)
00195       ::rmdir(atest);
00196 
00197     if( atemp != NULL)
00198       ::free(atemp);
00199   }
00200 }
00201 
00202 void MediaCurl::setCookieFile( const Pathname &fileName )
00203 {
00204   _cookieFile = fileName;
00205 }
00206 
00208 //
00209 //
00210 //        METHOD NAME : MediaCurl::attachTo
00211 //        METHOD TYPE : PMError
00212 //
00213 //        DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
00214 //
00215 void MediaCurl::attachTo (bool next)
00216 {
00217   if ( next )
00218     ZYPP_THROW(MediaNotSupportedException(_url));
00219 
00220   if ( !_url.isValid() )
00221     ZYPP_THROW(MediaBadUrlException(_url));
00222 
00223   curl_version_info_data *curl_info = NULL;
00224   curl_info = curl_version_info(CURLVERSION_NOW);
00225   // curl_info does not need any free (is static)
00226   if (curl_info->protocols)
00227   {
00228     const char * const *proto;
00229     std::string        scheme( _url.getScheme());
00230     bool               found = false;
00231     for(proto=curl_info->protocols; !found && *proto; ++proto)
00232     {
00233       if( scheme == std::string((const char *)*proto))
00234         found = true;
00235     }
00236     if( !found)
00237     {
00238       std::string msg("Unsupported protocol '");
00239       msg += scheme;
00240       msg += "'";
00241       ZYPP_THROW(MediaBadUrlException(_url, msg));
00242     }
00243   }
00244 
00245   if( !isUseableAttachPoint(attachPoint()))
00246   {
00247     std::string mountpoint = createAttachPoint().asString();
00248 
00249     if( mountpoint.empty())
00250       ZYPP_THROW( MediaBadAttachPointException(url()));
00251 
00252     setAttachPoint( mountpoint, true);
00253   }
00254 
00255   disconnectFrom(); // clean _curl if needed
00256   _curl = curl_easy_init();
00257   if ( !_curl ) {
00258     ZYPP_THROW(MediaCurlInitException(_url));
00259   }
00260 
00261   {
00262     char *ptr = getenv("ZYPP_MEDIA_CURL_DEBUG");
00263     _curlDebug = (ptr && *ptr) ? str::strtonum<long>( ptr) : 0L;
00264     if( _curlDebug > 0)
00265     {
00266       curl_easy_setopt( _curl, CURLOPT_VERBOSE, 1);
00267       curl_easy_setopt( _curl, CURLOPT_DEBUGFUNCTION, log_curl);
00268       curl_easy_setopt( _curl, CURLOPT_DEBUGDATA, &_curlDebug);
00269     }
00270   }
00271 
00272   CURLcode ret = curl_easy_setopt( _curl, CURLOPT_ERRORBUFFER, _curlError );
00273   if ( ret != 0 ) {
00274     disconnectFrom();
00275     ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer"));
00276   }
00277 
00278   ret = curl_easy_setopt( _curl, CURLOPT_FAILONERROR, true );
00279   if ( ret != 0 ) {
00280     disconnectFrom();
00281     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00282   }
00283 
00284   ret = curl_easy_setopt( _curl, CURLOPT_NOSIGNAL, 1 );
00285   if ( ret != 0 ) {
00286     disconnectFrom();
00287     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00288   }
00289 
00293   {
00294     _xfer_timeout = TRANSFER_TIMEOUT;
00295 
00296     std::string param(_url.getQueryParam("timeout"));
00297     if( !param.empty())
00298     {
00299       long num = str::strtonum<long>( param);
00300       if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX)
00301         _xfer_timeout = num;
00302     }
00303   }
00304 
00305   /*
00306   ** Connect timeout
00307   */
00308   ret = curl_easy_setopt( _curl, CURLOPT_CONNECTTIMEOUT, CONNECT_TIMEOUT);
00309   if ( ret != 0 ) {
00310     disconnectFrom();
00311     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00312   }
00313 
00314   if ( _url.getScheme() == "http" ) {
00315     // follow any Location: header that the server sends as part of
00316     // an HTTP header (#113275)
00317     ret = curl_easy_setopt ( _curl, CURLOPT_FOLLOWLOCATION, true );
00318     if ( ret != 0) {
00319       disconnectFrom();
00320       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00321     }
00322     ret = curl_easy_setopt ( _curl, CURLOPT_MAXREDIRS, 3L );
00323     if ( ret != 0) {
00324       disconnectFrom();
00325       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00326     }
00327     ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, _agent.c_str() );
00328     if ( ret != 0) {
00329       disconnectFrom();
00330       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00331     }
00332   }
00333 
00334   if ( _url.getScheme() == "https" )
00335   {
00336     bool verify_peer = false;
00337     bool verify_host = false;
00338 
00339     std::string verify( _url.getQueryParam("ssl_verify"));
00340     if( verify.empty() ||
00341         verify == "yes")
00342     {
00343       verify_peer = true;
00344       verify_host = true;
00345     }
00346     else
00347     if( verify == "no")
00348     {
00349       verify_peer = false;
00350       verify_host = false;
00351     }
00352     else
00353     {
00354       std::vector<std::string>                 flags;
00355       std::vector<std::string>::const_iterator flag;
00356       str::split( verify, std::back_inserter(flags), ",");
00357       for(flag = flags.begin(); flag != flags.end(); ++flag)
00358       {
00359         if( *flag == "host")
00360         {
00361           verify_host = true;
00362         }
00363         else
00364         if( *flag == "peer")
00365         {
00366           verify_peer = true;
00367         }
00368         else
00369         {
00370                 disconnectFrom();
00371           ZYPP_THROW(MediaBadUrlException(_url, "Unknown ssl_verify flag"));
00372         }
00373       }
00374     }
00375 
00376     _ca_path = Pathname(_url.getQueryParam("ssl_capath")).asString();
00377     if( _ca_path.empty())
00378     {
00379         _ca_path = "/etc/ssl/certs/";
00380     }
00381     else
00382     if( !PathInfo(_ca_path).isDir() || !Pathname(_ca_path).absolute())
00383     {
00384         disconnectFrom();
00385         ZYPP_THROW(MediaBadUrlException(_url, "Invalid ssl_capath path"));
00386     }
00387 
00388     if( verify_peer || verify_host)
00389     {
00390       ret = curl_easy_setopt( _curl, CURLOPT_CAPATH, _ca_path.c_str());
00391       if ( ret != 0 ) {
00392         disconnectFrom();
00393         ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00394       }
00395     }
00396 
00397     ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYPEER, verify_peer ? 1L : 0L);
00398     if ( ret != 0 ) {
00399       disconnectFrom();
00400       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00401     }
00402     ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L);
00403     if ( ret != 0 ) {
00404       disconnectFrom();
00405       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00406     }
00407 
00408     ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, _agent.c_str() );
00409     if ( ret != 0) {
00410       disconnectFrom();
00411       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00412     }
00413   }
00414 
00415 
00416   /*---------------------------------------------------------------*
00417    CURLOPT_USERPWD: [user name]:[password]
00418 
00419    Url::username/password -> CURLOPT_USERPWD
00420    If not provided, anonymous FTP identification
00421    *---------------------------------------------------------------*/
00422 
00423   if ( _url.getUsername().empty() ) {
00424     if ( _url.getScheme() == "ftp" ) {
00425       string id = "yast2@";
00426       id += VERSION;
00427       DBG << "Anonymous FTP identification: '" << id << "'" << endl;
00428       _userpwd = "anonymous:" + id;
00429     }
00430   } else {
00431     _userpwd = _url.getUsername();
00432     if ( _url.getPassword().size() ) {
00433       _userpwd += ":" + _url.getPassword();
00434     }
00435   }
00436 
00437   if ( _userpwd.size() ) {
00438     _userpwd = unEscape( _userpwd );
00439     ret = curl_easy_setopt( _curl, CURLOPT_USERPWD, _userpwd.c_str() );
00440     if ( ret != 0 ) {
00441       disconnectFrom();
00442       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00443     }
00444 
00445     // HTTP authentication type
00446     if(_url.getScheme() == "http" || _url.getScheme() == "https")
00447     {
00448       string use_auth = _url.getQueryParam("auth");
00449       if( use_auth.empty())
00450         use_auth = "digest,basic";
00451 
00452       try
00453       {
00454         long auth = CurlAuthData::auth_type_str2long(use_auth);
00455         if( auth != CURLAUTH_NONE)
00456         {
00457           DBG << "Enabling HTTP authentication methods: " << use_auth
00458               << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
00459 
00460           ret = curl_easy_setopt( _curl, CURLOPT_HTTPAUTH, auth);
00461           if ( ret != 0 ) {
00462             disconnectFrom();
00463             ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00464           }
00465         }
00466       }
00467       catch (MediaException & ex_r)
00468       {
00469         string auth_hint = getAuthHint();
00470 
00471         DBG << "Rethrowing as MediaUnauthorizedException. auth hint: '"
00472             << auth_hint << "'" << endl;
00473 
00474         ZYPP_THROW(MediaUnauthorizedException(
00475           _url, ex_r.msg(), _curlError, auth_hint
00476         ));
00477       }
00478     }
00479   }
00480 
00481   /*---------------------------------------------------------------*
00482    CURLOPT_PROXY: host[:port]
00483 
00484    Url::option(proxy and proxyport) -> CURLOPT_PROXY
00485    If not provided, /etc/sysconfig/proxy is evaluated
00486    *---------------------------------------------------------------*/
00487 
00488   _proxy = _url.getQueryParam( "proxy" );
00489 
00490   if ( ! _proxy.empty() ) {
00491     string proxyport( _url.getQueryParam( "proxyport" ) );
00492     if ( ! proxyport.empty() ) {
00493       _proxy += ":" + proxyport;
00494     }
00495   } else {
00496 
00497     ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy")));
00498 
00499     if ( proxy_info.enabled())
00500     {
00501       bool useproxy = true;
00502 
00503       std::list<std::string> nope = proxy_info.noProxy();
00504       for (ProxyInfo::NoProxyIterator it = proxy_info.noProxyBegin();
00505            it != proxy_info.noProxyEnd();
00506            it++)
00507       {
00508         std::string host( str::toLower(_url.getHost()));
00509         std::string temp( str::toLower(*it));
00510 
00511         // no proxy if it points to a suffix
00512         // preceeded by a '.', that maches
00513         // the trailing portion of the host.
00514         if( temp.size() > 1 && temp.at(0) == '.')
00515         {
00516           if(host.size() > temp.size() &&
00517              host.compare(host.size() - temp.size(), temp.size(), temp) == 0)
00518           {
00519             DBG << "NO_PROXY: '" << *it  << "' matches host '"
00520                                  << host << "'" << endl;
00521             useproxy = false;
00522             break;
00523           }
00524         }
00525         else
00526         // no proxy if we have an exact match
00527         if( host == temp)
00528         {
00529           DBG << "NO_PROXY: '" << *it  << "' matches host '"
00530                                << host << "'" << endl;
00531           useproxy = false;
00532           break;
00533         }
00534       }
00535 
00536       if ( useproxy ) {
00537         _proxy = proxy_info.proxy(_url.getScheme());
00538       }
00539     }
00540   }
00541 
00542 
00543   DBG << "Proxy: " << (_proxy.empty() ? "-none-" : _proxy) << endl;
00544 
00545   if ( ! _proxy.empty() ) {
00546 
00547     ret = curl_easy_setopt( _curl, CURLOPT_PROXY, _proxy.c_str() );
00548     if ( ret != 0 ) {
00549       disconnectFrom();
00550       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00551     }
00552 
00553     /*---------------------------------------------------------------*
00554      CURLOPT_PROXYUSERPWD: [user name]:[password]
00555 
00556      Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
00557      If not provided, $HOME/.curlrc is evaluated
00558      *---------------------------------------------------------------*/
00559 
00560     _proxyuserpwd = _url.getQueryParam( "proxyuser" );
00561 
00562     if ( ! _proxyuserpwd.empty() ) {
00563 
00564       string proxypassword( _url.getQueryParam( "proxypassword" ) );
00565       if ( ! proxypassword.empty() ) {
00566         _proxyuserpwd += ":" + proxypassword;
00567       }
00568 
00569     } else {
00570       char *home = getenv("HOME");
00571       if( home && *home)
00572       {
00573               Pathname curlrcFile = string( home ) + string( "/.curlrc" );
00574 
00575         PathInfo h_info(string(home), PathInfo::LSTAT);
00576         PathInfo c_info(curlrcFile,   PathInfo::LSTAT);
00577 
00578         if( h_info.isDir()  && h_info.owner() == getuid() &&
00579             c_info.isFile() && c_info.owner() == getuid())
00580         {
00581                 map<string,string> rc_data = base::sysconfig::read( curlrcFile );
00582 
00583                 map<string,string>::const_iterator it = rc_data.find("--proxy-user");
00584                 if (it != rc_data.end())
00585             _proxyuserpwd = it->second;
00586 
00587           DBG << "got proxy userpwd (--proxy-user) from ~/culrc" << endl;
00588         }
00589         else
00590         {
00591           WAR << "Not allowed to parse '" << curlrcFile
00592               << "': bad file owner" << std::endl;
00593         }
00594       }
00595     }
00596 
00597     _proxyuserpwd = unEscape( _proxyuserpwd );
00598     ret = curl_easy_setopt( _curl, CURLOPT_PROXYUSERPWD, _proxyuserpwd.c_str() );
00599     if ( ret != 0 ) {
00600       disconnectFrom();
00601       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00602     }
00603   }
00604 
00605   /*---------------------------------------------------------------*
00606    *---------------------------------------------------------------*/
00607 
00608   _currentCookieFile = _cookieFile.asString();
00609 
00610   ret = curl_easy_setopt( _curl, CURLOPT_COOKIEFILE,
00611                           _currentCookieFile.c_str() );
00612   if ( ret != 0 ) {
00613     disconnectFrom();
00614     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00615   }
00616 
00617   ret = curl_easy_setopt( _curl, CURLOPT_COOKIEJAR,
00618                           _currentCookieFile.c_str() );
00619   if ( ret != 0 ) {
00620     disconnectFrom();
00621     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00622   }
00623 
00624   ret = curl_easy_setopt( _curl, CURLOPT_PROGRESSFUNCTION,
00625                           &progressCallback );
00626   if ( ret != 0 ) {
00627     disconnectFrom();
00628     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00629   }
00630 
00631   ret = curl_easy_setopt( _curl, CURLOPT_NOPROGRESS, false );
00632   if ( ret != 0 ) {
00633     disconnectFrom();
00634     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00635   }
00636 
00637   // FIXME: need a derived class to propelly compare url's
00638   MediaSourceRef media( new MediaSource(_url.getScheme(), _url.asString()));
00639   setMediaSource(media);
00640 }
00641 
00642 bool
00643 MediaCurl::checkAttachPoint(const Pathname &apoint) const
00644 {
00645   return MediaHandler::checkAttachPoint( apoint, true, true);
00646 }
00647 
00649 //
00650 //
00651 //        METHOD NAME : MediaCurl::disconnectFrom
00652 //        METHOD TYPE : PMError
00653 //
00654 void MediaCurl::disconnectFrom()
00655 {
00656   if ( _curl )
00657   {
00658     curl_easy_cleanup( _curl );
00659     _curl = NULL;
00660   }
00661 }
00662 
00664 //
00665 //
00666 //        METHOD NAME : MediaCurl::releaseFrom
00667 //        METHOD TYPE : PMError
00668 //
00669 //        DESCRIPTION : Asserted that media is attached.
00670 //
00671 void MediaCurl::releaseFrom( bool eject )
00672 {
00673   disconnect();
00674 }
00675 
00676 
00678 //
00679 //        METHOD NAME : MediaCurl::getFile
00680 //        METHOD TYPE : PMError
00681 //
00682 
00683 void MediaCurl::getFile( const Pathname & filename ) const
00684 {
00685     // Use absolute file name to prevent access of files outside of the
00686     // hierarchy below the attach point.
00687     getFileCopy(filename, localPath(filename).absolutename());
00688 }
00689 
00690 
00691 void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target) const
00692 {
00693   callback::SendReport<DownloadProgressReport> report;
00694 
00695   Url url( _url );
00696 
00697   bool retry = false;
00698   CurlAuthData auth_data;
00699 
00700   do
00701   {
00702     try
00703     {
00704       doGetFileCopy(filename, target, report);
00705       retry = false;
00706     }
00707     // retry with proper authentication data
00708     catch (MediaUnauthorizedException & ex_r)
00709     {
00710       callback::SendReport<AuthenticationReport> auth_report;
00711 
00712       if (!_url.getUsername().empty() && !retry)
00713         auth_data.setUserName(_url.getUsername());
00714 
00715       string prompt_msg;
00716       if (retry || !_url.getUsername().empty())
00717         prompt_msg = _("Invalid user name or password.");
00718       else // first prompt
00719         prompt_msg = boost::str(boost::format(
00720           _("Authentication required for '%s'")) % _url.asString());
00721 
00722       // set available authentication types from the exception
00723       auth_data.setAuthType(ex_r.hint());
00724 
00725       if (auth_report->prompt(_url, prompt_msg, auth_data))
00726       {
00727         DBG << "callback answer: retry" << endl
00728             << "CurlAuthData: " << auth_data << endl;
00729 
00730         if (auth_data.valid()) {
00731           _userpwd = auth_data.getUserPwd();
00732 
00733           // set username and password
00734           CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _userpwd.c_str());
00735           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00736 
00737           // set auth type
00738           ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, auth_data.authType());
00739           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00740         }
00741 
00742         retry = true;
00743       }
00744       else
00745       {
00746         DBG << "callback answer: cancel" << endl;
00747         report->finish(url, zypp::media::DownloadProgressReport::ACCESS_DENIED, ex_r.asUserString());
00748         ZYPP_RETHROW(ex_r);
00749       }
00750     }
00751     // unexpected exception
00752     catch (MediaException & excpt_r)
00753     {
00754       // FIXME: this will not match the first URL
00755       // FIXME: error number fix
00756       report->finish(url, zypp::media::DownloadProgressReport::ERROR, excpt_r.asUserString());
00757       ZYPP_RETHROW(excpt_r);
00758     }
00759   }
00760   while (retry);
00761 
00762   report->finish(url, zypp::media::DownloadProgressReport::NO_ERROR, "");
00763 }
00764 
00765 bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
00766 {
00767   bool retry = false;
00768   CurlAuthData auth_data;
00769 
00770   do
00771   {
00772     try
00773     {
00774       return doGetDoesFileExist( filename );
00775     }
00776     // authentication problem, retry with proper authentication data
00777     catch (MediaUnauthorizedException & ex_r)
00778     {
00779       callback::SendReport<AuthenticationReport> auth_report;
00780 
00781       if (!_url.getUsername().empty() && !retry)
00782         auth_data.setUserName(_url.getUsername());
00783 
00784       string prompt_msg;
00785       if (retry || !_url.getUsername().empty())
00786         prompt_msg = _("Invalid user name or password.");
00787       else // first prompt
00788         prompt_msg = boost::str(boost::format(
00789           _("Authentication required for '%s'")) % _url.asString());
00790 
00791       // set available authentication types from the exception
00792       auth_data.setAuthType(ex_r.hint());
00793 
00794       if (auth_report->prompt(_url, prompt_msg, auth_data))
00795       {
00796         DBG << "callback answer: retry" << endl
00797             << "CurlAuthData: " << auth_data << endl;
00798 
00799         if (auth_data.valid()) {
00800           _userpwd = auth_data.getUserPwd();
00801 
00802           // set username and password
00803           CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _userpwd.c_str());
00804           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00805 
00806           // set auth type
00807           ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, auth_data.authType());
00808           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00809         }
00810 
00811         retry = true;
00812       }
00813       else
00814       {
00815         DBG << "callback answer: cancel" << endl;
00816         ZYPP_RETHROW(ex_r);
00817       }
00818     }
00819     // unexpected exception
00820     catch (MediaException & excpt_r)
00821     {
00822       ZYPP_RETHROW(excpt_r);
00823     }
00824   }
00825   while (retry);
00826 
00827   return false;
00828 }
00829 
00830 bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
00831 {
00832   DBG << filename.asString() << endl;
00833 
00834   if(!_url.isValid())
00835     ZYPP_THROW(MediaBadUrlException(_url));
00836 
00837   if(_url.getHost().empty())
00838     ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
00839 
00840   string path = _url.getPathName();
00841   if ( !path.empty() && path != "/" && *path.rbegin() == '/' &&
00842         filename.absolute() ) {
00843       // If url has a path with trailing slash, remove the leading slash from
00844       // the absolute file name
00845     path += filename.asString().substr( 1, filename.asString().size() - 1 );
00846   } else if ( filename.relative() ) {
00847       // Add trailing slash to path, if not already there
00848     if ( !path.empty() && *path.rbegin() != '/' ) path += "/";
00849     // Remove "./" from begin of relative file name
00850     path += filename.asString().substr( 2, filename.asString().size() - 2 );
00851   } else {
00852     path += filename.asString();
00853   }
00854 
00855   Url url( _url );
00856   url.setPathName( path );
00857 
00858   DBG << "URL: " << url.asString() << endl;
00859     // Use URL without options and without username and passwd
00860     // (some proxies dislike them in the URL).
00861     // Curl seems to need the just scheme, hostname and a path;
00862     // the rest was already passed as curl options (in attachTo).
00863   Url curlUrl( url );
00864 
00865     // Use asString + url::ViewOptions instead?
00866   curlUrl.setUsername( "" );
00867   curlUrl.setPassword( "" );
00868   curlUrl.setPathParams( "" );
00869   curlUrl.setQueryString( "" );
00870   curlUrl.setFragment( "" );
00871 
00872   //
00873     // See also Bug #154197 and ftp url definition in RFC 1738:
00874     // The url "ftp://user@host/foo/bar/file" contains a path,
00875     // that is relative to the user's home.
00876     // The url "ftp://user@host//foo/bar/file" (or also with
00877     // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
00878     // contains an absolute path.
00879   //
00880   string urlBuffer( curlUrl.asString());
00881   CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
00882                                    urlBuffer.c_str() );
00883   if ( ret != 0 ) {
00884     ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00885   }
00886 
00887   // set no data, because we only want to check if the file exists
00888   //ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1 );
00889   //if ( ret != 0 ) {
00890   //    ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00891   //}
00892 
00893   // instead of returning no data with NOBODY, we return
00894   // little data, that works with broken servers, and
00895   // works for ftp as well, because retrieving only headers
00896   // ftp will return always OK code ?
00897   ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
00898   if ( ret != 0 ) {
00899       ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00900   }
00901 
00902   FILE *file = ::fopen( "/dev/null", "w" );
00903   if ( !file ) {
00904       ::fclose(file);
00905       ERR << "fopen failed for /dev/null" << endl;
00906       curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
00907       if ( ret != 0 ) {
00908           ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00909       }
00910       ZYPP_THROW(MediaWriteException("/dev/null"));
00911   }
00912 
00913   ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
00914   if ( ret != 0 ) {
00915       ::fclose(file);
00916       std::string err( _curlError);
00917       curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
00918       if ( ret != 0 ) {
00919           ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00920       }
00921       ZYPP_THROW(MediaCurlSetOptException(url, err));
00922   }
00923     // Set callback and perform.
00924   //ProgressData progressData(_xfer_timeout, url, &report);
00925   //report->start(url, dest);
00926   //if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
00927   //  WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
00928   //}
00929 
00930   CURLcode ok = curl_easy_perform( _curl );
00931   MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
00932 
00933   // reset curl settings
00934   ret = curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
00935   if ( ret != 0 )
00936   {
00937     ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00938   }
00939 
00940   if ( ok != 0 )
00941   {
00942     ::fclose( file );
00943 
00944     std::string err;
00945     try
00946     {
00947       bool err_file_not_found = false;
00948       switch ( ok )
00949       {
00950       case CURLE_FTP_COULDNT_RETR_FILE:
00951       case CURLE_FTP_ACCESS_DENIED:
00952         err_file_not_found = true;
00953         break;
00954       case CURLE_HTTP_RETURNED_ERROR:
00955         {
00956           long httpReturnCode = 0;
00957           CURLcode infoRet = curl_easy_getinfo( _curl,
00958                                                 CURLINFO_RESPONSE_CODE,
00959                                                 &httpReturnCode );
00960           if ( infoRet == CURLE_OK )
00961           {
00962             string msg = "HTTP response: " +
00963                           str::numstring( httpReturnCode );
00964             if ( httpReturnCode == 401 )
00965             {
00966               std::string auth_hint = getAuthHint();
00967 
00968               DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
00969               DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
00970 
00971               ZYPP_THROW(MediaUnauthorizedException(
00972                 url, "Login failed.", _curlError, auth_hint
00973               ));
00974             }
00975             else
00976             if ( httpReturnCode == 404)
00977             {
00978                err_file_not_found = true;
00979                break;
00980             }
00981 
00982             msg += err;
00983             DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00984             ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00985           }
00986           else
00987           {
00988             string msg = "Unable to retrieve HTTP response:";
00989             msg += err;
00990             DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00991             ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00992           }
00993         }
00994         break;
00995       case CURLE_UNSUPPORTED_PROTOCOL:
00996       case CURLE_URL_MALFORMAT:
00997       case CURLE_URL_MALFORMAT_USER:
00998       case CURLE_BAD_PASSWORD_ENTERED:
00999       case CURLE_FTP_USER_PASSWORD_INCORRECT:
01000       case CURLE_COULDNT_RESOLVE_PROXY:
01001       case CURLE_COULDNT_RESOLVE_HOST:
01002       case CURLE_COULDNT_CONNECT:
01003       case CURLE_FTP_CANT_GET_HOST:
01004       case CURLE_WRITE_ERROR:
01005       case CURLE_ABORTED_BY_CALLBACK:
01006       case CURLE_SSL_PEER_CERTIFICATE:
01007       default:
01008         err = curl_easy_strerror(ok);
01009         if (err.empty())
01010           err = "Unrecognized error";
01011         break;
01012       }
01013 
01014       if( err_file_not_found)
01015       {
01016         // file does not exists
01017         return false;
01018       }
01019       else
01020       {
01021         // there was an error
01022         ZYPP_THROW(MediaCurlException(url, string(), _curlError));
01023       }
01024     }
01025     catch (const MediaException & excpt_r)
01026     {
01027       ZYPP_RETHROW(excpt_r);
01028     }
01029   }
01030 
01031   // exists
01032   return ( ok == CURLE_OK );
01033   //if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
01034   //  WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01035   //}
01036 }
01037 
01038 void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport<DownloadProgressReport> & report) const
01039 {
01040     DBG << filename.asString() << endl;
01041 
01042     if(!_url.isValid())
01043       ZYPP_THROW(MediaBadUrlException(_url));
01044 
01045     if(_url.getHost().empty())
01046       ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
01047 
01048     string path = _url.getPathName();
01049     if ( !path.empty() && path != "/" && *path.rbegin() == '/' &&
01050          filename.absolute() ) {
01051       // If url has a path with trailing slash, remove the leading slash from
01052       // the absolute file name
01053       path += filename.asString().substr( 1, filename.asString().size() - 1 );
01054     } else if ( filename.relative() ) {
01055       // Add trailing slash to path, if not already there
01056       if (path.empty()) path = "/";
01057       else if (*path.rbegin() != '/' ) path += "/";
01058       // Remove "./" from begin of relative file name
01059       path += filename.asString().substr( 2, filename.asString().size() - 2 );
01060     } else {
01061       path += filename.asString();
01062     }
01063 
01064     Url url( _url );
01065     url.setPathName( path );
01066 
01067     Pathname dest = target.absolutename();
01068     if( assert_dir( dest.dirname() ) )
01069     {
01070       DBG << "assert_dir " << dest.dirname() << " failed" << endl;
01071       ZYPP_THROW( MediaSystemException(url, "System error on " + dest.dirname().asString()) );
01072     }
01073 
01074     DBG << "URL: " << url.asString() << endl;
01075     // Use URL without options and without username and passwd
01076     // (some proxies dislike them in the URL).
01077     // Curl seems to need the just scheme, hostname and a path;
01078     // the rest was already passed as curl options (in attachTo).
01079     Url curlUrl( url );
01080 
01081     // Use asString + url::ViewOptions instead?
01082     curlUrl.setUsername( "" );
01083     curlUrl.setPassword( "" );
01084     curlUrl.setPathParams( "" );
01085     curlUrl.setQueryString( "" );
01086     curlUrl.setFragment( "" );
01087 
01088     //
01089     // See also Bug #154197 and ftp url definition in RFC 1738:
01090     // The url "ftp://user@host/foo/bar/file" contains a path,
01091     // that is relative to the user's home.
01092     // The url "ftp://user@host//foo/bar/file" (or also with
01093     // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
01094     // contains an absolute path.
01095     //
01096     string urlBuffer( curlUrl.asString());
01097     CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
01098                                      urlBuffer.c_str() );
01099     if ( ret != 0 ) {
01100       ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01101     }
01102 
01103     string destNew = target.asString() + ".new.zypp.XXXXXX";
01104     char *buf = ::strdup( destNew.c_str());
01105     if( !buf)
01106     {
01107       ERR << "out of memory for temp file name" << endl;
01108       ZYPP_THROW(MediaSystemException(
01109         url, "out of memory for temp file name"
01110       ));
01111     }
01112 
01113     int tmp_fd = ::mkstemp( buf );
01114     if( tmp_fd == -1)
01115     {
01116       free( buf);
01117       ERR << "mkstemp failed for file '" << destNew << "'" << endl;
01118       ZYPP_THROW(MediaWriteException(destNew));
01119     }
01120     destNew = buf;
01121     free( buf);
01122 
01123     FILE *file = ::fdopen( tmp_fd, "w" );
01124     if ( !file ) {
01125       ::close( tmp_fd);
01126       filesystem::unlink( destNew );
01127       ERR << "fopen failed for file '" << destNew << "'" << endl;
01128       ZYPP_THROW(MediaWriteException(destNew));
01129     }
01130 
01131     DBG << "dest: " << dest << endl;
01132     DBG << "temp: " << destNew << endl;
01133 
01134     ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
01135     if ( ret != 0 ) {
01136       ::fclose( file );
01137       filesystem::unlink( destNew );
01138       ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01139     }
01140 
01141     // Set callback and perform.
01142     ProgressData progressData(_xfer_timeout, url, &report);
01143     report->start(url, dest);
01144     if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
01145       WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01146     }
01147 
01148     ret = curl_easy_perform( _curl );
01149 
01150     if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
01151       WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01152     }
01153 
01154     if ( ret != 0 ) {
01155       ERR << "curl error: " << ret << ": " << _curlError
01156           << ", temp file size " << PathInfo(destNew).size()
01157           << " byte." << endl;
01158 
01159       ::fclose( file );
01160       filesystem::unlink( destNew );
01161 
01162       std::string err;
01163       try {
01164        bool err_file_not_found = false;
01165        switch ( ret ) {
01166         case CURLE_UNSUPPORTED_PROTOCOL:
01167         case CURLE_URL_MALFORMAT:
01168         case CURLE_URL_MALFORMAT_USER:
01169           err = " Bad URL";
01170         case CURLE_HTTP_RETURNED_ERROR:
01171           {
01172             long httpReturnCode = 0;
01173             CURLcode infoRet = curl_easy_getinfo( _curl,
01174                                                   CURLINFO_RESPONSE_CODE,
01175                                                   &httpReturnCode );
01176             if ( infoRet == CURLE_OK ) {
01177               string msg = "HTTP response: " +
01178                            str::numstring( httpReturnCode );
01179               if ( httpReturnCode == 401 )
01180               {
01181                 std::string auth_hint = getAuthHint();
01182 
01183                 DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
01184                 DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
01185 
01186                 ZYPP_THROW(MediaUnauthorizedException(
01187                   url, "Login failed.", _curlError, auth_hint
01188                 ));
01189               }
01190               else
01191               if ( httpReturnCode == 404)
01192               {
01193                  ZYPP_THROW(MediaFileNotFoundException(_url, filename));
01194               }
01195 
01196               msg += err;
01197               DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
01198               ZYPP_THROW(MediaCurlException(url, msg, _curlError));
01199             }
01200             else
01201             {
01202               string msg = "Unable to retrieve HTTP response:";
01203               msg += err;
01204               DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
01205               ZYPP_THROW(MediaCurlException(url, msg, _curlError));
01206             }
01207           }
01208           break;
01209         case CURLE_FTP_COULDNT_RETR_FILE:
01210         case CURLE_FTP_ACCESS_DENIED:
01211           err = "File not found";
01212           err_file_not_found = true;
01213           break;
01214         case CURLE_BAD_PASSWORD_ENTERED:
01215         case CURLE_FTP_USER_PASSWORD_INCORRECT:
01216           err = "Login failed";
01217           break;
01218         case CURLE_COULDNT_RESOLVE_PROXY:
01219         case CURLE_COULDNT_RESOLVE_HOST:
01220         case CURLE_COULDNT_CONNECT:
01221         case CURLE_FTP_CANT_GET_HOST:
01222           err = "Connection failed";
01223           break;
01224         case CURLE_WRITE_ERROR:
01225           err = "Write error";
01226           break;
01227         case CURLE_ABORTED_BY_CALLBACK:
01228           if( progressData.reached)
01229           {
01230             err  = "Timeout reached";
01231           }
01232           else
01233           {
01234             err = "User abort";
01235           }
01236           break;
01237         case CURLE_SSL_PEER_CERTIFICATE:
01238         default:
01239           err = "Unrecognized error";
01240           break;
01241        }
01242        if( err_file_not_found)
01243        {
01244          ZYPP_THROW(MediaFileNotFoundException(_url, filename));
01245        }
01246        else
01247        {
01248          ZYPP_THROW(MediaCurlException(url, err, _curlError));
01249        }
01250       }
01251       catch (const MediaException & excpt_r)
01252       {
01253         ZYPP_RETHROW(excpt_r);
01254       }
01255     }
01256 #if DETECT_DIR_INDEX
01257     else
01258     if(curlUrl.getScheme() == "http" ||
01259        curlUrl.getScheme() == "https")
01260     {
01261       //
01262       // try to check the effective url and set the not_a_file flag
01263       // if the url path ends with a "/", what usually means, that
01264       // we've received a directory index (index.html content).
01265       //
01266       // Note: This may be dangerous and break file retrieving in
01267       //       case of some server redirections ... ?
01268       //
01269       bool      not_a_file = false;
01270       char     *ptr = NULL;
01271       CURLcode  ret = curl_easy_getinfo( _curl,
01272                                          CURLINFO_EFFECTIVE_URL,
01273                                          &ptr);
01274       if ( ret == CURLE_OK && ptr != NULL)
01275       {
01276         try
01277         {
01278           Url         eurl( ptr);
01279           std::string path( eurl.getPathName());
01280           if( !path.empty() && path != "/" && *path.rbegin() == '/')
01281           {
01282             DBG << "Effective url ("
01283                 << eurl
01284                 << ") seems to provide the index of a directory"
01285                 << endl;
01286             not_a_file = true;
01287           }
01288         }
01289         catch( ... )
01290         {}
01291       }
01292 
01293       if( not_a_file)
01294       {
01295         ::fclose( file );
01296         filesystem::unlink( destNew );
01297         ZYPP_THROW(MediaNotAFileException(_url, filename));
01298       }
01299     }
01300 #endif // DETECT_DIR_INDEX
01301 
01302     if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
01303     {
01304       ERR << "Failed to chmod file " << destNew << endl;
01305     }
01306     ::fclose( file );
01307 
01308     if ( rename( destNew, dest ) != 0 ) {
01309       ERR << "Rename failed" << endl;
01310       ZYPP_THROW(MediaWriteException(dest));
01311     }
01312     DBG << "done: " << PathInfo(dest) << endl;
01313 }
01314 
01315 
01317 //
01318 //
01319 //        METHOD NAME : MediaCurl::getDir
01320 //        METHOD TYPE : PMError
01321 //
01322 //        DESCRIPTION : Asserted that media is attached
01323 //
01324 void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
01325 {
01326   filesystem::DirContent content;
01327   getDirInfo( content, dirname, /*dots*/false );
01328 
01329   for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
01330       Pathname filename = dirname + it->name;
01331       int res = 0;
01332 
01333       switch ( it->type ) {
01334       case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
01335       case filesystem::FT_FILE:
01336         getFile( filename );
01337         break;
01338       case filesystem::FT_DIR: // newer directory.yast contain at least directory info
01339         if ( recurse_r ) {
01340           getDir( filename, recurse_r );
01341         } else {
01342           res = assert_dir( localPath( filename ) );
01343           if ( res ) {
01344             WAR << "Ignore error (" << res <<  ") on creating local directory '" << localPath( filename ) << "'" << endl;
01345           }
01346         }
01347         break;
01348       default:
01349         // don't provide devices, sockets, etc.
01350         break;
01351       }
01352   }
01353 }
01354 
01356 //
01357 //
01358 //        METHOD NAME : MediaCurl::getDirInfo
01359 //        METHOD TYPE : PMError
01360 //
01361 //        DESCRIPTION : Asserted that media is attached and retlist is empty.
01362 //
01363 void MediaCurl::getDirInfo( std::list<std::string> & retlist,
01364                                const Pathname & dirname, bool dots ) const
01365 {
01366   getDirectoryYast( retlist, dirname, dots );
01367 }
01368 
01370 //
01371 //
01372 //        METHOD NAME : MediaCurl::getDirInfo
01373 //        METHOD TYPE : PMError
01374 //
01375 //        DESCRIPTION : Asserted that media is attached and retlist is empty.
01376 //
01377 void MediaCurl::getDirInfo( filesystem::DirContent & retlist,
01378                             const Pathname & dirname, bool dots ) const
01379 {
01380   getDirectoryYast( retlist, dirname, dots );
01381 }
01382 
01384 //
01385 //
01386 //        METHOD NAME : MediaCurl::progressCallback
01387 //        METHOD TYPE : int
01388 //
01389 //        DESCRIPTION : Progress callback triggered from MediaCurl::getFile
01390 //
01391 int MediaCurl::progressCallback( void *clientp, double dltotal, double dlnow,
01392                                  double ultotal, double ulnow )
01393 {
01394   ProgressData *pdata = reinterpret_cast<ProgressData *>(clientp);
01395   if( pdata)
01396   {
01397     // send progress report first, abort transfer if requested
01398     if( pdata->report)
01399     {
01400       if (! (*(pdata->report))->progress(int( dlnow * 100 / dltotal ), pdata->url))
01401       {
01402         return 1; // abort transfer
01403       }
01404     }
01405 
01406     // check if we there is a timeout set
01407     if( pdata->timeout > 0)
01408     {
01409       time_t now = time(NULL);
01410       if( now > 0)
01411       {
01412         bool progress = false;
01413 
01414         // reset time of last change in case initial time()
01415         // failed or the time was adjusted (goes backward)
01416         if( pdata->ltime <= 0 || pdata->ltime > now)
01417           pdata->ltime = now;
01418 
01419         // update download data if changed, mark progress
01420         if( dlnow != pdata->dload)
01421         {
01422           progress     = true;
01423           pdata->dload = dlnow;
01424           pdata->ltime = now;
01425         }
01426         // update upload data if changed, mark progress
01427         if( ulnow != pdata->uload)
01428         {
01429           progress     = true;
01430           pdata->uload = ulnow;
01431           pdata->ltime = now;
01432         }
01433 
01434         if( !progress && (now >= (pdata->ltime + pdata->timeout)))
01435         {
01436           pdata->reached = true;
01437           return 1; // aborts transfer
01438         }
01439       }
01440     }
01441   }
01442   return 0;
01443 }
01444 
01445 string MediaCurl::getAuthHint() const
01446 {
01447   long auth_info = CURLAUTH_NONE;
01448 
01449   CURLcode infoRet =
01450     curl_easy_getinfo(_curl, CURLINFO_HTTPAUTH_AVAIL, &auth_info);
01451 
01452   if(infoRet == CURLE_OK)
01453   {
01454     return CurlAuthData::auth_type_long2str(auth_info);
01455   }
01456 
01457   return "";
01458 }
01459 
01460   } // namespace media
01461 } // namespace zypp
01462 //

Generated on Tue Sep 25 19:23:01 2007 for libzypp by  doxygen 1.5.3