Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / media / MediaManager.cc
index 8d7f2d2..7295132 100644 (file)
@@ -9,22 +9,22 @@
 /** \file zypp/media/MediaManager.cc
  *
 */
-#include <zypp/media/MediaException.h>
-#include <zypp/media/MediaManager.h>
-//#include <zypp/media/Mount.h>
-//#include <zypp/media/Hal.h>
-#include <zypp/thread/Mutex.h>
-#include <zypp/thread/MutexLock.h>
-
-#include <zypp/base/String.h>
-#include <zypp/base/Logger.h>
-#include <zypp/Pathname.h>
-#include <zypp/PathInfo.h>
-
 #include <map>
 #include <list>
 #include <iostream>
+#include <typeinfo>
+
+#include "zypp/media/MediaException.h"
+#include "zypp/media/MediaManager.h"
+#include "zypp/media/MediaHandler.h"
+#include "zypp/media/Mount.h"
+#include "zypp/thread/Mutex.h"
+#include "zypp/thread/MutexLock.h"
 
+#include "zypp/base/String.h"
+#include "zypp/base/Logger.h"
+#include "zypp/Pathname.h"
+#include "zypp/PathInfo.h"
 
 //////////////////////////////////////////////////////////////////////
 namespace zypp
@@ -46,80 +46,209 @@ namespace zypp
       // STATIC
       static Mutex  g_Mutex;
 
-      typedef std::map<MediaId, MediaVerifierRef> MediaVfyMap;
-      typedef std::map<MediaId, MediaAccessRef>   MediaAccMap;
 
+      // -------------------------------------------------------------
+      struct ManagedMedia
+      {
+        ~ManagedMedia()
+        {}
+
+        ManagedMedia()
+          : desired (false)
+        {}
+
+        ManagedMedia(const ManagedMedia &m)
+          : desired (m.desired)
+          , handler (m.handler)
+          , verifier(m.verifier)
+        {}
+
+        ManagedMedia(const MediaAccessRef &h, const MediaVerifierRef &v)
+          : desired (false)
+          , handler (h)
+          , verifier(v)
+        {}
+
+        inline void
+        checkAttached(MediaAccessId id)
+        {
+          if( !handler->isAttached())
+          {
+            DBG << "checkAttached(" << id << ") not attached" << std::endl;
+            desired = false;
+            ZYPP_THROW(MediaNotAttachedException(
+              handler->url()
+            ));
+          }
+        }
+
+        inline void
+        checkDesired(MediaAccessId id)
+        {
+          checkAttached(id);
+
+          if( !desired)
+          {
+            try {
+              desired = verifier->isDesiredMedia(handler);
+            }
+            catch(const zypp::Exception &e) {
+              ZYPP_CAUGHT(e);
+              desired = false;
+            }
+
+            if( !desired)
+            {
+              DBG << "checkDesired(" << id << "): not desired (report by "
+                  << verifier->info() << ")" << std::endl;
+              ZYPP_THROW(MediaNotDesiredException(
+                handler->url()
+              ));
+            }
+
+            DBG << "checkDesired(" << id << "): desired (report by "
+                << verifier->info() << ")" << std::endl;
+          } else {
+            DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
+          }
+        }
+
+        bool             desired;
+        MediaAccessRef   handler;
+        MediaVerifierRef verifier;
+      };
+
+
+      // -------------------------------------------------------------
+      typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
 
       ////////////////////////////////////////////////////////////////
     } // anonymous
     //////////////////////////////////////////////////////////////////
 
 
