Modified MediaAccess to use MediaAria2c
authorGerard Farràs <gfarrasb@gmail.com>
Mon, 21 Jul 2008 19:00:09 +0000 (19:00 +0000)
committerGerard Farràs <gfarrasb@gmail.com>
Mon, 21 Jul 2008 19:00:09 +0000 (19:00 +0000)
devel/devel.gfarrasb/MediaHandler.cc [new file with mode: 0644]

diff --git a/devel/devel.gfarrasb/MediaHandler.cc b/devel/devel.gfarrasb/MediaHandler.cc
new file mode 100644 (file)
index 0000000..7ea9b70
--- /dev/null
@@ -0,0 +1,1400 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaHandler.cc
+ *
+*/
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include "zypp/TmpPath.h"
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+#include "zypp/media/MediaHandler.h"
+#include "zypp/media/MediaManager.h"
+#include "zypp/media/Mount.h"
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+using namespace std;
+
+// use directory.yast on every media (not just via ftp/http)
+#define NONREMOTE_DIRECTORY_YAST 1
+
+namespace zypp {
+  namespace media {
+
+  Pathname MediaHandler::_attachPrefix("");
+
+///////////////////////////////////////////////////////////////////
+//
+//     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 )
+    : _mediaSource()
+    , _attachPoint( new AttachPoint())
+    , _AttachPointHint()
+    , _relativeRoot( urlpath_below_attachpoint_r)
+    , _does_download( does_download_r )
+    , _attach_mtime(0)
+    , _url( url_r )
+    , _parentId(0)
+{
+  Pathname real_attach_point( getRealPath(attach_point_r.asString()));
+
+  if ( !real_attach_point.empty() ) {
+    ///////////////////////////////////////////////////////////////////
+    // check if provided attachpoint is usable.
+    ///////////////////////////////////////////////////////////////////
+
+    PathInfo adir( real_attach_point );
+    //
+    // The verify if attach_point_r isn't a mountpoint of another
+    // device is done in the particular media handler (if needed).
+    //
+    // We just verify, if attach_point_r is a directory and for
+    // schemes other than "file" and "dir", if it is absolute.
+    //
+    if ( !adir.isDir()
+        || (_url.getScheme() != "file"
+            && _url.getScheme() != "dir"
+            && !real_attach_point.absolute()) )
+    {
+      ERR << "Provided attach point is not a absolute directory: "
+          << adir << endl;
+    }
+    else {
+      attachPointHint( real_attach_point, false);
+      setAttachPoint( real_attach_point, false);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::~MediaHandler
+//     METHOD TYPE : Destructor
+//
+//     DESCRIPTION :
+//
+MediaHandler::~MediaHandler()
+{
+  try
+    {
+      removeAttachPoint();
+    }
+  catch(...) {}
+}
+
+void
+MediaHandler::resetParentId()
+{
+  _parentId = 0;
+}
+
+std::string
+MediaHandler::getRealPath(const std::string &path)
+{
+  std::string real;
+  if( !path.empty())
+  {
+#if __GNUC__ > 2
+    /** GNU extension */
+    char *ptr = ::realpath(path.c_str(), NULL);
+    if( ptr != NULL)
+    {
+      real = ptr;
+      free( ptr);
+    }
+    else
+    /** the SUSv2 way */
+    if( EINVAL == errno)
+    {
+      char buff[PATH_MAX + 2];
+      memset(buff, '\0', sizeof(buff));
+      if( ::realpath(path.c_str(), buff) != NULL)
+      {
+       real = buff;
+      }
+    }
+#else
+    char buff[PATH_MAX + 2];
+    memset(buff, '\0', sizeof(buff));
+    if( ::realpath(path.c_str(), buff) != NULL)
+    {
+      real = buff;
+    }
+#endif
+  }
+  return real;
+}
+
+zypp::Pathname
+MediaHandler::getRealPath(const Pathname &path)
+{
+  return zypp::Pathname(getRealPath(path.asString()));
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::removeAttachPoint
+//     METHOD TYPE : void
+//
+//     DESCRIPTION :
+//
+void
+MediaHandler::removeAttachPoint()
+{
+  if ( _mediaSource ) {
+    INT << "MediaHandler deleted with media attached." << endl;
+    return; // no cleanup if media still mounted!
+  }
+
+  DBG << "MediaHandler - checking if to remove attach point" << endl;
+  if ( _attachPoint.unique() &&
+       _attachPoint->temp    &&
+       !_attachPoint->path.empty() &&
+       PathInfo(_attachPoint->path).isDir())
+  {
+    Pathname path(_attachPoint->path);
+
+    setAttachPoint("", true);
+
+    int res = recursive_rmdir( path );
+    if ( res == 0 ) {
+      MIL << "Deleted default attach point " << path << endl;
+    } else {
+      ERR << "Failed to Delete default attach point " << path
+       << " errno(" << res << ")" << endl;
+    }
+  }
+  else
+  {
+    if( !_attachPoint->path.empty() && !_attachPoint->temp)
+      DBG << "MediaHandler - attachpoint is not temporary" << endl;
+  }
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attachPoint
+//     METHOD TYPE : Pathname
+//
+//     DESCRIPTION :
+//
+Pathname
+MediaHandler::attachPoint() const
+{
+  return _attachPoint->path;
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attachPoint
+//     METHOD TYPE :
+//
+//     DESCRIPTION :
+//
+void
+MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
+{
+  _attachPoint.reset( new AttachPoint(path, temporary));
+}
+
+Pathname
+MediaHandler::localRoot() const
+{
+  if( _attachPoint->path.empty())
+    return Pathname();
+  else
+    return _attachPoint->path + _relativeRoot;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attachPoint
+//     METHOD TYPE :
+//
+//     DESCRIPTION :
+//
+void
+MediaHandler::setAttachPoint(const AttachPointRef &ref)
+{
+  if( ref)
+    AttachPointRef(ref).swap(_attachPoint);
+  else
+    _attachPoint.reset( new AttachPoint());
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attachPointHint
+//     METHOD TYPE : void
+//
+//     DESCRIPTION :
+//
+void
+MediaHandler::attachPointHint(const Pathname &path, bool temporary)
+{
+  _AttachPointHint.path = path;
+  _AttachPointHint.temp = temporary;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attachPointHint
+//     METHOD TYPE : AttachPoint
+//
+//     DESCRIPTION :
+//
+AttachPoint
+MediaHandler::attachPointHint() const
+{
+  return _AttachPointHint;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::findAttachedMedia
+//     METHOD TYPE : AttachedMedia
+//
+//     DESCRIPTION :
+//
+AttachedMedia
+MediaHandler::findAttachedMedia(const MediaSourceRef &media) const
+{
+       return MediaManager().findAttachedMedia(media);
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::setAttachPrefix
+//     METHOD TYPE : void
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::setAttachPrefix(const Pathname &attach_prefix)
+{
+  if( attach_prefix.empty())
+  {
+    MIL << "Reseting to built-in attach point prefixes."
+        << std::endl;
+    MediaHandler::_attachPrefix = attach_prefix;
+    return true;
+  }
+  else
+  if( MediaHandler::checkAttachPoint(attach_prefix, false, true))
+  {
+    MIL << "Setting user defined attach point prefix: "
+        << attach_prefix << std::endl;
+    MediaHandler::_attachPrefix = attach_prefix;
+    return true;
+  }
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attach
+//     METHOD TYPE : Pathname
+//
+//     DESCRIPTION :
+//
+Pathname
+MediaHandler::createAttachPoint() const
+{
+  /////////////////////////////////////////////////////////////////
+  // provide a default (temporary) attachpoint
+  /////////////////////////////////////////////////////////////////
+  const char * defmounts[] = {
+      "/var/adm/mount", filesystem::TmpPath::defaultLocation().c_str(), /**/NULL/**/
+  };
+
+  Pathname apoint;
+  Pathname aroot( MediaHandler::_attachPrefix);
+
+  if( !aroot.empty())
+  {
+    apoint = createAttachPoint(aroot);
+  }
+  for ( const char ** def = defmounts; *def && apoint.empty(); ++def ) {
+    aroot = *def;
+    if( aroot.empty())
+      continue;
+
+    apoint = createAttachPoint(aroot);
+  }
+
+  if ( aroot.empty() ) {
+    ERR << "Create attach point: Can't find a writable directory to create an attach point" << std::endl;
+    return aroot;
+  }
+
+  if ( !apoint.empty() ) {
+    MIL << "Created default attach point " << apoint << std::endl;
+  }
+  return apoint;
+}
+
+Pathname
+MediaHandler::createAttachPoint(const Pathname &attach_root) const
+{
+  Pathname apoint;
+
+  if( attach_root.empty() || !attach_root.absolute()) {
+    ERR << "Create attach point: invalid attach root: '"
+        << attach_root << "'" << std::endl;
+    return apoint;
+  }
+
+  PathInfo adir( attach_root);
+  if( !adir.isDir() || (getuid() != 0 && !adir.userMayRWX())) {
+    DBG << "Create attach point: attach root is not a writable directory: '"
+        << attach_root << "'" << std::endl;
+    return apoint;
+  }
+
+  DBG << "Trying to create attach point in " << attach_root << std::endl;
+
+  //
+  // FIXME: use mkdtemp?
+  //
+#warning Use class TmpDir from TmpPath.h
+  Pathname abase( attach_root + "AP_" );
+  //        ma and sh need more than 42 for debugging :-)
+  //        since the readonly fs are handled now, ...
+  for ( unsigned i = 1; i < 1000; ++i ) {
+    adir( Pathname::extend( abase, str::hexstring( i ) ) );
+    if ( ! adir.isExist() ) {
+      int err = mkdir( adir.path() );
+      if (err == 0 ) {
+        apoint = getRealPath(adir.asString());
+       if( apoint.empty())
+       {
+         ERR << "Unable to resolve a real path for "
+             << adir.path() << std::endl;
+         rmdir(adir.path());
+       }
+        break;
+      }
+      else
+      if (err != EEXIST)       // readonly fs or other, dont try further
+        break;
+    }
+  }
+
+  if ( apoint.empty()) {
+    ERR << "Unable to create an attach point below of "
+        << attach_root << std::endl;
+  }
+  return apoint;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::isUseableAttachPoint
+//     METHOD TYPE : bool
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::isUseableAttachPoint(const Pathname &path, bool mtab) const
+{
+  MediaManager  manager;
+  return manager.isUseableAttachPoint(path, mtab);
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::setMediaSource
+//     METHOD TYPE : void
+//
+//     DESCRIPTION :
+//
+void
+MediaHandler::setMediaSource(const MediaSourceRef &ref)
+{
+  _mediaSource.reset();
+  if( ref && !ref->type.empty() && !ref->name.empty())
+    _mediaSource = ref;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attachedMedia
+//     METHOD TYPE : AttachedMedia
+//
+//     DESCRIPTION :
+//
+AttachedMedia
+MediaHandler::attachedMedia() const
+{
+  if ( _mediaSource && _attachPoint)
+    return AttachedMedia(_mediaSource, _attachPoint);
+  else
+    return AttachedMedia();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::isSharedMedia
+//     METHOD TYPE : bool
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::isSharedMedia() const
+{
+  return !_mediaSource.unique();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::checkAttached
+//     METHOD TYPE : bool
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::checkAttached(bool matchMountFs) const
+{
+  bool _isAttached = false;
+
+  AttachedMedia ref( attachedMedia());
+  if( ref.mediaSource)
+  {
+    time_t old_mtime = _attach_mtime;
+    _attach_mtime = MediaManager::getMountTableMTime();
+    if( !(old_mtime <= 0 || _attach_mtime != old_mtime))
+    {
+      // OK, skip the check (we've seen it at least once)
+      _isAttached = true;
+    }
+    else
+    {
+      if( old_mtime > 0)
+        DBG << "Mount table changed - rereading it" << std::endl;
+      else
+        DBG << "Forced check of the mount table" << std::endl;
+
+      MountEntries  entries( MediaManager::getMountEntries());
+      MountEntries::const_iterator e;
+      for( e = entries.begin(); e != entries.end(); ++e)
+      {
+        bool        is_device = false;
+        std::string dev_path(Pathname(e->src).asString());
+        PathInfo    dev_info;
+
+        if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
+            dev_info(e->src) && dev_info.isBlk())
+        {
+          is_device = true;
+        }
+
+        if( is_device &&  (ref.mediaSource->maj_nr &&
+                          ref.mediaSource->bdir.empty()))
+        {
+          std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
+          MediaSource media(mtype, e->src, dev_info.major(), dev_info.minor());
+
+          if( ref.mediaSource->equals( media) &&
+              ref.attachPoint->path == Pathname(e->dir))
+          {
+            DBG << "Found media device "
+                << ref.mediaSource->asString()
+                << " in the mount table as " << e->src << std::endl;
+            _isAttached = true;
+            break;
+          }
+          // differs
+        }
+        else
+        if(!is_device && (!ref.mediaSource->maj_nr ||
+                         !ref.mediaSource->bdir.empty()))
+        {
+          std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
+         if( ref.mediaSource->bdir.empty())
+         {
+           MediaSource media(mtype, e->src);
+
+           if( ref.mediaSource->equals( media) &&
+                ref.attachPoint->path == Pathname(e->dir))
+           {
+             DBG << "Found media name "
+                  << ref.mediaSource->asString()
+                  << " in the mount table as " << e->src << std::endl;
+             _isAttached = true;
+             break;
+           }
+         }
+         else
+         {
+           if(ref.mediaSource->bdir == e->src &&
+              ref.attachPoint->path == Pathname(e->dir))
+           {
+             DBG << "Found bound media "
+                 << ref.mediaSource->asString()
+                 << " in the mount table as " << e->src << std::endl;
+             _isAttached = true;
+             break;
+           }
+         }
+          // differs
+        }
+      }
+
+      if( !_isAttached)
+      {
+       if(  entries.empty())
+       {
+         ERR << "Unable to find any entry in the /etc/mtab file" << std::endl;
+       }
+       else
+       {
+         MountEntries::const_iterator e;
+         for( e = entries.begin(); e != entries.end(); ++e)
+         {
+           XXX << "mount entry: " << e->src << " on " << e->dir
+               << " type " << e->type << "(" << e->opts << ")" << endl;
+         }
+       }
+       if( old_mtime > 0)
+       {
+          ERR << "Attached media not in mount table any more - forcing reset!"
+              << std::endl;
+
+         _mediaSource.reset();
+       }
+       else
+       {
+          WAR << "Attached media not in mount table ..." << std::endl;
+       }
+
+        // reset the mtime and force a new check to make sure,
+        // that we've found the media at least once in the mtab.
+        _attach_mtime = 0;
+      }
+    }
+  }
+  return _isAttached;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::attach
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::attach( bool next )
+{
+  if ( isAttached() )
+    return;
+
+  // reset it in case of overloaded isAttached()
+  // that checks the media against /etc/mtab ...
+  setMediaSource(MediaSourceRef());
+
+  AttachPoint ap( attachPointHint());
+  setAttachPoint(ap.path, ap.temp);
+
+  try
+  {
+    attachTo( next ); // pass to concrete handler
+  }
+  catch(const MediaException &e)
+  {
+    removeAttachPoint();
+    ZYPP_RETHROW(e);
+  }
+  MIL << "Attached: " << *this << endl;
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::localPath
+//     METHOD TYPE : Pathname
+//
+Pathname MediaHandler::localPath( const Pathname & pathname ) const
+{
+    Pathname _localRoot( localRoot());
+    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;
+
+  disconnectFrom(); // pass to concrete handler
+  MIL << "Disconnected: " << *this << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::release
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::release( const std::string & ejectDev )
+{
+  if ( !isAttached() ) {
+    DBG << "Request to release media - not attached; eject '" << ejectDev << "'"
+        << std::endl;
+    if ( !ejectDev.empty() )
+      forceEject(ejectDev);
+    return;
+  }
+
+  DBG << "Request to release attached media "
+      << _mediaSource->asString()
+      << ", use count=" << _mediaSource.use_count()
+      << std::endl;
+
+  if( _mediaSource.unique())
+  {
+    DBG << "Releasing media " << _mediaSource->asString() << std::endl;
+    try {
+      releaseFrom( ejectDev ); // pass to concrete handler
+    }
+    catch(const MediaNotEjectedException &e)
+    {
+      // not ejected because the media
+      // is mounted by somebody else
+      // (if our attach point is busy,
+      //  we get an umount exception)
+      _mediaSource.reset(NULL);
+      removeAttachPoint();
+      // OK, retrow now
+      ZYPP_RETHROW(e);
+    }
+    _mediaSource.reset(NULL);
+    removeAttachPoint();
+  }
+  else if( !ejectDev.empty() ) {
+    //
+    // Can't eject a shared media
+    //
+    //ZYPP_THROW(MediaIsSharedException(_mediaSource->asString()));
+
+    MediaSourceRef media( new MediaSource(*_mediaSource));
+    _mediaSource.reset(NULL);
+
+    MediaManager manager;
+    manager.forceReleaseShared(media);
+
+    setMediaSource(media);
+    DBG << "Releasing media (forced) " << _mediaSource->asString() << std::endl;
+    try {
+      releaseFrom( ejectDev ); // pass to concrete handler
+    }
+    catch(const MediaNotEjectedException &e)
+    {
+      // not ejected because the media
+      // is mounted by somebody else
+      // (if our attach point is busy,
+      //  we get an umount exception)
+      _mediaSource.reset(NULL);
+      removeAttachPoint();
+      // OK, retrow now
+      ZYPP_RETHROW(e);
+    }
+    _mediaSource.reset(NULL);
+    removeAttachPoint();
+  }
+  else {
+    DBG << "Releasing shared media reference only" << std::endl;
+    _mediaSource.reset(NULL);
+    setAttachPoint("", true);
+  }
+  MIL << "Released: " << *this << endl;
+}
+
+bool MediaHandler::isAutoMountedMedia(const AttachedMedia &media)
+{
+  (void)media;
+  return false;
+}
+
+void MediaHandler::forceRelaseAllMedia(bool matchMountFs, bool autoMountedOny)
+{
+  forceRelaseAllMedia( attachedMedia().mediaSource, matchMountFs, autoMountedOny);
+}
+
+void MediaHandler::forceRelaseAllMedia(const MediaSourceRef &ref,
+                                       bool                  matchMountFs,
+                                      bool                  autoMountedOny)
+{
+  if( !ref)
+    return;
+
+  MountEntries  entries( MediaManager::getMountEntries());
+  MountEntries::const_iterator e;
+  for( e = entries.begin(); e != entries.end(); ++e)
+  {
+    bool        is_device = false;
+    std::string dev_path(Pathname(e->src).asString());
+    PathInfo    dev_info;
+
+    if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
+        dev_info(e->src) && dev_info.isBlk())
+    {
+      is_device = true;
+    }
+
+    if( is_device &&  ref->maj_nr)
+    {
+      std::string mtype(matchMountFs ? e->type : ref->type);
+      MediaSource media(mtype, e->src, dev_info.major(), dev_info.minor());
+
+      if( ref->equals( media) && e->type != "subfs")
+      {
+       if(autoMountedOny)
+       {
+         try {
+           AttachedMedia am(MediaSourceRef(new MediaSource(media)),
+                            AttachPointRef(new AttachPoint(e->dir)));
+           if( !isAutoMountedMedia(am))
+             continue;
+         }
+         catch(...)
+         {
+             continue;
+         }
+       }
+        DBG << "Forcing release of media device "
+            << ref->asString()
+            << " in the mount table as "
+           << e->src << std::endl;
+       try {
+         Mount mount;
+         mount.umount(e->dir);
+       }
+       catch (const Exception &e)
+       {
+         ZYPP_CAUGHT(e);
+       }
+      }
+    }
+    else
+    if(!is_device && !ref->maj_nr)
+    {
+      std::string mtype(matchMountFs ? e->type : ref->type);
+      MediaSource media(mtype, e->src);
+      if( ref->equals( media))
+      {
+       if(autoMountedOny)
+       {
+         try {
+           AttachedMedia am(MediaSourceRef(new MediaSource(media)),
+                            AttachPointRef(new AttachPoint(e->dir)));
+           if( !isAutoMountedMedia(am))
+             continue;
+         }
+         catch(...)
+         {
+             continue;
+         }
+       }
+       DBG << "Forcing release of media name "
+           << ref->asString()
+           << " in the mount table as "
+           << e->src << std::endl;
+       try {
+         Mount mount;
+         mount.umount(e->dir);
+       }
+       catch (const Exception &e)
+       {
+         ZYPP_CAUGHT(e);
+       }
+      }
+    }
+  }
+}
+
+bool
+MediaHandler::checkAttachPoint(const Pathname &apoint) const
+{
+  return MediaHandler::checkAttachPoint( apoint, true, false);
+}
+
+// STATIC
+bool
+MediaHandler::checkAttachPoint(const Pathname &apoint,
+                              bool            emptydir,
+                              bool            writeable)
+{
+  if( apoint.empty() || !apoint.absolute())
+  {
+    ERR << "Attach point '" << apoint << "' is not absolute"
+        << std::endl;
+    return false;
+  }
+  if( apoint == "/")
+  {
+    ERR << "Attach point '" << apoint << "' is not allowed"
+        << std::endl;
+    return false;
+  }
+
+  PathInfo ainfo(apoint);
+  if( !ainfo.isDir())
+  {
+    ERR << "Attach point '" << apoint << "' is not a directory"
+        << std::endl;
+    return false;
+  }
+
+  if( emptydir)
+  {
+    if( 0 != zypp::filesystem::is_empty_dir(apoint))
+    {
+      ERR << "Attach point '" << apoint << "' is not a empty directory"
+          << std::endl;
+      return false;
+    }
+  }
+
+  if( writeable)
+  {
+    Pathname apath(apoint + "XXXXXX");
+    char    *atemp = ::strdup( apath.asString().c_str());
+    char    *atest = NULL;
+    if( !ainfo.userMayRWX() || atemp == NULL ||
+        (atest=::mkdtemp(atemp)) == NULL)
+    {
+      if( atemp != NULL)
+       ::free(atemp);
+
+      ERR << "Attach point '" << ainfo.path()
+          << "' is not a writeable directory" << std::endl;
+      return false;
+    }
+    else if( atest != NULL)
+      ::rmdir(atest);
+
+    if( atemp != NULL)
+      ::free(atemp);
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//     METHOD NAME : MediaHandler::dependsOnParent
+//     METHOD TYPE : bool
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::dependsOnParent()
+{
+  return _parentId != 0;
+}
+
+bool
+MediaHandler::dependsOnParent(MediaAccessId parentId, bool exactIdMatch)
+{
+  if( _parentId != 0)
+  {
+    if(parentId == _parentId)
+      return true;
+
+    if( !exactIdMatch)
+    {
+      MediaManager mm;
+      AttachedMedia am1 = mm.getAttachedMedia(_parentId);
+      AttachedMedia am2 = mm.getAttachedMedia(parentId);
+      if( am1.mediaSource && am2.mediaSource)
+      {
+       return am1.mediaSource->equals( *(am2.mediaSource));
+      }
+    }
+  }
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::provideFile
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::provideFileCopy( Pathname srcFilename,
+                                       Pathname targetFilename ) const
+{
+  if ( !isAttached() ) {
+    INT << "Media not_attached on provideFileCopy(" << srcFilename
+        << "," << targetFilename << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+
+  getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
+  DBG << "provideFileCopy(" << srcFilename << "," << targetFilename  << ")" << endl;
+}
+
+void MediaHandler::provideFile( Pathname filename ) const
+{
+  if ( !isAttached() ) {
+    INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+
+  getFile( filename ); // pass to concrete handler
+  DBG << "provideFile(" << filename << ")" << endl;
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::provideDir
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::provideDir( Pathname dirname ) const
+{
+  if ( !isAttached() ) {
+    INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+
+  getDir( dirname, /*recursive*/false ); // pass to concrete handler
+  MIL << "provideDir(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::provideDirTree
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::provideDirTree( Pathname dirname ) const
+{
+  if ( !isAttached() ) {
+    INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+
+  getDir( dirname, /*recursive*/true ); // pass to concrete handler
+  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() ) {
+    unlink( info.path() );
+  } else if ( info.isDir() ) {
+    if ( info.path() != localRoot() ) {
+      recursive_rmdir( info.path() );
+    } else {
+      clean_dir( info.path() );
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::dirInfo
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::dirInfo( std::list<std::string> & retlist,
+                            const Pathname & dirname, bool dots ) const
+{
+  retlist.clear();
+
+  if ( !isAttached() ) {
+    INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+
+  getDirInfo( retlist, dirname, dots ); // pass to concrete handler
+  MIL << "dirInfo(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::dirInfo
+//     METHOD TYPE : PMError
+//
+//     DESCRIPTION :
+//
+void MediaHandler::dirInfo( filesystem::DirContent & retlist,
+                            const Pathname & dirname, bool dots ) const
+{
+  retlist.clear();
+
+  if ( !isAttached() ) {
+    INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+
+  getDirInfo( retlist, dirname, dots ); // pass to concrete handler
+  MIL << "dirInfo(" << dirname << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//      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
+//
+void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
+                                       const Pathname & dirname, bool dots ) const
+{
+  retlist.clear();
+
+  filesystem::DirContent content;
+  getDirectoryYast( content, dirname, dots );
+
+  // convert to std::list<std::string>
+  for ( filesystem::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( filesystem::DirContent & retlist,
+                                     const Pathname & dirname, bool dots ) const
+{
+  retlist.clear();
+
+  // look for directory.yast
+  Pathname dirFile = dirname + "directory.yast";
+  getFile( dirFile );
+  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;
+    ZYPP_THROW(MediaSystemException(url(),
+      "Unable to load '" + localPath( dirFile ).asString() + "'"));
+  }
+
+  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.
+    filesystem::FileType type = filesystem::FT_NOT_AVAIL;
+    if ( *line.rbegin() == '/' ) {
+      line.erase( line.end()-1 );
+      type = filesystem::FT_DIR;
+    }
+
+    if ( dots ) {
+      if ( line == "." || line == ".." ) continue;
+    } else {
+      if ( *line.begin() == '.' ) continue;
+    }
+
+    retlist.push_back( filesystem::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())
+      ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
+    else
+      ZYPP_THROW(MediaFileNotFoundException(url(), filename));
+}
+
+
+void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
+{
+  getFile(srcFilename);
+
+  if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
+    ZYPP_THROW(MediaWriteException(targetFilename));
+  }
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     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())
+    ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
+  else
+    ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     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() ) {
+    ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
+  }
+
+#if NONREMOTE_DIRECTORY_YAST
+  // use directory.yast if available
+  try {
+    getDirectoryYast( retlist, dirname, dots );
+  }
+  catch (const MediaException & excpt_r)
+  {
+#endif
+
+    // readdir
+    int res = readdir( retlist, info.path(), dots );
+    if ( res )
+    {
+      MediaSystemException nexcpt(url(), "readdir failed");
+#if NONREMOTE_DIRECTORY_YAST
+      nexcpt.remember(excpt_r);
+#endif
+      ZYPP_THROW(nexcpt);
+    }
+
+#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( filesystem::DirContent & retlist,
+                               const Pathname & dirname, bool dots ) const
+{
+  PathInfo info( localPath( dirname ) );
+  if( ! info.isDir() ) {
+    ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
+  }
+
+#if NONREMOTE_DIRECTORY_YAST
+  // use directory.yast if available
+  try {
+    getDirectoryYast( retlist, dirname, dots );
+  }
+  catch (const MediaException & excpt_r)
+  {
+#endif
+
+    // readdir
+    int res = readdir( retlist, info.path(), dots );
+    if ( res )
+    {
+       MediaSystemException nexcpt(url(), "readdir failed");
+#if NONREMOTE_DIRECTORY_YAST
+       nexcpt.remember(excpt_r);
+#endif
+       ZYPP_THROW(nexcpt);
+    }
+#if NONREMOTE_DIRECTORY_YAST
+  }
+#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();
+}
+
+bool MediaHandler::hasMoreDevices()
+{
+  return false;
+}
+
+void MediaHandler::getDetectedDevices(std::vector<std::string> & devices,
+                                      unsigned int & index) const
+{
+  // clear the vector by default
+  if (!devices.empty())
+    devices.clear();
+  index = 0;
+
+  DBG << "No devices for this medium" << endl;
+}
+
+
+  } // namespace media
+} // namespace zypp
+// vim: set ts=8 sts=2 sw=2 ai noet: