From 88af32e4ae8158d7d4da9b554104d0b8491dad75 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Wed, 16 Aug 2006 15:36:35 +0000 Subject: [PATCH] Implement media doesFileExists(). Current way to do that is to provide, and if t fails, it doesnt exists, but if it succeeds, then you do a transfer :-( So doesFileExists to the rescue The current implementation does a partial transfer of 100 bytes, as using NOBODY option of curl doesn't work for ftp. It can be optimized using different methods for different URL schemes. It is not yet used but it wll be used in the source probing. Marius, please give it a look when you are back. --- devel/devel.dmacvicar/Makefile.am | 5 +- devel/devel.dmacvicar/media-glob.cc | 120 ++++++++++++++++++++++++++++++++++++ zypp/media/MediaAccess.cc | 11 ++++ zypp/media/MediaAccess.h | 10 +++ zypp/media/MediaCD.cc | 5 ++ zypp/media/MediaCurl.cc | 99 +++++++++++++++++++++++++++++ zypp/media/MediaDIR.cc | 5 ++ zypp/media/MediaDISK.cc | 5 ++ zypp/media/MediaHandler.cc | 38 ++++++++++++ zypp/media/MediaHandler.h | 24 +++++++- zypp/media/MediaISO.cc | 4 ++ zypp/media/MediaManager.cc | 13 ++++ zypp/media/MediaManager.h | 6 +- zypp/media/MediaNFS.cc | 6 ++ zypp/media/MediaSMB.cc | 5 ++ 15 files changed, 353 insertions(+), 3 deletions(-) create mode 100644 devel/devel.dmacvicar/media-glob.cc diff --git a/devel/devel.dmacvicar/Makefile.am b/devel/devel.dmacvicar/Makefile.am index 3ab3bbe..b95bfd8 100644 --- a/devel/devel.dmacvicar/Makefile.am +++ b/devel/devel.dmacvicar/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in ## ################################################## -noinst_PROGRAMS = test lock testbed aj yumparser +noinst_PROGRAMS = test lock testbed aj yumparser media ## ################################################## @@ -15,6 +15,9 @@ LDADD = -L$(top_srcdir)/zypp/.libs -L$(top_srcdir)/zypp2/.libs -lzypp -lzypp2 - ## ################################################## +media_SOURCES = media-glob.cc +media_LDFLAGS = -static + test_SOURCES = zypp-keyring.cc test_LDFLAGS = -static diff --git a/devel/devel.dmacvicar/media-glob.cc b/devel/devel.dmacvicar/media-glob.cc new file mode 100644 index 0000000..89536ef --- /dev/null +++ b/devel/devel.dmacvicar/media-glob.cc @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +#include +#include +#include + +using namespace zypp; +using namespace zypp::media; +typedef std::list stringlist; +/* +** Very basic example verifier. +** +** This one does not know anything about the product, it +** just checks if /media.1 (limited to 1st CD) exists... +*/ +class MyMediaVerifier: public MediaVerifierBase +{ +private: + // std::string _productname; +public: + MyMediaVerifier(/* std::string &productname */) + : MediaVerifierBase() + //, _productname(productname) + {} + + virtual + ~MyMediaVerifier() + {} + + virtual bool + isDesiredMedia(const MediaAccessRef &ref) + { + DBG << "isDesiredMedia(): for media nr 1 " << std::endl; + + if( !ref) + DBG << "isDesiredMedia(): invalid media handle" << std::endl; + + std::list lst; + Pathname dir("/media.1"); + + DBG << "isDesiredMedia(): checking " << dir.asString() << std::endl; + + // check the product e.g. via /media.1/products as well... + try + { + if( ref) + ref->dirInfo(lst, dir, false); + } + catch(const zypp::Exception &e) + { + ZYPP_CAUGHT(e); + } + DBG << "isDesiredMedia(): media " + << (lst.empty() ? "does not contain" : "contains") + << " the " << dir.asString() << " directory." + << std::endl; + + return !lst.empty(); + } +}; + +int main(void) +{ + MediaVerifierRef verifier( + new MyMediaVerifier(/* "SUSE-Linux-CORE-i386 9" */) + ); + MediaManager mm; + media::MediaId id; + media::MediaId id2; + try + { + + //id = mm.open(zypp::Url("cd:/"), ""); + id = mm.open(zypp::Url("http://duncan.mac-vicar.com/photos/"), ""); + //mm.addVerifier( id, verifier); + mm.attach(id); + //mm.provideFile(id, Pathname("/directory.yast")); + //mm.release(id); + //mm.attach(id); + //mm.provideFile(id, Pathname("/directory.yast")); + + //void dirInfo(MediaAccessId accessId, std::list &retlist, const Pathname &dirname, bool dots = true) const; + //stringlist retlist; + //mm.dirInfo(id, retlist, "/"); + + mm.doesFileExist(id, "bateria.jpg"); + + mm.doesFileExist(id, "fdsfsd.jpg"); + + id2 = mm.open( zypp::Url("ftp://ftp.kernel.org/pub/"), ""); + mm.attach(id2); + + mm.doesFileExist(id2, "README"); + mm.doesFileExist(id2, "notExists"); + + /* + std::cout << "DirInfo: " << retlist.size() << " objects" << std::endl; + for ( stringlist::const_iterator it = retlist.begin(); it != retlist.end(); ++it) + { + std::cout << "item: " << *it << std::endl; + } + */ + } + catch(const MediaException &e) + { + ZYPP_CAUGHT(e); + } + catch( ... ) + { + // hmm... + ERR << "Catched *unknown* exception" << std::endl; + } + + return 0; +} + +// vim: set ts=2 sts=2 sw=2 ai et: diff --git a/zypp/media/MediaAccess.cc b/zypp/media/MediaAccess.cc index 7a033e2..cf3cf7f 100644 --- a/zypp/media/MediaAccess.cc +++ b/zypp/media/MediaAccess.cc @@ -371,6 +371,17 @@ MediaAccess::dirInfo( filesystem::DirContent & retlist, const Pathname & dirname _handler->dirInfo( retlist, dirname, dots ); } +// return if a file exists +bool +MediaAccess::doesFileExist( const Pathname & filename ) const +{ + if ( !_handler ) { + ZYPP_THROW(MediaNotOpenException("doesFileExist(" + filename.asString() + ")")); + } + + return _handler->doesFileExist( filename ); +} + std::ostream & MediaAccess::dumpOn( std::ostream & str ) const { diff --git a/zypp/media/MediaAccess.h b/zypp/media/MediaAccess.h index 4dd8755..aa07c5e 100644 --- a/zypp/media/MediaAccess.h +++ b/zypp/media/MediaAccess.h @@ -315,6 +315,16 @@ namespace zypp { void dirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots = true ) const; + /** + * check if a file exists + * + * Asserted that url is a file and not a dir. + * + * \throws MediaException + * + **/ + bool doesFileExist( const Pathname & filename ) const; + /** * Destructor **/ diff --git a/zypp/media/MediaCD.cc b/zypp/media/MediaCD.cc index 91b54e8..be5ddfa 100644 --- a/zypp/media/MediaCD.cc +++ b/zypp/media/MediaCD.cc @@ -853,6 +853,11 @@ namespace zypp { MediaHandler::getDirInfo( retlist, dirname, dots ); } + bool MediaCD::getDoesFileExist( const Pathname & filename ) const + { + return MediaHandler::getDoesFileExist( filename ); + } + } // namespace media } // namespace zypp // vim: set ts=8 sts=2 sw=2 ai noet: diff --git a/zypp/media/MediaCurl.cc b/zypp/media/MediaCurl.cc index 454e40f..c4e12b1 100644 --- a/zypp/media/MediaCurl.cc +++ b/zypp/media/MediaCurl.cc @@ -691,6 +691,105 @@ void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target report->finish(url, zypp::media::DownloadProgressReport::NO_ERROR, ""); } +bool MediaCurl::getDoesFileExist( const Pathname & filename ) const +{ + DBG << filename.asString() << endl; + + if(!_url.isValid()) + ZYPP_THROW(MediaBadUrlException(_url)); + + if(_url.getHost().empty()) + ZYPP_THROW(MediaBadUrlEmptyHostException(_url)); + + string path = _url.getPathName(); + if ( !path.empty() && path != "/" && *path.rbegin() == '/' && + filename.absolute() ) { + // If url has a path with trailing slash, remove the leading slash from + // the absolute file name + path += filename.asString().substr( 1, filename.asString().size() - 1 ); + } else if ( filename.relative() ) { + // Add trailing slash to path, if not already there + if ( !path.empty() && *path.rbegin() != '/' ) path += "/"; + // Remove "./" from begin of relative file name + path += filename.asString().substr( 2, filename.asString().size() - 2 ); + } else { + path += filename.asString(); + } + + Url url( _url ); + url.setPathName( path ); + + DBG << "URL: " << url.asString() << endl; + // Use URL without options and without username and passwd + // (some proxies dislike them in the URL). + // Curl seems to need the just scheme, hostname and a path; + // the rest was already passed as curl options (in attachTo). + Url curlUrl( url ); + + // Use asString + url::ViewOptions instead? + curlUrl.setUsername( "" ); + curlUrl.setPassword( "" ); + curlUrl.setPathParams( "" ); + curlUrl.setQueryString( "" ); + curlUrl.setFragment( "" ); + + // + // See also Bug #154197 and ftp url definition in RFC 1738: + // The url "ftp://user@host/foo/bar/file" contains a path, + // that is relative to the user's home. + // The url "ftp://user@host//foo/bar/file" (or also with + // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file" + // contains an absolute path. + // + string urlBuffer( curlUrl.asString()); + CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL, + urlBuffer.c_str() ); + if ( ret != 0 ) { + ZYPP_THROW(MediaCurlSetOptException(url, _curlError)); + } + + // set no data, because we only want to check if the file exists + //ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1 ); + //if ( ret != 0 ) { + // ZYPP_THROW(MediaCurlSetOptException(url, _curlError)); + //} + + // instead of returning no data with NOBODY, we return + // little data, that works with broken servers, and + // works for ftp as well, because retrieving only headers + // ftp will return always OK code ? + ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-100" ); + if ( ret != 0 ) { + ZYPP_THROW(MediaCurlSetOptException(url, _curlError)); + } + + FILE *file = ::fopen( "/dev/null", "w" ); + if ( !file ) { + ::fclose(file); + ERR << "fopen failed for /dev/null" << endl; + ZYPP_THROW(MediaWriteException("/dev/null")); + } + + ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file ); + if ( ret != 0 ) { + ::fclose(file); + ZYPP_THROW(MediaCurlSetOptException(url, _curlError)); + } + // Set callback and perform. + //ProgressData progressData(_xfer_timeout, url, &report); + //report->start(url, dest); + //if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) { + // WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;; + //} + + CURLcode ok = curl_easy_perform( _curl ); + MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl; + return ( ok = CURLE_OK ); + //if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) { + // WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;; + //} +} + void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport & report) const { DBG << filename.asString() << endl; diff --git a/zypp/media/MediaDIR.cc b/zypp/media/MediaDIR.cc index 4e8c466..f211288 100644 --- a/zypp/media/MediaDIR.cc +++ b/zypp/media/MediaDIR.cc @@ -146,5 +146,10 @@ namespace zypp { MediaHandler::getDirInfo( retlist, dirname, dots ); } + bool MediaDIR::getDoesFileExist( const Pathname & filename ) const + { + return MediaHandler::getDoesFileExist( filename ); + } + } // namespace media } // namespace zypp diff --git a/zypp/media/MediaDISK.cc b/zypp/media/MediaDISK.cc index 14d59e6..c48418a 100644 --- a/zypp/media/MediaDISK.cc +++ b/zypp/media/MediaDISK.cc @@ -421,6 +421,11 @@ namespace zypp { MediaHandler::getDirInfo( retlist, dirname, dots ); } + bool MediaDISK::getDoesFileExist( const Pathname & filename ) const + { + return MediaHandler::getDoesFileExist( filename ); + } + } // namespace media } // namespace zypp // vim: set ts=8 sts=2 sw=2 ai noet: diff --git a/zypp/media/MediaHandler.cc b/zypp/media/MediaHandler.cc index c5511d8..eb0dcc6 100644 --- a/zypp/media/MediaHandler.cc +++ b/zypp/media/MediaHandler.cc @@ -1097,6 +1097,25 @@ void MediaHandler::dirInfo( filesystem::DirContent & retlist, /////////////////////////////////////////////////////////////////// // // +// METHOD NAME : MediaHandler::doesFileExist +// METHOD TYPE : PMError +// +// DESCRIPTION : +// +bool MediaHandler::doesFileExist( const Pathname & filename ) const +{ + // TODO do some logging + if ( !isAttached() ) { + INT << "Error Not attached on doesFileExist(" << filename << ")" << endl; + ZYPP_THROW(MediaNotAttachedException(url())); + } + return getDoesFileExist( filename ); + MIL << "doesFileExist(" << filename << ")" << endl; +} + +/////////////////////////////////////////////////////////////////// +// +// // METHOD NAME : MediaHandler::getDirectoryYast // METHOD TYPE : PMError // @@ -1303,6 +1322,25 @@ void MediaHandler::getDirInfo( filesystem::DirContent & retlist, #endif } +/////////////////////////////////////////////////////////////////// +// +// +// METHOD NAME : MediaHandler::getDoesFileExist +// METHOD TYPE : PMError +// +// DESCRIPTION : Asserted that file is not a directory +// Default implementation of pure virtual. +// +bool MediaHandler::getDoesFileExist( const Pathname & filename ) const +{ + PathInfo info( localPath( filename ) ); + if( ! info.isDir() ) { + ZYPP_THROW(MediaNotAFileException(url(), localPath(filename))); + } + return info.isExist(); +} + + } // namespace media } // namespace zypp // vim: set ts=8 sts=2 sw=2 ai noet: diff --git a/zypp/media/MediaHandler.h b/zypp/media/MediaHandler.h index 31d44a4..1b3af0d 100644 --- a/zypp/media/MediaHandler.h +++ b/zypp/media/MediaHandler.h @@ -415,6 +415,16 @@ class MediaHandler { **/ virtual void getDirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots = true ) const = 0; + + /** + * check if a file exists + * + * Asserted that url is a file and not a dir. + * + * \throws MediaException + * + **/ + virtual bool getDoesFileExist( const Pathname & filename ) const = 0; protected: @@ -656,6 +666,17 @@ class MediaHandler { **/ void dirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots = true ) const; + + /** + * check if a file exists + * + * Asserted that url is a file and not a dir. + * + * \throws MediaException + * + **/ + bool doesFileExist( const Pathname & filename ) const; + }; /////////////////////////////////////////////////////////////////// @@ -669,7 +690,8 @@ class MediaHandler { virtual void getDirInfo( std::list & retlist, \ const Pathname & dirname, bool dots = true ) const; \ virtual void getDirInfo( filesystem::DirContent & retlist, \ - const Pathname & dirname, bool dots = true ) const; + const Pathname & dirname, bool dots = true ) const; \ + virtual bool getDoesFileExist( const Pathname & filename ) const; } // namespace media } // namespace zypp diff --git a/zypp/media/MediaISO.cc b/zypp/media/MediaISO.cc index 2ee7e8f..5fdd36d 100644 --- a/zypp/media/MediaISO.cc +++ b/zypp/media/MediaISO.cc @@ -284,6 +284,10 @@ namespace zypp MediaHandler::getDirInfo(retlist, dirname, dots); } + bool MediaISO::getDoesFileExist( const Pathname & filename ) const + { + return MediaHandler::getDoesFileExist( filename ); + } ////////////////////////////////////////////////////////////////// } // namespace media diff --git a/zypp/media/MediaManager.cc b/zypp/media/MediaManager.cc index 1812932..453e6df 100644 --- a/zypp/media/MediaManager.cc +++ b/zypp/media/MediaManager.cc @@ -854,6 +854,19 @@ namespace zypp } // --------------------------------------------------------------- + bool + MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const + { + MutexLock glock(g_Mutex); + ManagedMedia &ref( m_impl->findMM(accessId)); + + // FIXME: ref.checkDesired(accessId); ??? + ref.checkAttached(accessId); + + return ref.handler->doesFileExist(filename); + } + + // --------------------------------------------------------------- // STATIC time_t MediaManager::getMountTableMTime() diff --git a/zypp/media/MediaManager.h b/zypp/media/MediaManager.h index 5309eb4..49d73e2 100644 --- a/zypp/media/MediaManager.h +++ b/zypp/media/MediaManager.h @@ -776,7 +776,11 @@ namespace zypp const Pathname &dirname, bool dots = true) const; - + /** + * FIXME: see MediaAccess class. + */ + bool doesFileExist(MediaAccessId accessId, + const Pathname & filename ) const; public: /** * Get the modification time of the /etc/mtab file. diff --git a/zypp/media/MediaNFS.cc b/zypp/media/MediaNFS.cc index b1f35ce..1a6c98f 100644 --- a/zypp/media/MediaNFS.cc +++ b/zypp/media/MediaNFS.cc @@ -228,5 +228,11 @@ namespace zypp { MediaHandler::getDirInfo( retlist, dirname, dots ); } + bool MediaNFS::getDoesFileExist( const Pathname & filename ) const + { + return MediaHandler::getDoesFileExist( filename ); + } + + } // namespace media } // namespace zypp diff --git a/zypp/media/MediaSMB.cc b/zypp/media/MediaSMB.cc index 10a330f..cf17400 100644 --- a/zypp/media/MediaSMB.cc +++ b/zypp/media/MediaSMB.cc @@ -338,5 +338,10 @@ namespace zypp { MediaHandler::getDirInfo( retlist, dirname, dots ); } + bool MediaSMB::getDoesFileExist( const Pathname & filename ) const + { + return MediaHandler::getDoesFileExist( filename ); + } + } // namespace media } // namespace zypp -- 2.7.4