-    // ---------------------------------------------------------------
-    class MediaManager::Impl
+    //////////////////////////////////////////////////////////////////
+    std::string
+    MediaVerifierBase::info() const
+    {
+      return std::string(typeid((*this)).name());
+    }
+
+
+    //////////////////////////////////////////////////////////////////
+    std::string
+    NoVerifier::info() const
+    {
+      return std::string("zypp::media::NoVerifier");
+    }
+
+
+    //////////////////////////////////////////////////////////////////
+    class MediaManager_Impl
     {
     private:
-    /*
-      time_t       mtab_mtime;
-      MountEntries mtab_table;
-    */
-      MediaId      last_mediaid;
+      friend class MediaManager;
 
-    public:
-      MediaVfyMap  mediaVfyMap;
-      MediaAccMap  mediaAccMap;
+      MediaAccessId       last_accessid;
+      ManagedMediaMap     mediaMap;
 
-      Impl()
-        : /* mtab_mtime(0)
-        , */ last_mediaid(0)
+      MediaManager_Impl()
+        : last_accessid(0)
       {}
 
-      ~Impl()
-      {}
+    public:
+      ~MediaManager_Impl()
+      {
+        MutexLock glock(g_Mutex);
 
-      MediaId
-      nextMediaId()
+        try
+        {
+          // remove depending (iso) handlers first
+          ManagedMediaMap::iterator it;
+          bool found;
+          do
+          {
+            found = false;
+            for(it = mediaMap.begin(); it != mediaMap.end(); /**/)
+            {
+              if( it->second.handler->dependsOnParent())
+              {
+                found = true;
+                // let it forget its parent, we will
+                // destroy it later (in clear())...
+                it->second.handler->resetParentId();
+                mediaMap.erase( it++ ); // postfix! Incrementing before erase
+              } else {
+                ++it;
+              }
+            }
+          } while(found);
+
+          // remove all other handlers
+          mediaMap.clear();
+        }
+        catch( ... )
+        {}
+      }
+
+      inline MediaAccessId
+      nextAccessId()
       {
-        return last_mediaid++;
+        return ++last_accessid;
       }
 
-      bool hasMediaAcc(MediaId mediaId) const
+      inline bool
+      hasId(MediaAccessId accessId) const
       {
-        return mediaAccMap.find(mediaId) != mediaAccMap.end();
+        return mediaMap.find(accessId) != mediaMap.end();
       }
 
-      bool hasVerifier(MediaId mediaId) const
+      inline ManagedMedia &
+      findMM(MediaAccessId accessId)
       {
-        return mediaVfyMap.find(mediaId) != mediaVfyMap.end();
+        ManagedMediaMap::iterator it( mediaMap.find(accessId));
+        if( it == mediaMap.end())
+        {
+          ZYPP_THROW(MediaNotOpenException(
+            "Invalid media access id " + str::numstring(accessId)
+          ));
+        }
+        return it->second;
       }
 
-      /*
-      MountEntries
-      getMountEntries()
+      static inline time_t
+      getMountTableMTime()
       {
-        if( mtab_mtime == 0 ||
-            mtab_mtime != zypp::PathInfo("/etc/mtab").mtime())
+        time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
+        if( mtime <= 0)
         {
-          mtab_table = Mount::getEntries("/etc/mtab");
+          WAR << "Failed to retrieve modification time of '/etc/mtab'"
+              << std::endl;
         }
-        return mtab_table;
+        return mtime;
+      }
+
+      static inline MountEntries
+      getMountEntries()
+      {
+        return Mount::getEntries();
       }
-      */
+
     };
 
 
-    // ---------------------------------------------------------------
+    //////////////////////////////////////////////////////////////////
     // STATIC
-    zypp::RW_pointer<MediaManager::Impl> MediaManager::m_impl(NULL);
+    zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl;
 
 
-    // ---------------------------------------------------------------
+    //////////////////////////////////////////////////////////////////
     MediaManager::MediaManager()
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
       if( !m_impl)
       {
-        m_impl.reset( new MediaManager::Impl());
+        m_impl.reset( new MediaManager_Impl());
       }
     }
 
@@ -129,381 +258,729 @@ namespace zypp
     }
 
     // ---------------------------------------------------------------
