AC_CHECK_HEADERS([boost/scoped_ptr.hpp],
[],
AC_MSG_ERROR([boost header not found. please install boost-devel]))
+AC_CHECK_HEADERS([curl/curl.h],
+ [],
+ AC_MSG_ERROR([libcurl header not found. please install curl-devel.]))
dnl ==================================================
dnl checks for typedefs
dnl ==================================================
zypp/parser/yum/schema/Makefile \
zypp/solver/Makefile \
zypp/source/Makefile \
- zypp/source/yum/Makefile
+ zypp/source/yum/Makefile \
+ zypp/media/Makefile \
)
dnl ==================================================
## Process this file with automake to produce Makefile.in
## ##################################################
-SUBDIRS = base parser capability solver source detail
+SUBDIRS = base parser capability solver source detail media
## ##################################################
Changelog.h \
\
ExternalProgram.h \
- Pathname.cc \
- PathInfo.cc \
- Digest.cc
+ Pathname.h \
+ PathInfo.h \
+ Digest.h
## ##################################################
capability/lib@PACKAGE@_capability.la \
solver/lib@PACKAGE@_solver.la \
parser/lib@PACKAGE@_parser.la \
- source/lib@PACKAGE@_source.la
+ source/lib@PACKAGE@_source.la \
+ media/lib@PACKAGE@_media.la \
+ -lutil
## ##################################################
include_HEADERS = \
MediaException.h \
MediaAccess.h \
- MediaHandler.h \
- MediaCurl.h
+ MediaHandler.h
+
+# MediaCurl.h
noinst_LTLIBRARIES = lib@PACKAGE@_media.la
lib@PACKAGE@_media_la_SOURCES = \
MediaAccess.cc \
- MediaHandler.cc \
- MediaCurl.cc
+ MediaHandler.cc
+
+# MediaCurl.cc
lib@PACKAGE@_media_la_LIBADD = -lcurl
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaAccess.cc
+ *
+*/
+
+#include <ctype.h>
+
+#include <iostream>
+
+#include "zypp/base/Logger.h"
+
+#include "zypp/media/MediaException.h"
+#include "zypp/media/MediaAccess.h"
+#include "zypp/media/MediaHandler.h"
+
+/*
+#include "zypp/media/MediaCD.h"
+#include "zypp/media/MediaDIR.h"
+#include "zypp/media/MediaDISK.h"
+#include "zypp/media/MediaNFS.h"
+#include "zypp/media/MediaSMB.h"
+#include "zypp/media/MediaCIFS.h"
+*/
+//#include "zypp/media/MediaCurl.h"
+
+using namespace std;
+
+namespace zypp {
+ namespace media {
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : MediaAccess
+//
+///////////////////////////////////////////////////////////////////
+
+const Pathname MediaAccess::_noPath; // empty path
+
+///////////////////////////////////////////////////////////////////
+// constructor
+MediaAccess::MediaAccess ()
+ : _handler (0)
+{
+}
+
+// destructor
+MediaAccess::~MediaAccess()
+{
+#warning FIXME uncomment
+#if 0
+ DBG << *this << endl;
+#endif
+ close(); // !!! make sure handler gets properly deleted.
+}
+
+// open URL
+void
+MediaAccess::open (const Url& url, const Pathname & preferred_attach_point)
+{
+#warning FIXME uncomment once media backends get ready
+#if 0
+ if(!url.isValid()) {
+ ERR << Error::E_bad_url << " opening " << url << endl;
+ return Error::E_bad_url;
+ }
+
+ close();
+
+ switch ( url.protocol() ) {
+ case Url::cd:
+ case Url::dvd:
+ _handler = new MediaCD (url,preferred_attach_point);
+ break;
+ case Url::nfs:
+ _handler = new MediaNFS (url,preferred_attach_point);
+ break;
+ case Url::file:
+ case Url::dir:
+ _handler = new MediaDIR (url,preferred_attach_point);
+ break;
+ case Url::hd:
+ _handler = new MediaDISK (url,preferred_attach_point);
+ break;
+ case Url::smb:
+ case Url::cifs:
+ _handler = new MediaCIFS (url,preferred_attach_point);
+ break;
+ case Url::ftp:
+ case Url::http:
+ case Url::https:
+ _handler = new MediaCurl (url,preferred_attach_point);
+ break;
+ case Url::unknown:
+ ERR << Error::E_bad_media_type << " opening " << url << endl;
+ return Error::E_bad_media_type;
+ break;
+ }
+
+ // check created handler
+ if ( !_handler ){
+ ERR << "Failed to create media handler" << endl;
+ return Error::E_system;
+ }
+
+ MIL << "Opened: " << *this << endl;
+ return Error::E_ok;
+#endif
+}
+
+// Type of media if open, otherwise NONE.
+#warning FIXME uncomment once real Url class is implemented
+#if 0
+Url::Protocol
+MediaAccess::protocol() const
+{
+ if ( !_handler )
+ return Url::unknown;
+
+ return _handler->protocol();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaAccess::url
+// METHOD TYPE : Url
+//
+Url MediaAccess::url() const
+{
+ if ( !_handler )
+ return Url();
+
+ return _handler->url();
+}
+
+// close handler
+void
+MediaAccess::close ()
+{
+ ///////////////////////////////////////////////////////////////////
+ // !!! make shure handler gets properly deleted.
+ // I.e. release attached media before deleting the handler.
+ ///////////////////////////////////////////////////////////////////
+ if ( _handler ) {
+ try {
+ _handler->release();
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME uncomment, rethrow
+#if 0
+ WAR << "Close: " << *this << " (" << err << ")" << endl;
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+#warning FIXME uncomment
+#if 0
+ MIL << "Close: " << *this << " (" << err << ")" << endl;
+#endif
+ delete _handler;
+ _handler = 0;
+ }
+}
+
+
+// attach media
+void MediaAccess::attach (bool next)
+{
+ if ( !_handler ) {
+ INT << "Error::E_not_open" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+ }
+ _handler->attach(next);
+}
+
+// True if media is open and attached.
+bool
+MediaAccess::isAttached() const
+{
+ return( _handler && _handler->isAttached() );
+}
+
+// local directory that corresponds to medias url
+// If media is not open an empty pathname.
+const Pathname &
+MediaAccess::localRoot() const
+{
+ if ( !_handler )
+ return _noPath;
+
+ return _handler->localRoot();
+}
+
+// Short for 'localRoot() + pathname', but returns an empty
+// * pathname if media is not open.
+Pathname
+MediaAccess::localPath( const Pathname & pathname ) const
+{
+ if ( !_handler )
+ return _noPath;
+
+ return _handler->localPath( pathname );
+}
+
+void
+MediaAccess::disconnect()
+{
+ if ( !_handler )
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+
+ _handler->disconnect();
+}
+
+// release attached media
+void
+MediaAccess::release( bool eject )
+{
+ if ( !_handler )
+ return;
+
+ _handler->release( eject );
+}
+
+
+// provide file denoted by path to attach dir
+//
+// filename is interpreted relative to the attached url
+// and a path prefix is preserved to destination
+void
+MediaAccess::provideFile( const Pathname & filename, bool cached, bool checkonly) const
+{
+ if ( cached ) {
+ PathInfo pi( localPath( filename ) );
+ if ( pi.isExist() )
+ return;
+ }
+
+ if(checkonly)
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_error");
+
+ if ( !_handler ) {
+ INT << "Error::E_not_open" << " on provideFile(" << filename << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+ }
+
+ _handler->provideFile( filename );
+}
+
+void
+MediaAccess::releaseFile( const Pathname & filename ) const
+{
+ if ( !_handler )
+ return;
+
+ _handler->releaseFile( filename );
+}
+
+// provide directory tree denoted by path to attach dir
+//
+// dirname is interpreted relative to the attached url
+// and a path prefix is preserved to destination
+void
+MediaAccess::provideDir( const Pathname & dirname ) const
+{
+ if ( !_handler ) {
+ INT << "Error::E_not_open" << " on provideDir(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+ }
+
+ _handler->provideDir( dirname );
+}
+
+void
+MediaAccess::provideDirTree( const Pathname & dirname ) const
+{
+ if ( !_handler ) {
+ INT << "Error::E_not_open" << " on provideDirTree(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+ }
+
+ _handler->provideDirTree( dirname );
+}
+
+void
+MediaAccess::releaseDir( const Pathname & dirname ) const
+{
+ if ( !_handler )
+ return;
+
+ _handler->releaseDir( dirname );
+}
+
+void
+MediaAccess::releasePath( const Pathname & pathname ) const
+{
+ if ( !_handler )
+ return;
+
+ _handler->releasePath( pathname );
+}
+
+// Return content of directory on media
+void
+MediaAccess::dirInfo( list<string> & retlist, const Pathname & dirname, bool dots ) const
+{
+ retlist.clear();
+
+ if ( !_handler ) {
+ INT << "Error::E_not_open" << " on dirInfo(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+ }
+
+ _handler->dirInfo( retlist, dirname, dots );
+}
+
+// Return content of directory on media
+void
+MediaAccess::dirInfo( PathInfo::dircontent & retlist, const Pathname & dirname, bool dots ) const
+{
+ retlist.clear();
+
+ if ( !_handler ) {
+ INT << "Error::E_not_open" << " on dirInfo(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_open");
+ }
+
+ _handler->dirInfo( retlist, dirname, dots );
+}
+
+std::ostream &
+MediaAccess::dumpOn( std::ostream & str ) const
+{
+ if ( !_handler )
+ return str << "MediaAccess( closed )";
+
+#warning FIXME uncomment once real Url class is implemented
+#if 0
+ string tstr = Url::protocolToString( _handler->protocol() );
+ str << tstr << "(" << *_handler << ")";
+#endif
+ return str;
+}
+
+void MediaAccess::getFile( const Url &from, const Pathname &to )
+{
+ DBG << "From: " << from << endl << "To: " << to << endl;
+
+ Pathname path
+#warning FIXME uncomment once real Url class is implemented
+#if 0
+ = from.path()
+#endif
+;
+ Pathname dir = path.dirname();
+ string base = path.basename();
+
+ Url u = from;
+#warning FIXME uncomment once real Url class is implemented
+#if 0
+ u.setPath( dir.asString() );
+#endif
+
+ MediaAccess media;
+
+ try {
+ media.open( u );
+ media.attach();
+ media._handler->provideFileCopy( base, to );
+ media.release();
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME uncomment, add message into log
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+ } // namespace media
+} // namespace zypp
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaAccess.h
+ *
+*/
+#ifndef ZYPP_MEDIA_MEDIAACCESS_H
+#define ZYPP_MEDIA_MEDIAACCESS_H
+
+#include <iosfwd>
+#include <map>
+#include <list>
+#include <string>
+
+#include "zypp/base/ReferenceCounted.h"
+#include "zypp/base/NonCopyable.h"
+#include "zypp/base/PtrTypes.h"
+
+#include "zypp/Pathname.h"
+#include "zypp/PathInfo.h"
+
+#include "zypp/media/MediaException.h"
+
+#warning FIXME use real Url class
+// #include "zypp/@Review/Url.h"
+typedef std::string Url;
+
+namespace zypp {
+ namespace media {
+
+ class MediaHandler;
+
+ ///////////////////////////////////////////////////////////////////
+ //
+ // CLASS NAME : MediaAccess
+ /**
+ * @short Handle access to a medium
+ *
+ * The concrete @ref MediaHandler for a certain url is created
+ * on @ref open and deleted on @close.
+ *
+ * The inteface here basically checks whether the handler exists,
+ * then forwards the request to @ref MediaHandler.
+ **/
+ class MediaAccess : public base::ReferenceCounted, private base::NonCopyable
+ {
+ public:
+ typedef shared_ptr<MediaAccess> Ptr;
+ typedef shared_ptr<const MediaAccess> constPtr;
+
+ private:
+
+ static const Pathname _noPath;
+
+ /**
+ * handler for 'physical' media
+ * == 0 if not open
+ **/
+ MediaHandler * _handler;
+
+ public:
+
+ /**
+ * constructor
+ **/
+ MediaAccess();
+
+ /**
+ * open url. If preferred_attach_point is given,
+ * try to use it as attach point.
+ *
+ * <b>Caution:</b> The medium can choose a different attach point.
+ * Only getAttachPoint() knows the real attach point.
+ *
+ * \throws MediaException
+ *
+ **/
+ void open( const Url& url, const Pathname & preferred_attach_point = "" );
+
+ /**
+ * True if media is open.
+ **/
+ bool isOpen() const { return( _handler != 0 ); }
+
+ /**
+ * Used Protocol if media is opened, otherwise 'unknown'.
+ **/
+#warning FIXME uncomment once real Url class is implemented
+#if 0
+ Url::Protocol protocol() const;
+#endif
+
+ /**
+ * Url if media is opened, otherwise empty.
+ **/
+ Url url() const;
+
+ /**
+ * close url
+ *
+ * \throws MediaException
+ *
+ **/
+ void close();
+
+ public:
+
+ /**
+ * Use concrete handler to attach the media.
+ *
+ * @param next try next available device in turn until end of device
+ * list is reached (for media which are accessible through multiple
+ * devices like cdroms).
+ *
+ * \throws MediaException
+ *
+ **/
+ void attach(bool next = false);
+
+ /**
+ * True if media is attached.
+ *
+ * \throws MediaException
+ *
+ **/
+ bool isAttached() const;
+
+ /**
+ * Return the local directory that corresponds to medias url,
+ * no matter if media isAttached or not. Files requested will
+ * be available at 'localRoot() + filename' or better
+ * 'localPath( filename )'.
+ *
+ * If media is not open an empty pathname is returned.
+ **/
+ const Pathname & localRoot() const;
+
+ /**
+ * Short for 'localRoot() + pathname', but returns an empty
+ * pathname if media is not open.
+ *
+ * Files provided will be available at 'localPath(filename)'.
+ **/
+ Pathname localPath( const Pathname & pathname ) const;
+
+ /**
+ Use concrete handler to disconnect the media.
+
+ This is useful for media which e.g. holds open a connection to a
+ server like FTP. After calling disconnect() the media object still is
+ valid and files are present.
+
+ After calling disconnect() it's not possible to call provideFile() or
+ provideDir() anymore.
+ *
+ * \throws MediaException
+ *
+ */
+ void disconnect();
+
+ /**
+ * Use concrete handler to release the media.
+ * @param eject if true, physically eject the media * (i.e. CD-ROM)
+ *
+ * \throws MediaException
+ *
+ **/
+ void release( bool eject = false );
+
+ /**
+ * Use concrete handler to provide file denoted by path below
+ * 'attach point'. Filename is interpreted relative to the
+ * attached url and a path prefix is preserved.
+ *
+ * @param cached If cached is set to true, the function checks, if
+ * the file already exists and doesn't download it again
+ * if it does. Currently only the existence is checked,
+ * no other file attributes.
+ * @param checkonly If this and 'cached' are set to true only the
+ * existence of the file is checked but it's not
+ * downloaded. If 'cached' is unset an errer is
+ * returned always.
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideFile( const Pathname & filename, bool cached = false, bool checkonly = false ) const;
+
+ /**
+ * Remove filename below attach point IFF handler downloads files
+ * to the local filesystem. Never remove anything from media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void releaseFile( const Pathname & filename ) const;
+
+ /**
+ * Use concrete handler to provide directory denoted
+ * by path below 'attach point' (not recursive!).
+ * 'dirname' is interpreted relative to the
+ * attached url and a path prefix is preserved.
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideDir( const Pathname & dirname ) const;
+
+ /**
+ * Use concrete handler to provide directory tree denoted
+ * by path below 'attach point' (recursive!!).
+ * 'dirname' is interpreted relative to the
+ * attached url and a path prefix is preserved.
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideDirTree( const Pathname & dirname ) const;
+
+ /**
+ * Remove directory tree below attach point IFF handler downloads files
+ * to the local filesystem. Never remove anything from media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void releaseDir( const Pathname & dirname ) const;
+
+ /**
+ * Remove pathname below attach point IFF handler downloads files
+ * to the local filesystem. Never remove anything from media.
+ *
+ * If pathname denotes a directory it is recursively removed.
+ * If pathname is empty or '/' everything below the attachpoint
+ * is recursively removed.
+ *
+ * \throws MediaException
+ *
+ **/
+ void releasePath( const Pathname & pathname ) const;
+
+ public:
+
+ /**
+ * Return content of directory on media via retlist. If dots is false
+ * entries starting with '.' are not reported.
+ *
+ * The request is forwarded to the concrete handler,
+ * which may atempt to retieve the content e.g. via 'readdir'
+ *
+ * <B>Caution:</B> This is not supported by all media types.
+ * Be prepared to handle E_not_supported_by_media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void dirInfo( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots = true ) const;
+
+ /**
+ * Basically the same as dirInfo above. The content is returned as
+ * PathInfo::dircontent, which includes name and filetype of each directory
+ * entry. Retrieving the filetype usg. requires an additional ::stat call for
+ * each entry, thus it's more expensive than a simple readdir.
+ *
+ * <B>Caution:</B> This is not supported by all media types.
+ * Be prepared to handle E_not_supported_by_media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void dirInfo( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots = true ) const;
+
+ /**
+ * Destructor
+ **/
+ virtual ~MediaAccess();
+
+ public:
+
+ virtual std::ostream & dumpOn( std::ostream & str ) const;
+
+ public:
+ /**
+ * Get file from location at specified by URL and copy it to
+ * destination.
+ *
+ * @param from Source URL
+ * @param to Destination file name
+ *
+ * \throws MediaException
+ *
+ **/
+ void getFile( const Url &from, const Pathname &to );
+
+ public:
+
+ /**
+ * Helper class that provides file on construction
+ * and cleans up on destruction.
+ *
+ * <b>Caution:</b> There's no synchronisation between multiple
+ * FileProvider instances, that provide the same file from the
+ * same media. If the first one goes out of scope, the file is
+ * cleaned. It's just a convenience for 'access and forgett'.
+ *
+ * <b>Caution:</b> We should either store the reference MediaAccess'
+ * MediaHandler here (for this MediaHandler must become a
+ * ref counting pointer class), or we need more info from MediaHandler
+ * (whether he's downloading to the local fs. If not, no releasefile
+ * is necessary).
+ * Currently we can not releaseFile after the media was closed
+ * (it's passed to the handler, which is deleted on close).
+ *
+ * \throws MediaException
+ **/
+ class FileProvider {
+ FileProvider( const FileProvider & ); // no copy
+ FileProvider & operator=( const FileProvider & ); // no assign
+ private:
+ MediaAccess::constPtr _media;
+ Pathname _file;
+ Pathname _local_file;
+ public:
+ /**
+ * \throws MediaException
+ */
+ FileProvider( MediaAccess::constPtr media_r, const Pathname & file_r )
+ : _media( media_r )
+ , _file( file_r )
+ , _local_file( "" )
+ {
+ if ( _file.empty() ) {
+ throw MediaException(ZYPP_EX_CODELOCATION, "E_bad_filename");
+ } else if ( _media ) {
+ try {
+ _media->provideFile( _file );
+ _local_file = _media->localPath( _file );
+ }
+ catch (const MediaException & excpt_r)
+ {
+ _media.reset();
+#warning FIXME rethrow the exception
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ }
+ }
+
+ ~FileProvider() {
+ if ( _media )
+ {
+ try {
+ _media->releaseFile( _file );
+ }
+ catch (const MediaException &excpt_r)
+ {
+ INT << "Exception raised while releasing file" << std::endl;
+ }
+ }
+ }
+
+ public:
+
+ /**
+ * If no error, expect operator() to return the local
+ * Pathname of the provided file.
+ **/
+ Pathname localFile() const { return _local_file; }
+
+ /**
+ * Return the local Pathname of the provided file or
+ * an empty Pathname on error.
+ **/
+ Pathname operator()() const {
+ if ( _media )
+ return _media->localPath( _file );
+ return Pathname();
+ }
+ };
+ };
+
+///////////////////////////////////////////////////////////////////
+
+ } // namespace media
+} // namespace zypp
+
+#endif // ZYPP_MEDIA_MEDIAACCESS_H
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaCurl.cc
+ *
+*/
+
+#include <iostream>
+
+#include "zypp/base/Logger.h"
+#include "zypp/ExternalProgram.h"
+#include "zypp/base/stringutil.h"
+//#include <y2util/SysConfig.h>
+
+#include "zypp/media/MediaCurl.h"
+//#include "zypp/media/MediaCallbacks.h"
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include "config.h"
+
+using namespace std;
+using namespace zypp::base;
+//using namespace MediaCallbacks;
+
+namespace zypp {
+ namespace media {
+
+Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
+
+MediaCurl::Callbacks *MediaCurl::_callbacks = 0;
+
+bool MediaCurl::_globalInit = false;
+
+///////////////////////////////////////////////////////////////////
+
+static inline void escape( string & str_r,
+ const char char_r, const string & escaped_r ) {
+ for ( string::size_type pos = str_r.find( char_r );
+ pos != string::npos; pos = str_r.find( char_r, pos ) ) {
+ str_r.replace( pos, 1, escaped_r );
+ }
+}
+
+static inline string escapedPath( string path_r ) {
+ escape( path_r, ' ', "%20" );
+ return path_r;
+}
+
+static inline string unEscape( string text_r ) {
+ char * tmp = curl_unescape( text_r.c_str(), 0 );
+ string ret( tmp );
+ curl_free( tmp );
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : MediaCurl
+//
+///////////////////////////////////////////////////////////////////
+
+MediaCurl::MediaCurl( const Url & url_r,
+ const Pathname & attach_point_hint_r )
+ : MediaHandler( url_r, attach_point_hint_r,
+ "/", // urlpath at attachpoint
+ true ), // does_download
+ _curl( 0 ), _connected( false )
+{
+ if ( ! _globalInit )
+ {
+ _globalInit = true;
+ CURLcode ret = curl_global_init( CURL_GLOBAL_ALL );
+ if ( ret != 0 )
+ WAR << "curl global init failed" << endl;
+ }
+}
+
+void MediaCurl::setCookieFile( const Pathname &fileName )
+{
+ _cookieFile = fileName;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::attachTo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
+//
+void MediaCurl::attachTo (bool next)
+{
+ if ( next )
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_supported_by_media");
+
+ if ( !_url.isValid() )
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_bad_url");
+
+ _curl = curl_easy_init();
+ if ( !_curl ) {
+ ERR << "curl easy init failed" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_error");
+ }
+
+ _connected = true;
+
+ CURLcode ret = curl_easy_setopt( _curl, CURLOPT_ERRORBUFFER, _curlError );
+ if ( ret != 0 ) {
+ ERR << "Error setting error buffer" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ ret = curl_easy_setopt( _curl, CURLOPT_FAILONERROR, true );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ if ( _url.protocol() == Url::http ) {
+ // follow any Location: header that the server sends as part of
+ // an HTTP header (#113275)
+ ret = curl_easy_setopt ( _curl, CURLOPT_FOLLOWLOCATION, true );
+ if ( ret != 0) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+ ret = curl_easy_setopt ( _curl, CURLOPT_MAXREDIRS, 3L );
+ if ( ret != 0) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+ }
+
+ // XXX: wasn't that the wrong fix for some problem? this should be
+ // removed
+ if ( _url.protocol() == Url::https ) {
+ WAR << "Disable certificate verification for https." << endl;
+ ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYPEER, 0 );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYHOST, 0 );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+ }
+
+
+ /*---------------------------------------------------------------*
+ CURLOPT_USERPWD: [user name]:[password]
+
+ Url::username/password -> CURLOPT_USERPWD
+ If not provided, anonymous FTP identification
+ *---------------------------------------------------------------*/
+
+ if ( _url.username().empty() ) {
+ if ( _url.protocol() == Url::ftp ) {
+ string id = "yast2@";
+ id += VERSION;
+ DBG << "Anonymous FTP identification: '" << id << "'" << endl;
+ _userpwd = "anonymous:" + id;
+ }
+ } else {
+ _userpwd = _url.username();
+ if ( _url.password().size() ) {
+ _userpwd += ":" + _url.password();
+ }
+ }
+
+ if ( _userpwd.size() ) {
+ _userpwd = unEscape( _userpwd );
+ ret = curl_easy_setopt( _curl, CURLOPT_USERPWD, _userpwd.c_str() );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+ }
+
+ /*---------------------------------------------------------------*
+ CURLOPT_PROXY: host[:port]
+
+ Url::option(proxy and proxyport) -> CURLOPT_PROXY
+ If not provided, /etc/sysconfig/proxy is evaluated
+ *---------------------------------------------------------------*/
+
+ _proxy = _url.option( "proxy" );
+
+ if ( ! _proxy.empty() ) {
+ string proxyport( _url.option( "proxyport" ) );
+ if ( ! proxyport.empty() ) {
+ _proxy += ":" + proxyport;
+ }
+
+#warning FIXME enable proxy via sysconfig somehow
+#if 0
+ } else {
+
+ SysConfig cfg( "proxy" );
+
+ if ( cfg.readBoolEntry( "PROXY_ENABLED", false ) ) {
+ bool useproxy = true;
+
+ std::vector<std::string> nope;
+ stringutil::split( cfg.readEntry( "NO_PROXY" ), nope, ", \t" );
+ for ( unsigned i = 0; i < nope.size(); ++i ) {
+ // no proxy: if nope equals host,
+ // or is a suffix preceeded by a '.'
+ string::size_type pos = _url.host().find( nope[i] );
+ if ( pos != string::npos
+ && ( pos + nope[i].size() == _url.host().size() )
+ && ( pos == 0 || _url.host()[pos -1] == '.' ) ) {
+ DBG << "NO_PROXY: " << nope[i] << " matches host " << _url.host() << endl;
+ useproxy = false;
+ break;
+ }
+ }
+
+ if ( useproxy ) {
+ if ( _url.protocol() == Url::ftp ) {
+ _proxy = cfg.readEntry( "FTP_PROXY" );
+ } else if ( _url.protocol() == Url::http ) {
+ _proxy = cfg.readEntry( "HTTP_PROXY" );
+ } else if ( _url.protocol() == Url::https ) {
+ _proxy = cfg.readEntry( "HTTPS_PROXY" );
+ }
+ }
+ }
+#endif
+ }
+
+
+ DBG << "Proxy: " << _proxy << endl;
+
+ if ( ! _proxy.empty() ) {
+
+ ret = curl_easy_setopt( _curl, CURLOPT_PROXY, _proxy.c_str() );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ /*---------------------------------------------------------------*
+ CURLOPT_PROXYUSERPWD: [user name]:[password]
+
+ Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
+ If not provided, $HOME/.curlrc is evaluated
+ *---------------------------------------------------------------*/
+
+ _proxyuserpwd = _url.option( "proxyuser" );
+
+ if ( ! _proxyuserpwd.empty() ) {
+
+ string proxypassword( _url.option( "proxypassword" ) );
+ if ( ! proxypassword.empty() ) {
+ _proxyuserpwd += ":" + proxypassword;
+ }
+
+#warning FIXME enable proxy via sysconfig somehow
+#if 0
+ } else {
+
+ string curlrcFile = string( getenv("HOME") ) + string( "/.curlrc" );
+ SysConfig curlrc( curlrcFile );
+ _proxyuserpwd = curlrc.readEntry( "proxy-user" );
+
+#endif
+ }
+
+ _proxyuserpwd = unEscape( _proxyuserpwd );
+ ret = curl_easy_setopt( _curl, CURLOPT_PROXYUSERPWD, _proxyuserpwd.c_str() );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ }
+
+ /*---------------------------------------------------------------*
+ *---------------------------------------------------------------*/
+
+ _currentCookieFile = _cookieFile.asString();
+
+ ret = curl_easy_setopt( _curl, CURLOPT_COOKIEFILE,
+ _currentCookieFile.c_str() );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ ret = curl_easy_setopt( _curl, CURLOPT_COOKIEJAR,
+ _currentCookieFile.c_str() );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ ret = curl_easy_setopt( _curl, CURLOPT_PROGRESSFUNCTION,
+ &MediaCurl::progressCallback );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ ret = curl_easy_setopt( _curl, CURLOPT_NOPROGRESS, false );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::disconnectFrom
+// METHOD TYPE : PMError
+//
+void MediaCurl::disconnectFrom()
+{
+ if ( _connected ) curl_easy_cleanup( _curl );
+ _connected = false ;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::releaseFrom
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached.
+//
+void MediaCurl::releaseFrom( bool eject )
+{
+ disconnect();
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+// METHOD NAME : MediaCurl::getFile
+// METHOD TYPE : PMError
+//
+
+void MediaCurl::getFile( const Pathname & filename ) const
+{
+ // Use absolute file name to prevent access of files outside of the
+ // hierarchy below the attach point.
+ getFileCopy(filename, localPath(filename).absolutename());
+}
+
+
+void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target) const
+{
+ DBG << filename.asString() << endl;
+
+ if(!_url.isValid())
+ throw MediaException(ZYPP_EX_CODELOCATION, string("Error::E_bad_url") + " " + _url.asString());
+
+ if(_url.host().empty())
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_no_host_specified");
+
+ string path = _url.path();
+ 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.setPath( escapedPath(path) );
+
+ Pathname dest = target.absolutename();
+ string destNew = target.asString() + ".new.yast.37456";
+
+ DBG << "dest: " << dest << endl;
+ DBG << "destNew: " << destNew << endl;
+
+ if( PathInfo::assert_dir( dest.dirname() ) )
+ {
+ DBG << "assert_dir " << dest.dirname() << " failed" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, string("Error::E_system") + string(" ") + dest.dirname().asString());
+ }
+
+ DBG << "URL: " << url.asString().c_str() << endl;
+ // Use URL without options (not RFC conform) and without
+ // username and passwd (some proxies dislike them in the URL.
+ // Curloptions for these were set in attachTo().
+ Url curlUrl( url );
+ curlUrl.setUsername( "" );
+ curlUrl.setPassword( "" );
+ string urlBuffer = curlUrl.asString(true,false,true); // without options
+
+ CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
+ urlBuffer.c_str() );
+ if ( ret != 0 ) {
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ FILE *file = fopen( destNew.c_str(), "w" );
+ if ( !file ) {
+ ERR << "fopen failed for file '" << destNew << "'" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, string("Error::E_write_error") + string(" ") + destNew);
+ }
+
+ ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
+ if ( ret != 0 ) {
+ fclose( file );
+ ERR << _curlError << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_curl_setopt_failed");
+ }
+
+ // Set callback and perform.
+#warning FIXME reenable callback
+#if 0
+ DownloadProgressReport::Send report( downloadProgressReport );
+ report->start( url, dest );
+ if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &report ) != 0 ) {
+ WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
+ }
+#endif
+
+ ret = curl_easy_perform( _curl );
+ fclose( file );
+
+ if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
+ WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
+ }
+
+ if ( ret != 0 ) {
+ PathInfo::unlink( destNew );
+
+ ERR << "curl error: " << ret << ": " << _curlError << endl;
+ std::string err;
+ switch ( ret ) {
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ case CURLE_URL_MALFORMAT:
+ case CURLE_URL_MALFORMAT_USER:
+ err = "Error::E_bad_url";
+ break;
+ case CURLE_HTTP_NOT_FOUND:
+ {
+ long httpReturnCode;
+ CURLcode infoRet = curl_easy_getinfo( _curl, CURLINFO_HTTP_CODE,
+ &httpReturnCode );
+ if ( infoRet == CURLE_OK ) {
+ string msg = "HTTP return code: " +
+ stringutil::numstring( httpReturnCode ) +
+ " (URL: " + url.asString() + ")";
+ DBG << msg << endl;
+ if ( httpReturnCode == 401 )
+ {
+ msg = "URL: " + url.asString();
+ err = "Error::E_login_failed";
+ }
+ else
+ {
+ err = "Error::E_file_not_found";
+ }
+#warning FIXME reenable change report
+#if 0
+ report->stop( err );
+#endif
+ throw MediaException(ZYPP_EX_CODELOCATION, err + string(" ") + _curlError);
+ }
+ }
+ break;
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ case CURLE_FTP_ACCESS_DENIED:
+ err = "Error::E_file_not_found";
+ break;
+ case CURLE_BAD_PASSWORD_ENTERED:
+ case CURLE_FTP_USER_PASSWORD_INCORRECT:
+ err = "Error::E_login_failed";
+ break;
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ case CURLE_COULDNT_CONNECT:
+ case CURLE_FTP_CANT_GET_HOST:
+ err = "Error::E_connection_failed";
+ break;
+ case CURLE_WRITE_ERROR:
+ err = "Error::E_write_error";
+ break;
+ case CURLE_ABORTED_BY_CALLBACK:
+ err = "Error::E_user_abort";
+ break;
+ case CURLE_SSL_PEER_CERTIFICATE:
+ default:
+ err = "Error::E_error";
+ break;
+ }
+
+#warning FIXME reenable change report
+#if 0
+ report->stop( err );
+#endif
+ throw MediaException(ZYPP_EX_CODELOCATION, err + string(" ") + _curlError);
+ }
+
+ if ( PathInfo::rename( destNew, dest ) != 0 ) {
+ ERR << "Rename failed" << endl;
+#warning FIXME reenable change report
+#if 0
+ report->stop( Error::E_write_error );
+#endif
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_write_error");
+ }
+
+#warning FIXME reenable change report
+#if 0
+ report->stop( Error::E_ok );
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::getDir
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached
+//
+void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
+{
+ PathInfo::dircontent content;
+ try {
+ getDirInfo( content, dirname, /*dots*/false );
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+
+ for ( PathInfo::dircontent::const_iterator it = content.begin(); it != content.end(); ++it ) {
+ try {
+ Pathname filename = dirname + it->name;
+ int res = 0;
+
+ switch ( it->type ) {
+ case PathInfo::NOT_AVAIL: // old directory.yast contains no typeinfo at all
+ case PathInfo::T_FILE:
+ getFile( filename );
+ break;
+ case PathInfo::T_DIR: // newer directory.yast contain at least directory info
+ if ( recurse_r ) {
+ getDir( filename, recurse_r );
+ } else {
+ res = PathInfo::assert_dir( localPath( filename ) );
+ if ( res ) {
+ WAR << "Ignore error (" << res << ") on creating local directory '" << localPath( filename ) << "'" << endl;
+ }
+ }
+ break;
+ default:
+ // don't provide devices, sockets, etc.
+ break;
+ }
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::getDirInfo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached and retlist is empty.
+//
+void MediaCurl::getDirInfo( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ try {
+ getDirectoryYast( retlist, dirname, dots );
+ }
+ catch (const MediaException & excpt_r)
+ {
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_supported_by_media");
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::getDirInfo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached and retlist is empty.
+//
+void MediaCurl::getDirInfo( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ try {
+ getDirectoryYast( retlist, dirname, dots );
+ }
+ catch (const MediaException & excpt_r)
+ {
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_supported_by_media");
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaCurl::progressCallback
+// METHOD TYPE : int
+//
+// DESCRIPTION : Progress callback triggered from MediaCurl::getFile
+//
+int MediaCurl::progressCallback( void *clientp, double dltotal, double dlnow,
+ double ultotal, double ulnow )
+{
+#warning FIXME this function
+#if 0
+ DownloadProgressReport::Send * reportP = reinterpret_cast<DownloadProgressReport::Send*>( clientp );
+ if ( reportP ) {
+ ProgressData pd( 0, int(dltotal), int(dlnow) );
+ if ( (*reportP)->progress( pd ) == false )
+ return 1; // abort requested by user
+ }
+
+#warning YOU callbacks still active
+ if ( _callbacks ) {
+ if ( _callbacks->progress( int( dlnow * 100 / dltotal ) ) ) return 0;
+ else return 1;
+ }
+#endif
+ return 0;
+}
+
+ } // namespace media
+} // namespace zypp
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaCurl.h
+ *
+*/
+#ifndef ZYPP_MEDIA_MEDIACURL_H
+#define ZYPP_MEDIA_MEDIACURL_H
+
+#include "zypp/media/MediaHandler.h"
+
+#include <curl/curl.h>
+
+namespace zypp {
+ namespace media {
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : MediaCurl
+/**
+ * @short Implementation class for FTP, HTTP and HTTPS MediaHandler
+ * @see MediaHandler
+ **/
+class MediaCurl : public MediaHandler {
+
+ protected:
+
+ MEDIA_HANDLER_API;
+ /**
+ *
+ * \throws MediaException
+ *
+ */
+ virtual void disconnectFrom();
+ /**
+ *
+ * \throws MediaException
+ *
+ */
+ virtual void getFileCopy( const Pathname & srcFilename, const Pathname & targetFilename) const;
+
+
+ public:
+
+ MediaCurl( const Url & url_r,
+ const Pathname & attach_point_hint_r );
+
+ virtual ~MediaCurl() { release(); }
+
+ static void setCookieFile( const Pathname & );
+
+ class Callbacks
+ {
+ public:
+ virtual ~Callbacks() {}
+ virtual bool progress( int percent ) = 0;
+ };
+
+ static void setCallbacks( Callbacks *c ) { _callbacks = c; }
+
+ protected:
+
+ static int progressCallback( void *clientp, double dltotal, double dlnow,
+ double ultotal, double ulnow );
+
+ private:
+ CURL *_curl;
+ char _curlError[ CURL_ERROR_SIZE ];
+
+ std::string _userpwd;
+ std::string _proxy;
+ std::string _proxyuserpwd;
+ std::string _currentCookieFile;
+
+ static Pathname _cookieFile;
+
+ static Callbacks *_callbacks;
+
+ bool _connected;
+
+ static bool _globalInit;
+};
+
+///////////////////////////////////////////////////////////////////
+
+ } // namespace media
+} // namespace zypp
+
+#endif // ZYPP_MEDIA_MEDIACURL_H
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaException.h
+ *
+*/
+#ifndef ZYPP_MEDIA_MEDIAEXCEPTION_H
+#define ZYPP_MEDIA_MEDIAEXCEPTION_H
+
+#include <iosfwd>
+#include <stdexcept>
+
+#include "zypp/base/Exception.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+ namespace media {
+ ///////////////////////////////////////////////////////////////
+ //
+ // CLASS NAME : MediaException
+ /** Just inherits Exception to separate media exceptions
+ *
+ **/
+ class MediaException : public Exception
+ {
+ typedef exception_detail::CodeLocation CodeLocation;
+ public:
+ /** Ctor taking CodeLocation and message.
+ * Use \ref ZYPP_THROW to throw exceptions.
+ */
+ MediaException( const CodeLocation & where_r, const std::string & msg_r )
+ : Exception( msg_r )
+ {}
+ };
+
+ /////////////////////////////////////////////////////////////////
+ } // namespace media
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_MEDIA_MEDIAEXCEPTION_H
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaHandler.cc
+ *
+*/
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include "zypp/base/Logger.h"
+#include "zypp/media/MediaHandler.h"
+#include "zypp/base/stringutil.h"
+
+using namespace std;
+using namespace zypp::base;
+
+// use directory.yast on every media (not just via ftp/http)
+#define NONREMOTE_DIRECTORY_YAST 1
+
+namespace zypp {
+ namespace media {
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : MediaHandler
+//
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::MediaHandler
+// METHOD TYPE : Constructor
+//
+// DESCRIPTION :
+//
+MediaHandler::MediaHandler ( const Url & url_r,
+ const Pathname & attach_point_r,
+ const Pathname & urlpath_below_attachpoint_r,
+ const bool does_download_r )
+ : _attachPoint( attach_point_r )
+ , _tmp_attachPoint( false )
+ , _does_download( does_download_r )
+ , _isAttached( false )
+ , _url( url_r )
+{
+ if ( _attachPoint.empty() ) {
+ ///////////////////////////////////////////////////////////////////
+ // provide a default attachpoint
+ ///////////////////////////////////////////////////////////////////
+
+ Pathname aroot;
+ PathInfo adir;
+ const char * defmounts[] = { "/var/adm/mount", "/var/tmp", /**/NULL/**/ };
+ for ( const char ** def = defmounts; *def; ++def ) {
+ adir( *def );
+ if ( adir.isDir() && adir.userMayRWX() ) {
+ aroot = adir.path();
+ break;
+ }
+ }
+ if ( aroot.empty() ) {
+ ERR << "Create attach point: Can't find a writable directory to create an attach point" << endl;
+ return;
+ }
+
+ Pathname abase( aroot + "AP_" );
+ Pathname apoint;
+
+ for ( unsigned i = 1; i < 1000; ++i ) {
+ adir( Pathname::extend( abase, stringutil::hexstring( i ) ) );
+ if ( ! adir.isExist() && PathInfo::mkdir( adir.path() ) == 0 ) {
+ apoint = adir.path();
+ break;
+ }
+ }
+
+ if ( apoint.empty() ) {
+ ERR << "Unable to create an attach point below " << aroot << endl;
+ return;
+ }
+
+ // success
+ _attachPoint = apoint;
+ _tmp_attachPoint = true;
+ MIL << "Created default attach point " << _attachPoint << endl;
+
+ } else {
+ ///////////////////////////////////////////////////////////////////
+ // check if provided attachpoint is usable.
+ ///////////////////////////////////////////////////////////////////
+ PathInfo adir( _attachPoint );
+ if ( !adir.isDir() ) {
+ ERR << "Provided attach point is not a directory: " << adir << endl;
+ _attachPoint = Pathname();
+ }
+
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // must init _localRoot after _attachPoint is determined.
+ ///////////////////////////////////////////////////////////////////
+
+ if ( !_attachPoint.empty() ) {
+ _localRoot = _attachPoint + urlpath_below_attachpoint_r;
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::~MediaHandler
+// METHOD TYPE : Destructor
+//
+// DESCRIPTION :
+//
+MediaHandler::~MediaHandler()
+{
+ if ( _isAttached ) {
+ INT << "MediaHandler deleted with media attached." << endl;
+ return; // no cleanup if media still mounted!
+ }
+
+ if ( _tmp_attachPoint ) {
+ int res = PathInfo::recursive_rmdir( _attachPoint );
+ if ( res == 0 ) {
+ MIL << "Deleted default attach point " << _attachPoint << endl;
+ } else {
+ ERR << "Failed to Delete default attach point " << _attachPoint
+ << " errno(" << res << ")" << endl;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::attach
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::attach( bool next )
+{
+ if ( _isAttached )
+ return;
+
+ if ( _attachPoint.empty() ) {
+ ERR << "Error::E_bad_attachpoint" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_bad_attachpoint");
+ }
+
+ try {
+ attachTo( next ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "Attach failed: " << excpt_r << " " << *this << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ _isAttached = true;
+ MIL << "Attached: " << *this << endl;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::localPath
+// METHOD TYPE : Pathname
+//
+Pathname MediaHandler::localPath( const Pathname & pathname ) const {
+ if ( _localRoot.empty() )
+ return _localRoot;
+
+ // we must check maximum file name length
+ // this is important for fetching the suseservers, the
+ // url with all parameters can get too long (bug #42021)
+
+ return _localRoot + pathname.absolutename();
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::disconnect
+// METHOD TYPE : PMError
+//
+void MediaHandler::disconnect()
+{
+ if ( !_isAttached )
+ return;
+
+ try {
+ disconnectFrom(); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "Disconnect failed: " << excpt_r << " " << *this << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ MIL << "Disconnected: " << *this << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::release
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::release( bool eject )
+{
+ if ( !_isAttached ) {
+ if ( eject )
+ forceEject();
+ return;
+ }
+
+ try {
+ releaseFrom( eject ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "Release failed: " << excpt_r << " " << *this << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ _isAttached = false;
+ MIL << "Released: " << *this << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::provideFile
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::provideFileCopy( Pathname srcFilename,
+ Pathname targetFilename ) const
+{
+ if ( !_isAttached ) {
+ INT << "Error::E_not_attached" << " on provideFileCopy(" << srcFilename
+ << "," << targetFilename << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_attached");
+ }
+
+ try {
+ getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "provideFileCopy(" << srcFilename << "," << targetFilename << "): " << excpt_r << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ DBG << "provideFileCopy(" << srcFilename << "," << targetFilename << ")" << endl;
+}
+
+void MediaHandler::provideFile( Pathname filename ) const
+{
+ if ( !_isAttached ) {
+ INT << "Error::E_not_attached" << " on provideFile(" << filename << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_attached");
+ }
+
+ try {
+ getFile( filename ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "provideFile(" << filename << "): " << excpt_r << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ DBG << "provideFile(" << filename << ")" << endl;
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::provideDir
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::provideDir( Pathname dirname ) const
+{
+ if ( !_isAttached ) {
+ INT << "Error::E_not_attached" << " on provideDir(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_attached");
+ }
+ try {
+ getDir( dirname, /*recursive*/false ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "provideDir(" << dirname << "): " << excpt_r << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ MIL << "provideDir(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::provideDirTree
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::provideDirTree( Pathname dirname ) const
+{
+ if ( !_isAttached ) {
+ INT << "Error::E_not_attached" << " on provideDirTree(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_attached");
+ }
+
+ try {
+ getDir( dirname, /*recursive*/true ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "provideDirTree(" << dirname << "): " << excpt_r << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+
+ MIL << "provideDirTree(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::releasePath
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::releasePath( Pathname pathname ) const
+{
+ if ( ! _does_download || _attachPoint.empty() )
+ return;
+
+ PathInfo info( localPath( pathname ) );
+
+ if ( info.isFile() ) {
+ PathInfo::unlink( info.path() );
+ } else if ( info.isDir() ) {
+ if ( info.path() != _localRoot ) {
+ PathInfo::recursive_rmdir( info.path() );
+ } else {
+ PathInfo::clean_dir( info.path() );
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::dirInfo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::dirInfo( list<string> & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ retlist.clear();
+
+ if ( !_isAttached ) {
+ INT << "Error::E_not_attached" << " on dirInfo(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_attached");
+ }
+
+ try {
+ getDirInfo( retlist, dirname, dots ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "dirInfo(" << dirname << "): " << excpt_r << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ MIL << "dirInfo(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::dirInfo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION :
+//
+void MediaHandler::dirInfo( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ retlist.clear();
+
+ if ( !_isAttached ) {
+ INT << "Error::E_not_attached" << " on dirInfo(" << dirname << ")" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_attached");
+ }
+
+ try {
+ getDirInfo( retlist, dirname, dots ); // pass to concrete handler
+ }
+ catch (const MediaException & excpt_r)
+ {
+ WAR << "dirInfo(" << dirname << "): " << excpt_r << endl;
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ MIL << "dirInfo(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::getDirectoryYast
+// METHOD TYPE : PMError
+//
+void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ retlist.clear();
+
+ PathInfo::dircontent content;
+ try {
+ getDirectoryYast( content, dirname, dots );
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+
+ // convert to std::list<std::string>
+ for ( PathInfo::dircontent::const_iterator it = content.begin(); it != content.end(); ++it ) {
+ retlist.push_back( it->name );
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::getDirectoryYast
+// METHOD TYPE : PMError
+//
+void MediaHandler::getDirectoryYast( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ retlist.clear();
+
+ // look for directory.yast
+ Pathname dirFile = dirname + "directory.yast";
+ try {
+ getFile( dirFile );
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME rethrow
+#if 0
+ ERR << "provideFile(" << dirFile << "): " << excpt_r << endl;
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+ DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
+
+ // using directory.yast
+ ifstream dir( localPath( dirFile ).asString().c_str() );
+ if ( dir.fail() ) {
+ ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_system");
+ }
+
+ string line;
+ while( getline( dir, line ) ) {
+ if ( line.empty() ) continue;
+ if ( line == "directory.yast" ) continue;
+
+ // Newer directory.yast append '/' to directory names
+ // Remaining entries are unspecified, although most probabely files.
+ PathInfo::file_type type = PathInfo::NOT_AVAIL;
+ if ( *line.rbegin() == '/' ) {
+ line.erase( line.end()-1 );
+ type = PathInfo::T_DIR;
+ }
+
+ if ( dots ) {
+ if ( line == "." || line == ".." ) continue;
+ } else {
+ if ( *line.begin() == '.' ) continue;
+ }
+
+ retlist.push_back( PathInfo::direntry( line, type ) );
+ }
+}
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : operator<<
+** FUNCTION TYPE : ostream &
+*/
+ostream & operator<<( ostream & str, const MediaHandler & obj )
+{
+ str << obj.url() << ( obj.isAttached() ? "" : " not" )
+ << " attached; localRoot \"" << obj.localRoot() << "\"";
+ return str;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::getFile
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached.
+// Default implementation of pure virtual.
+//
+void MediaHandler::getFile( const Pathname & filename ) const
+{
+ PathInfo info( localPath( filename ) );
+ if( info.isFile() ) {
+ return;
+ }
+
+ if (info.isExist())
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_a_file");
+ else
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_file_not_found");
+}
+
+
+void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
+{
+ try {
+ getFile(srcFilename);
+ }
+ catch (const MediaException & excpt_r)
+ {
+#warning FIXME rethrow
+#if 0
+ ZYPP_RETHROW(excpt_r);
+#endif
+ }
+
+ if ( PathInfo::copy( localPath( srcFilename ), targetFilename ) != 0 ) {
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_write_error");
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::getDir
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached.
+// Default implementation of pure virtual.
+//
+void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
+{
+ PathInfo info( localPath( dirname ) );
+ if( info.isDir() ) {
+ return;
+ }
+
+ if (info.isExist())
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_a_file");
+ else
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_file_not_found");
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::getDirInfo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached and retlist is empty.
+// Default implementation of pure virtual.
+//
+void MediaHandler::getDirInfo( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ PathInfo info( localPath( dirname ) );
+ if( ! info.isDir() ) {
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_a_directory");
+ }
+
+#if NONREMOTE_DIRECTORY_YAST
+ // use directory.yast if available
+ try {
+ getDirectoryYast( retlist, dirname, dots );
+ }
+ catch (const MediaException & excpt_r)
+ {
+#endif
+
+ // readdir
+ int res = PathInfo::readdir( retlist, info.path(), dots );
+ if ( res )
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_system");
+
+#if NONREMOTE_DIRECTORY_YAST
+ }
+#endif
+
+ return;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : MediaHandler::getDirInfo
+// METHOD TYPE : PMError
+//
+// DESCRIPTION : Asserted that media is attached and retlist is empty.
+// Default implementation of pure virtual.
+//
+void MediaHandler::getDirInfo( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots ) const
+{
+ PathInfo info( localPath( dirname ) );
+ if( ! info.isDir() ) {
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_not_a_directory");
+ }
+
+#if NONREMOTE_DIRECTORY_YAST
+ // use directory.yast if available
+ try {
+ getDirectoryYast( retlist, dirname, dots );
+ }
+ catch (const MediaException & excpt_r)
+ {
+#endif
+
+ // readdir
+ int res = PathInfo::readdir( retlist, info.path(), dots );
+ if ( res )
+ throw MediaException(ZYPP_EX_CODELOCATION, "Error::E_system");
+#if NONREMOTE_DIRECTORY_YAST
+ }
+#endif
+}
+
+ } // namespace media
+} // namespace zypp
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaHandler.h
+ *
+*/
+#ifndef ZYPP_MEDIA_MEDIAHANDLERL_H
+#define ZYPP_MEDIA_MEDIAHANDLERL_H
+
+#include <iosfwd>
+#include <string>
+#include <list>
+
+#include "zypp/Pathname.h"
+#include "zypp/PathInfo.h"
+
+#warning FIXME use real Url class
+// #include "zypp/@Review/Url.h"
+typedef std::string Url;
+
+#include "zypp/media/MediaAccess.h"
+
+namespace zypp {
+ namespace media {
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : MediaHandler
+/**
+ * @short Abstract base class for 'physical' MediaHandler like MediaCD, etc.
+ *
+ * Handles the requests forwarded by @ref MediaAccess. The public interface
+ * contains nonvirtual methods, which should do common sanitychecks and
+ * logging. For the real action they call virtual methods overloaded by the
+ * concrete handler.
+ **/
+class MediaHandler {
+ friend std::ostream & operator<<( std::ostream & str, const MediaHandler & obj );
+
+ public:
+ typedef shared_ptr<MediaHandler> Ptr;
+ typedef shared_ptr<const MediaHandler> constPtr;
+
+ private:
+
+ /**
+ * this is where the media will be actually "mounted"
+ * all files are provided 'below' this directory.
+ **/
+ Pathname _attachPoint;
+
+ /**
+ * If a default attach point was created, it has to be
+ * removed on destuction.
+ **/
+ bool _tmp_attachPoint;
+
+ /**
+ * The local directory that corresponds to the media url.
+ * With NFS it's the '_attachPoint', as the directory on the
+ * server is mounted. With CD/DVD it's 'attach point+_url.path()'
+ * because the CDs root directory is mounted. And with CIFS
+ * it's '_url.path() without the shares name'.
+ **/
+ Pathname _localRoot;
+
+ /**
+ * True if concrete handler downloads files to the local
+ * filesystem. If true releaseFile/Dir will delete them.
+ **/
+ bool _does_download;
+
+ /**
+ * True, if media is attached.
+ **/
+ bool _isAttached;
+
+ protected:
+
+ /**
+ * Url to handle
+ **/
+ const Url _url;
+
+ /**
+ * Attachpoint to use
+ **/
+ const Pathname & attachPoint() const { return _attachPoint; }
+
+ protected:
+
+ ///////////////////////////////////////////////////////////////////
+ //
+ // Real action interface to be overloaded by concrete handler.
+ //
+ ///////////////////////////////////////////////////////////////////
+
+ /**
+ * Call concrete handler to attach the media.
+ *
+ * Asserted that not already attached, and attachPoint is a directory.
+ *
+ * @param next try next available device in turn until end of device
+ * list is reached (for media which are accessible through multiple
+ * devices like cdroms).
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void attachTo(bool next = false) = 0;
+
+ /**
+ * Call concrete handler to disconnect media.
+ *
+ * Asserted that media is attached.
+ *
+ * This is useful for media which e.g. holds open a connection to a
+ * server like FTP. After calling disconnect() the media object still is
+ * valid and files are present.
+ *
+ * After calling disconnect() it's not possible to call provideFile() or
+ * provideDir() anymore.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void disconnectFrom() { return; }
+
+ /**
+ * Call concrete handler to release the media.
+ * If eject is true, physically eject the media (i.e. CD-ROM).
+ *
+ * Asserted that media is attached.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void releaseFrom( bool eject ) = 0;
+
+ /**
+ * Call concrete handler to physically eject the media (i.e. CD-ROM)
+ * in case the media is not attached..
+ *
+ * Asserted that media is not attached.
+ **/
+ virtual void forceEject() {}
+
+ /**
+ * Call concrete handler to provide file below attach point.
+ *
+ * Default implementation provided, that returns whether a file
+ * is located at '_localRoot + filename'.
+ *
+ * Asserted that media is attached.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void getFile( const Pathname & filename ) const = 0;
+
+ /**
+ * Call concrete handler to provide a file under a different place
+ * in the file system (usually not under attach point) as a copy.
+ * Media must be attached before by callee.
+ *
+ * Default implementation provided that calls getFile(srcFilename)
+ * and copies the result around.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void getFileCopy( const Pathname & srcFilename, const Pathname & targetFilename ) const;
+
+
+ /**
+ * Call concrete handler to provide directory content (not recursive!)
+ * below attach point.
+ *
+ * Return E_not_supported_by_media if media does not support retrieval of
+ * directory content.
+ *
+ * Default implementation provided, that returns whether a directory
+ * is located at '_localRoot + dirname'.
+ *
+ * Asserted that media is attached.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void getDir( const Pathname & dirname, bool recurse_r ) const = 0;
+
+ /**
+ * Call concrete handler to provide a content list of directory on media
+ * via retlist. If dots is false entries starting with '.' are not reported.
+ *
+ * Return E_not_supported_by_media if media does not support retrieval of
+ * directory content.
+ *
+ * Default implementation provided, that returns the content of a
+ * directory at '_localRoot + dirnname' retrieved via 'readdir'.
+ *
+ * Asserted that media is attached and retlist is empty.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void getDirInfo( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots = true ) const = 0;
+
+ /**
+ * Basically the same as getDirInfo above. The content list is returned as
+ * PathInfo::dircontent, which includes name and filetype of each directory
+ * entry. Retrieving the filetype usg. requires an additional ::stat call for
+ * each entry, thus it's more expensive than a simple readdir.
+ *
+ * Asserted that media is attached and retlist is empty.
+ *
+ * \throws MediaException
+ *
+ **/
+ virtual void getDirInfo( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots = true ) const = 0;
+
+ protected:
+
+ /**
+ * Retrieve and if available scan dirname/directory.yast.
+ *
+ * Asserted that media is attached.
+ *
+ * \throws MediaException
+ *
+ **/
+ void getDirectoryYast( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots = true ) const;
+
+ /**
+ * Retrieve and if available scan dirname/directory.yast.
+ *
+ * Asserted that media is attached.
+ *
+ * \throws MediaException
+ *
+ **/
+ void getDirectoryYast( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots = true ) const;
+
+ public:
+
+ /**
+ * If the concrete media handler provides a nonempty
+ * attach_point, it must be an existing directory.
+ *
+ * On an empty attach_point, MediaHandler will create
+ * a temporay directory, which will be erased from
+ * destructor.
+ *
+ * On any error, the attach_point is set to an empty Pathname,
+ * which should lead to E_bad_attachpoint.
+ **/
+ MediaHandler ( const Url& url_r,
+ const Pathname & attach_point_r,
+ const Pathname & urlpath_below_attachpoint_r,
+ const bool does_download_r );
+
+ /**
+ * Contolling MediaAccess takes care, that attached media is released
+ * prior to deleting this.
+ **/
+ virtual ~MediaHandler();
+
+ public:
+
+ ///////////////////////////////////////////////////////////////////
+ //
+ // MediaAccess interface. Does common checks and logging.
+ // Invokes real action if necessary.
+ //
+ ///////////////////////////////////////////////////////////////////
+
+ /**
+ * Protocol hint for MediaAccess.
+ **/
+#warning FIXME uncomment once real Url class is implemented
+#if 0
+ Url::Protocol protocol() const { return _url.protocol(); }
+#endif
+
+ /**
+ * Url used.
+ **/
+ Url url() const { return _url; }
+
+ /**
+ * Use concrete handler to attach the media.
+ *
+ * @param next try next available device in turn until end of device
+ * list is reached (for media which are accessible through multiple
+ * devices like cdroms).
+ *
+ * \throws MediaException
+ *
+ **/
+ void attach(bool next);
+
+ /**
+ * True if media is attached.
+ **/
+ bool isAttached() const { return _isAttached; }
+
+ /**
+ * Return the local directory that corresponds to medias url,
+ * no matter if media isAttached or not. Files requested will
+ * be available at 'localRoot() + filename' or better
+ * 'localPath( filename )'.
+ *
+ * Returns empty pathname if E_bad_attachpoint
+ **/
+ const Pathname & localRoot() const { return _localRoot; }
+
+ /**
+ * Files provided will be available at 'localPath(filename)'.
+ *
+ * Returns empty pathname if E_bad_attachpoint
+ **/
+ Pathname localPath( const Pathname & pathname ) const;
+
+ /**
+ * Use concrete handler to isconnect media.
+ *
+ * This is useful for media which e.g. holds open a connection to a
+ * server like FTP. After calling disconnect() the media object still is
+ * valid and files are present.
+ *
+ * After calling disconnect() it's not possible to call provideFile() or
+ * provideDir() anymore.
+ *
+ * \throws MediaException
+ *
+ **/
+ void disconnect();
+
+ /**
+ * Use concrete handler to release the media.
+ * @param eject if true, physically eject the media * (i.e. CD-ROM)
+ *
+ * \throws MediaException
+ *
+ **/
+ void release( bool eject = false );
+
+ /**
+ * Use concrete handler to provide file denoted by path below
+ * 'localRoot'. Filename is interpreted relative to the
+ * attached url and a path prefix is preserved.
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideFile( Pathname filename ) const;
+
+ /**
+ * Call concrete handler to provide a copy of a file under a different place
+ * in the file system (usually not under attach point) as a copy.
+ * Media must be attached before by callee.
+ *
+ * @param srcFilename Filename of source file on the media
+ * @param targetFilename Filename for the target in the file system
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideFileCopy( Pathname srcFilename, Pathname targetFilename) const;
+
+ /**
+ * Use concrete handler to provide directory denoted
+ * by path below 'localRoot' (not recursive!).
+ * dirname is interpreted relative to the
+ * attached url and a path prefix is preserved.
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideDir( Pathname dirname ) const;
+
+ /**
+ * Use concrete handler to provide directory tree denoted
+ * by path below 'localRoot' (recursive!!).
+ * dirname is interpreted relative to the
+ * attached url and a path prefix is preserved.
+ *
+ * \throws MediaException
+ *
+ **/
+ void provideDirTree( Pathname dirname ) const;
+
+ /**
+ * Remove filename below localRoot IFF handler downloads files
+ * to the local filesystem. Never remove anything from media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void releaseFile( const Pathname & filename ) const { return releasePath( filename ); }
+
+ /**
+ * Remove directory tree below localRoot IFF handler downloads files
+ * to the local filesystem. Never remove anything from media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void releaseDir( const Pathname & dirname ) const { return releasePath( dirname ); }
+
+ /**
+ * Remove pathname below localRoot IFF handler downloads files
+ * to the local filesystem. Never remove anything from media.
+ *
+ * If pathname denotes a directory it is recursively removed.
+ * If pathname is empty or '/' everything below the localRoot
+ * is recursively removed.
+ * If pathname denotes a file it is unlinked.
+ *
+ * \throws MediaException
+ *
+ **/
+ void releasePath( Pathname pathname ) const;
+
+ public:
+
+ /**
+ * Return content of directory on media via retlist. If dots is false
+ * entries starting with '.' are not reported.
+ *
+ * The request is forwarded to the concrete handler,
+ * which may atempt to retieve the content e.g. via 'readdir'
+ *
+ * <B>Caution:</B> This is not supported by all media types.
+ * Be prepared to handle E_not_supported_by_media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void dirInfo( std::list<std::string> & retlist,
+ const Pathname & dirname, bool dots = true ) const;
+
+ /**
+ * Basically the same as dirInfo above. The content is returned as
+ * PathInfo::dircontent, which includes name and filetype of each directory
+ * entry. Retrieving the filetype usg. requires an additional ::stat call for
+ * each entry, thus it's more expensive than a simple readdir.
+ *
+ * <B>Caution:</B> This is not supported by all media types.
+ * Be prepared to handle E_not_supported_by_media.
+ *
+ * \throws MediaException
+ *
+ **/
+ void dirInfo( PathInfo::dircontent & retlist,
+ const Pathname & dirname, bool dots = true ) const;
+};
+
+///////////////////////////////////////////////////////////////////
+
+#define MEDIA_HANDLER_API \
+ protected: \
+ virtual void attachTo (bool next = false); \
+ virtual void releaseFrom( bool eject ); \
+ virtual void getFile( const Pathname & filename ) const; \
+ virtual void getDir( const Pathname & dirname, bool recurse_r ) const; \
+ virtual void getDirInfo( std::list<std::string> & retlist, \
+ const Pathname & dirname, bool dots = true ) const; \
+ virtual void getDirInfo( PathInfo::dircontent & retlist, \
+ const Pathname & dirname, bool dots = true ) const;
+
+ } // namespace media
+} // namespace zypp
+
+
+#endif // ZYPP_MEDIA_MEDIAHANDLERL_H
+
+