-    MediaId
+    MediaAccessId
     MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
     {
-      MutexLock lock(g_Mutex);
-
-      // check if we already have this url
-      MediaAccMap::const_iterator a(m_impl->mediaAccMap.begin());
-      for( ; a != m_impl->mediaAccMap.end(); ++a)
-      {
-        // FIXME: not sufficient. each handler should provide
-        //        method to compare its type of media url
-        //        and MediaAccess to choose right handler...
-        if( a->second->url().asString() == url.asString())
-        {
-          return a->first;
-        }
-      }
+      MutexLock glock(g_Mutex);
 
       // create new access handler for it
-      MediaAccessRef accRef( new MediaAccess());
+      MediaAccessRef handler( new MediaAccess());
+      MediaVerifierRef verifier( new NoVerifier());
+      ManagedMedia tmp( handler, verifier);
 
-      accRef->open(url, preferred_attach_point);
+      tmp.handler->open(url, preferred_attach_point);
 
-      MediaId nextId = m_impl->nextMediaId();
+      MediaAccessId nextId = m_impl->nextAccessId();
 
-      m_impl->mediaAccMap[nextId] = accRef;
+      m_impl->mediaMap[nextId] = tmp;
 
+      DBG << "Opened new media access using id " << nextId
+          << " to " << url.asString() << std::endl;
       return nextId;
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::close(MediaId mediaId)
+    MediaManager::close(MediaAccessId accessId)
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
+
+      //
+      // The MediaISO handler internally requests an accessId
+      // of a "parent" handler providing the iso file.
+      // The parent handler accessId is private to MediaISO,
+      // but the attached media source may be shared reference.
+      // This means, that if the accessId exactly matches the
+      // parent handler id, close was used on uninitialized
+      // accessId variable (or the accessId was guessed) and
+      // the close request to this id will be rejected here.
+      //
+      ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
+      {
+        if( m->second.handler->dependsOnParent(accessId, true))
+        {
+          ZYPP_THROW(MediaIsSharedException(
+            m->second.handler->url().asString()
+          ));
+        }
+      }
 
-      if( !m_impl->hasMediaAcc( mediaId))
-        ZYPP_THROW(MediaException("Invalid media id"));
+      DBG << "Close to access handler using id "
+          << accessId << " requested" << std::endl;
 
-      if( m_impl->hasVerifier( mediaId))
-        m_impl->mediaVfyMap.erase(mediaId);
+      ManagedMedia &ref( m_impl->findMM(accessId));
+      ref.handler->close();
 
-      m_impl->mediaAccMap[mediaId]->close();
-      m_impl->mediaAccMap.erase(mediaId);
+      m_impl->mediaMap.erase(accessId);
     }
 
     // ---------------------------------------------------------------
     bool
-    MediaManager::isOpen(MediaId mediaId) const
+    MediaManager::isOpen(MediaAccessId accessId) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      return m_impl->hasMediaAcc( mediaId);
+      ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
+      return it != m_impl->mediaMap.end() &&
+             it->second.handler->isOpen();
     }
 
     // ---------------------------------------------------------------
     std::string
-    MediaManager::protocol(MediaId mediaId) const
+    MediaManager::protocol(MediaAccessId accessId) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( m_impl->hasMediaAcc( mediaId))
-        return m_impl->mediaAccMap[mediaId]->protocol();
-      else
-        return std::string("unknown");
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      return ref.handler->protocol();
+    }
+
+    // ---------------------------------------------------------------
+         bool
+    MediaManager::downloads(MediaAccessId accessId) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      return ref.handler->downloads();
     }
 
     // ---------------------------------------------------------------
     Url
-    MediaManager::url(MediaId mediaId) const
+    MediaManager::url(MediaAccessId accessId) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( m_impl->hasMediaAcc( mediaId))
-        return m_impl->mediaAccMap[mediaId]->url();
-      else
-        return Url();
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      return ref.handler->url();
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::addVerifier(MediaId mediaId, const MediaVerifierRef &ref)
+    MediaManager::addVerifier(MediaAccessId           accessId,
+                              const MediaVerifierRef &verifier)
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !ref)
-        ZYPP_THROW(MediaException("Invalid (empty) verifier reference"));
+      if( !verifier)
+        ZYPP_THROW(MediaException("Invalid verifier reference"));
 
-      if( !m_impl->hasMediaAcc( mediaId))
-        ZYPP_THROW(MediaException("Invalid media id"));
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      // FIXME: just replace?
-      if( m_impl->hasVerifier( mediaId))
-        ZYPP_THROW(MediaException("Remove verifier first"));
+      ref.desired = false;
+      MediaVerifierRef(verifier).swap(ref.verifier);
 
-      m_impl->mediaVfyMap[mediaId] = ref;
+      DBG << "MediaVerifier change: id=" << accessId << ", verifier="
+          << verifier->info() << std::endl;
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::delVerifier(MediaId mediaId)
+    MediaManager::delVerifier(MediaAccessId accessId)
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
-        ZYPP_THROW(MediaException("Invalid media id"));
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      if( m_impl->hasVerifier( mediaId))
-        m_impl->mediaVfyMap.erase(mediaId);
+      MediaVerifierRef verifier( new NoVerifier());
+      ref.desired  = false;
+      ref.verifier.swap(verifier);
+
+      DBG << "MediaVerifier change: id=" << accessId << ", verifier="
+          << verifier->info() << std::endl;
     }
 
     // ---------------------------------------------------------------
-    void
-    MediaManager::attach(MediaId mediaId, bool next)
+    bool
+    MediaManager::setAttachPrefix(const Pathname &attach_prefix)
+    {
+      MutexLock glock(g_Mutex);
+
+      return MediaHandler::setAttachPrefix(attach_prefix);
+    }
+
+    // ---------------------------------------------------------------
+    void MediaManager::attach(MediaAccessId accessId)
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      DBG << "attach(id=" << accessId << ")" << std::endl;
+
+      // try first mountable/mounted device
+      ref.handler->attach(false);
+      try
       {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
+        ref.checkDesired(accessId);
+        return;
       }
+      catch (const MediaException & ex)
+      {
+        ZYPP_CAUGHT(ex);
 
-      if( !m_impl->hasVerifier( mediaId))
-        ZYPP_THROW(MediaException("Add a verifier first"));
+        if (!ref.handler->hasMoreDevices())
+          ZYPP_RETHROW(ex);
 
-      m_impl->mediaAccMap[mediaId]->attach(next);
+        if (ref.handler->isAttached())
+          ref.handler->release();
+      }
+
+      MIL << "checkDesired(" << accessId << ") of first device failed,"
+        " going to try others with attach(true)" << std::endl;
+
+      while (ref.handler->hasMoreDevices())
+      {
+        try
+        {
+          // try to attach next device
+          ref.handler->attach(true);
+          ref.checkDesired(accessId);
+          return;
+        }
+        catch (const MediaNotDesiredException & ex)
+        {
+          ZYPP_CAUGHT(ex);
+
+          if (!ref.handler->hasMoreDevices())
+          {
+            MIL << "No desired media found after trying all detected devices." << std::endl;
+            ZYPP_RETHROW(ex);
+          }
+
+          AttachedMedia media(ref.handler->attachedMedia());
+          DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
+
+          ref.handler->release();
+        }
+        catch (const MediaException & ex)
+        {
+          ZYPP_CAUGHT(ex);
+
+          if (!ref.handler->hasMoreDevices())
+            ZYPP_RETHROW(ex);
+
+          AttachedMedia media(ref.handler->attachedMedia());
+          DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
+
+          if (ref.handler->isAttached()) ref.handler->release();
+        }
+      }
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::release(MediaId mediaId, bool eject)
+    MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      if( !m_impl->hasMediaAcc( mediaId))
+      DBG << "release(id=" << accessId;
+      if (!ejectDev.empty())
+        DBG << ", " << ejectDev;
+      DBG << ")" << std::endl;
+
+      if(!ejectDev.empty())
       {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
+        //
+        // release MediaISO handlers, that are using the one
+        // specified with accessId, because it provides the
+        // iso file and it will disappear now (forced release
+        // with eject).
+        //
+        ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
+        for( ; m != m_impl->mediaMap.end(); ++m)
+        {
+          if( m->second.handler->dependsOnParent(accessId, false))
+          {
+            try
+            {
+              DBG << "Forcing release of handler depending on access id "
+                  << accessId << std::endl;
+              m->second.desired  = false;
+              m->second.handler->release();
+            }
+            catch(const MediaException &e)
+            {
+              ZYPP_CAUGHT(e);
+            }
+          }
+        }
       }
-
-      m_impl->mediaAccMap[mediaId]->release(eject);
+      ref.desired  = false;
+      ref.handler->release(ejectDev);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::disconnect(MediaId mediaId)
+    MediaManager::releaseAll()
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
+      MIL << "Releasing all attached media" << std::endl;
+
+      ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
       {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
+        if( m->second.handler->dependsOnParent())
+          continue;
+
+        try
+        {
+          if(m->second.handler->isAttached())
+          {
+            DBG << "Releasing media id " << m->first << std::endl;
+            m->second.desired  = false;
+            m->second.handler->release();
+          }
+          else
+          {
+            DBG << "Media id " << m->first << " not attached " << std::endl;
+          }
+        }
+        catch(const MediaException & e)
+        {
+          ZYPP_CAUGHT(e);
+          ERR << "Failed to release media id " << m->first << std::endl;
+        }
       }
-      return m_impl->mediaAccMap[mediaId]->disconnect();
+
+      MIL << "Exit" << std::endl;
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::disconnect(MediaAccessId accessId)
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      ref.handler->disconnect();
     }
 
     // ---------------------------------------------------------------
     bool
-    MediaManager::isAttached(MediaId mediaId) const
+    MediaManager::isAttached(MediaAccessId accessId) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      return ref.handler->isAttached();
+    }
 
-      if( !m_impl->hasMediaAcc( mediaId))
+    // ---------------------------------------------------------------
+    bool MediaManager::isSharedMedia(MediaAccessId accessId) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      return ref.handler->isSharedMedia();
+    }
+
+    // ---------------------------------------------------------------
+    bool
+    MediaManager::isDesiredMedia(MediaAccessId accessId) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      if( !ref.handler->isAttached())
       {
-        // FIXME: throw or just return false?
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
+        ref.desired = false;
+      }
+      else
+      {
+        try {
+          ref.desired = ref.verifier->isDesiredMedia(ref.handler);
+        }
+        catch(const zypp::Exception &e) {
+          ZYPP_CAUGHT(e);
+          ref.desired = false;
+        }
       }
-      return m_impl->mediaAccMap[mediaId]->isAttached();
+      DBG << "isDesiredMedia(" << accessId << "): "
+          << (ref.desired ? "" : "not ")
+          << "desired (report by "
+          << ref.verifier->info() << ")" << std::endl;
+      return ref.desired;
     }
 
     // ---------------------------------------------------------------
     bool
-    MediaManager::isDesiredMedia(MediaId mediaId, MediaNr mediaNr) const
+    MediaManager::isDesiredMedia(MediaAccessId           accessId,
+                                 const MediaVerifierRef &verifier) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !isAttached(mediaId))
-        return false;
+      MediaVerifierRef v(verifier);
+      if( !v)
+        ZYPP_THROW(MediaException("Invalid verifier reference"));
 
-      // FIXME: throw or just return false?
-      if( !m_impl->hasVerifier( mediaId))
-        ZYPP_THROW(MediaException("Add a verifier first"));
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      bool ok;
-      try {
-        ok = m_impl->mediaVfyMap[mediaId]->isDesiredMedia(
-          m_impl->mediaAccMap[mediaId], mediaNr
-        );
+      bool desired = false;
+      if( ref.handler->isAttached())
+      {
+        try {
+          desired = v->isDesiredMedia(ref.handler);
+        }
+        catch(const zypp::Exception &e) {
+          ZYPP_CAUGHT(e);
+          desired = false;
+        }
       }
-      catch( ... ) { ok = false; }
-      return ok;
+      DBG << "isDesiredMedia(" << accessId << "): "
+          << (desired ? "" : "not ")
+          << "desired (report by "
+          << v->info() << ")" << std::endl;
+      return desired;
+    }
+
+    // ---------------------------------------------------------------
+    bool
+    MediaManager::isChangeable(MediaAccessId accessId)
+    {
+      return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
     }
 
     // ---------------------------------------------------------------
     Pathname
-    MediaManager::localRoot(MediaId mediaId) const
+    MediaManager::localRoot(MediaAccessId accessId) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      if( !m_impl->hasMediaAcc( mediaId))
-      {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
-      }
       Pathname path;
-      path = m_impl->mediaAccMap[mediaId]->localRoot();
+      path = ref.handler->localRoot();
       return path;
     }
 
     // ---------------------------------------------------------------
     Pathname
-    MediaManager::localPath(MediaId mediaId,
+    MediaManager::localPath(MediaAccessId accessId,
                             const Pathname & pathname) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      if( !m_impl->hasMediaAcc( mediaId))
-      {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
-      }
       Pathname path;
-      path = m_impl->mediaAccMap[mediaId]->localPath(pathname);
+      path = ref.handler->localPath(pathname);
       return path;
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::provideFile(MediaId mediaId, MediaNr mediaNr,
-                              const Pathname &filename,
-                              bool cached, bool checkonly) const
+    MediaManager::provideFile(MediaAccessId   accessId,
+                              const Pathname &filename ) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !isDesiredMedia(mediaId, mediaNr))
-      {
-        ZYPP_THROW(MediaNotDesiredException(
-          m_impl->mediaAccMap[mediaId]->url(), mediaNr
-        ));
-      }
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      m_impl->mediaAccMap[mediaId]->provideFile(filename, cached, checkonly);
+      ref.checkDesired(accessId);
+
+      ref.handler->provideFile(filename);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::provideDir(MediaId mediaId,
-                             MediaNr mediaNr,
-                             const Pathname & dirname ) const
+    MediaManager::setDeltafile(MediaAccessId   accessId,
+                              const Pathname &filename ) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !isDesiredMedia(mediaId, mediaNr))
-      {
-        ZYPP_THROW(MediaNotDesiredException(
-          m_impl->mediaAccMap[mediaId]->url(), mediaNr
-        ));
-      }
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      ref.checkDesired(accessId);
 
-      m_impl->mediaAccMap[mediaId]->provideDir(dirname);
+      ref.handler->setDeltafile(filename);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::provideDirTree(MediaId mediaId,
-                                 MediaNr mediaNr,
-                                 const Pathname & dirname ) const
+    MediaManager::provideDir(MediaAccessId   accessId,
+                             const Pathname &dirname) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !isDesiredMedia(mediaId, mediaNr))
-      {
-        ZYPP_THROW(MediaNotDesiredException(
-          m_impl->mediaAccMap[mediaId]->url(), mediaNr
-        ));
-      }
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      ref.checkDesired(accessId);
 
-      m_impl->mediaAccMap[mediaId]->provideDirTree(dirname);
+      ref.handler->provideDir(dirname);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::releaseFile(MediaId mediaId,
-                              const Pathname & filename) const
+    MediaManager::provideDirTree(MediaAccessId   accessId,
+                                 const Pathname &dirname) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
-      {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
-      }
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      m_impl->mediaAccMap[mediaId]->releaseFile(filename);
+      ref.checkDesired(accessId);
+
+      ref.handler->provideDirTree(dirname);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::releaseDir(MediaId mediaId,
-                             const Pathname & dirname) const
+    MediaManager::releaseFile(MediaAccessId   accessId,
+                              const Pathname &filename) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
-      {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
-      }
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      ref.checkAttached(accessId);
+
+      ref.handler->releaseFile(filename);
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::releaseDir(MediaAccessId   accessId,
+                             const Pathname &dirname) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
 
-      m_impl->mediaAccMap[mediaId]->releaseDir(dirname);
+      ref.checkAttached(accessId);
+
+      ref.handler->releaseDir(dirname);
     }
 
 
     // ---------------------------------------------------------------
     void
-    MediaManager::releasePath(MediaId mediaId,
-                              const Pathname & pathname) const
+    MediaManager::releasePath(MediaAccessId   accessId,
+                              const Pathname &pathname) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
-      {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
-      }
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      ref.checkAttached(accessId);
+
+      ref.handler->releasePath(pathname);
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::dirInfo(MediaAccessId           accessId,
+                          std::list<std::string> &retlist,
+                          const Pathname         &dirname,
+                          bool                    dots) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      // FIXME: ref.checkDesired(accessId); ???
+      ref.checkAttached(accessId);
+
+      ref.handler->dirInfo(retlist, dirname, dots);
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::dirInfo(MediaAccessId           accessId,
+                          filesystem::DirContent &retlist,
+                          const Pathname         &dirname,
+                          bool                    dots) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      // FIXME: ref.checkDesired(accessId); ???
+      ref.checkAttached(accessId);
+
+      ref.handler->dirInfo(retlist, dirname, dots);
+    }
+
+    // ---------------------------------------------------------------
+    bool
+    MediaManager::doesFileExist(MediaAccessId  accessId, const Pathname & filename ) const
+    {
+      MutexLock glock(g_Mutex);
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      // FIXME: ref.checkDesired(accessId); ???
+      ref.checkAttached(accessId);
 
-      m_impl->mediaAccMap[mediaId]->releasePath(pathname);
+      return ref.handler->doesFileExist(filename);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::dirInfo(MediaId mediaId,
-                          std::list<std::string> & retlist,
-                          const Pathname & dirname, bool dots) const
+    MediaManager::getDetectedDevices(MediaAccessId accessId,
+                                     std::vector<std::string> & devices,
+                                     unsigned int & index) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
+      ManagedMedia &ref( m_impl->findMM(accessId));
+      return ref.handler->getDetectedDevices(devices, index);
+    }
 
-      if( !m_impl->hasMediaAcc( mediaId))
+    // ---------------------------------------------------------------
+    // STATIC
+    time_t
+    MediaManager::getMountTableMTime()
+    {
+      MutexLock glock(g_Mutex);
+      return MediaManager_Impl::getMountTableMTime();
+    }
+
+    // ---------------------------------------------------------------
+    // STATIC
+    MountEntries
+    MediaManager::getMountEntries()
+    {
+      MutexLock glock(g_Mutex);
+
+      return MediaManager_Impl::getMountEntries();
+    }
+
+    // ---------------------------------------------------------------
+    bool
+    MediaManager::isUseableAttachPoint(const Pathname &path,
+                                       bool            mtab) const
+    {
+      if( path.empty() || path == "/" || !PathInfo(path).isDir())
+        return false;
+
+      MutexLock glock(g_Mutex);
+
+      //
+      // check against our current attach points
+      //
+      ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
       {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
+        AttachedMedia ret = m->second.handler->attachedMedia();
+        if( ret.mediaSource && ret.attachPoint)
+        {
+          std::string mnt(ret.attachPoint->path.asString());
+          std::string our(path.asString());
+
+          if( our == mnt)
+          {
+            // already used as attach point
+            return false;
+          }
+          else
+          if( mnt.size() > our.size()   &&
+              mnt.at(our.size()) == '/' &&
+             !mnt.compare(0, our.size(), our))
+          {
+            // mountpoint is bellow of path
+            // (would hide the content)
+            return false;
+          }
+        }
       }
 
-      m_impl->mediaAccMap[mediaId]->dirInfo(retlist, dirname, dots);
+      if( !mtab)
+        return true;
+
+      //
+      // check against system mount entries
+      //
+      MountEntries  entries( m_impl->getMountEntries());
+      MountEntries::const_iterator e;
+      for( e = entries.begin(); e != entries.end(); ++e)
+      {
+        std::string mnt(Pathname(e->dir).asString());
+        std::string our(path.asString());
+
+        if( our == mnt)
+        {
+          // already used as mountpoint
+          return false;
+        }
+        else
+        if( mnt.size() > our.size()   &&
+            mnt.at(our.size()) == '/' &&
+           !mnt.compare(0, our.size(), our))
+        {
+          // mountpoint is bellow of path
+          // (would hide the content)
+          return false;
+        }
+      }
+
+      return true;
     }
 
     // ---------------------------------------------------------------
-    void
-    MediaManager::dirInfo(MediaId mediaId,
-                          filesystem::DirContent & retlist,
-                          const Pathname & dirname, bool dots) const
+    AttachedMedia
+    MediaManager::getAttachedMedia(MediaAccessId &accessId) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      return ref.handler->attachedMedia();
+    }
+
+    // ---------------------------------------------------------------
+    AttachedMedia
+    MediaManager::findAttachedMedia(const MediaSourceRef &media) const
     {
-      MutexLock lock(g_Mutex);
+      MutexLock glock(g_Mutex);
 
-      if( !m_impl->hasMediaAcc( mediaId))
+      if( !media || media->type.empty())
+        return AttachedMedia();
+
+      ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
       {
-        ZYPP_THROW(MediaNotOpenException(
-          "Invalid media id " + str::numstring(mediaId)
-        ));
+        if( !m->second.handler->isAttached())
+          continue;
+
+        AttachedMedia ret = m->second.handler->attachedMedia();
+        if( ret.mediaSource && ret.mediaSource->equals( *media))
+            return ret;
       }
+      return AttachedMedia();
+    }
 
-      m_impl->mediaAccMap[mediaId]->dirInfo(retlist, dirname, dots);
+    // ---------------------------------------------------------------
+    void
+    MediaManager::forceReleaseShared(const MediaSourceRef &media)
+    {
+      MutexLock glock(g_Mutex);
+
+      if( !media || media->type.empty())
+        return;
+
+      ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
+      {
+        if( !m->second.handler->isAttached())
+          continue;
+
+        AttachedMedia ret = m->second.handler->attachedMedia();
+        if( ret.mediaSource && ret.mediaSource->equals( *media))
+        {
+          m->second.handler->release();
+          m->second.desired  = false;
+        }
+      }
     }
 
     //////////////////////////////////////////////////////////////////