Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / media / MediaHandler.cc
index 7c9fc2a..18c05fe 100644 (file)
 #include <fstream>
 #include <sstream>
 
-#include "zypp/base/Logger.h"
+#include "zypp/TmpPath.h"
+#include "zypp/Date.h"
+#include "zypp/base/LogTools.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;
 
@@ -28,7 +34,7 @@ using namespace std;
 namespace zypp {
   namespace media {
 
-
+  Pathname MediaHandler::_attachPrefix("");
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -48,24 +54,41 @@ MediaHandler::MediaHandler ( const Url &      url_r,
                             const Pathname & attach_point_r,
                             const Pathname & urlpath_below_attachpoint_r,
                             const bool       does_download_r )
-    : _attachPoint( new AttachPoint())
+    : _mediaSource()
+    , _attachPoint( new AttachPoint())
+    , _AttachPointHint()
     , _relativeRoot( urlpath_below_attachpoint_r)
     , _does_download( does_download_r )
     , _attach_mtime(0)
     , _url( url_r )
+    , _parentId(0)
 {
-  if ( !attach_point_r.empty() ) {
+  Pathname real_attach_point( getRealPath(attach_point_r.asString()));
+
+  if ( !real_attach_point.empty() ) {
     ///////////////////////////////////////////////////////////////////
     // check if provided attachpoint is usable.
     ///////////////////////////////////////////////////////////////////
 
-    PathInfo adir( attach_point_r );
-    // FIXME: verify if attach_point_r isn't a mountpoint of other device
-    if ( !adir.isDir() ) {
-      ERR << "Provided attach point is not a directory: " << adir << endl;
+    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 {
-      setAttachPoint( attach_point_r, false);
+      attachPointHint( real_attach_point, false);
+      setAttachPoint( real_attach_point, false);
     }
   }
 }
@@ -87,6 +110,56 @@ MediaHandler::~MediaHandler()
   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()));
+}
+
+
 ///////////////////////////////////////////////////////////////////
 //
 //
@@ -103,7 +176,7 @@ MediaHandler::removeAttachPoint()
     return; // no cleanup if media still mounted!
   }
 
-  INT << "MediaHandler - checking if to remove attach point" << endl;
+  DBG << "MediaHandler - checking if to remove attach point" << endl;
   if ( _attachPoint.unique() &&
        _attachPoint->temp    &&
        !_attachPoint->path.empty() &&
@@ -123,8 +196,8 @@ MediaHandler::removeAttachPoint()
   }
   else
   {
-    if( !_attachPoint->temp)
-      INT << "MediaHandler - attachpoint is not temporary" << endl;
+    if( !_attachPoint->path.empty() && !_attachPoint->temp)
+      DBG << "MediaHandler - attachpoint is not temporary" << endl;
   }
 }
 
@@ -155,14 +228,17 @@ MediaHandler::attachPoint() const
 void
 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
 {
-  _localRoot = Pathname();
-
   _attachPoint.reset( new AttachPoint(path, temporary));
-
-  if( !_attachPoint->path.empty())
-    _localRoot = _attachPoint->path + _relativeRoot;
 }
 
+Pathname
+MediaHandler::localRoot() const
+{
+  if( _attachPoint->path.empty())
+    return Pathname();
+  else
+    return _attachPoint->path + _relativeRoot;
+}
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -175,17 +251,40 @@ MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
 void
 MediaHandler::setAttachPoint(const AttachPointRef &ref)
 {
-  _localRoot = Pathname();
-
   if( ref)
     AttachPointRef(ref).swap(_attachPoint);
   else
     _attachPoint.reset( new AttachPoint());
+}
 
-  if( !_attachPoint->path.empty())
-    _localRoot = _attachPoint->path + _relativeRoot;
+///////////////////////////////////////////////////////////////////
+//
+//
+//     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;
+}
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -201,6 +300,34 @@ 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;
+}
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -217,42 +344,22 @@ MediaHandler::createAttachPoint() const
   // provide a default (temporary) attachpoint
   /////////////////////////////////////////////////////////////////
   const char * defmounts[] = {
-      "/var/adm/mount", "/var/tmp", /**/NULL/**/
+      "/var/adm/mount", filesystem::TmpPath::defaultLocation().c_str(), /**/NULL/**/
   };
 
   Pathname apoint;
-  Pathname aroot;
-  PathInfo adir;
-  for ( const char ** def = defmounts; *def && apoint.empty(); ++def ) {
-    adir( *def );
-    if ( !adir.isDir() || !adir.userMayRWX() )
-      continue;
+  Pathname aroot( MediaHandler::_attachPrefix);
 
-    aroot = adir.path();
+  if( !aroot.empty())
+  {
+    apoint = createAttachPoint(aroot);
+  }
+  for ( const char ** def = defmounts; *def && apoint.empty(); ++def ) {
+    aroot = *def;
     if( aroot.empty())
       continue;
 
-    DBG << "Trying to create attachPoint in " << aroot << std::endl;
-
-    //
-    // FIXME: use mkdtemp
-    //
-    Pathname abase( aroot + "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 = adir.path();
-            break;
-       }
-       else
-       if (err != EEXIST)      // readonly fs or other, dont try further
-          break;
-      }
-    }
+    apoint = createAttachPoint(aroot);
   }
 
   if ( aroot.empty() ) {
@@ -260,56 +367,85 @@ MediaHandler::createAttachPoint() const
     return aroot;
   }
 
-  if ( apoint.empty() ) {
-    ERR << "Unable to create an attach point below " << aroot << std::endl;
-  } else {
+  if ( !apoint.empty() ) {
     MIL << "Created default attach point " << apoint << std::endl;
   }
   return apoint;
 }
 
-
-///////////////////////////////////////////////////////////////////
-//
-//
-//     METHOD NAME : MediaHandler::isUseableAttachPoint
-//     METHOD TYPE : bool
-//
-//     DESCRIPTION :
-//
-bool
-MediaHandler::isUseableAttachPoint(const Pathname &path) const
+Pathname
+MediaHandler::createAttachPoint(const Pathname &attach_root) const
 {
-  if( path.empty() || path == "/" || !PathInfo(path).isDir())
-    return false;
+  Pathname apoint;
 
-  MediaManager  manager;
-  MountEntries  entries( manager.getMountEntries());
-  MountEntries::const_iterator e;
+  if( attach_root.empty() || !attach_root.absolute()) {
+    ERR << "Create attach point: invalid attach root: '"
+        << attach_root << "'" << std::endl;
+    return apoint;
+  }
 
-  for( e = entries.begin(); e != entries.end(); ++e)
+  PathInfo adir( attach_root );
+  if( !adir.isDir() || (geteuid() != 0 && !adir.userMayRWX())) {
+    DBG << "Create attach point: attach root is not a writable directory: '"
+        << attach_root << "'" << std::endl;
+    return apoint;
+  }
+
+  static bool cleanup_once( true );
+  if ( cleanup_once )
   {
-    std::string mnt(Pathname(e->dir).asString());
+    cleanup_once = false;
+    DBG << "Look for orphaned attach points in " << adir << std::endl;
+    std::list<std::string> entries;
+    filesystem::readdir( entries, attach_root, false );
+    for ( const std::string & entry : entries )
+    {
+      if ( ! str::hasPrefix( entry, "AP_0x" ) )
+       continue;
+      PathInfo sdir( attach_root + entry );
+      if ( sdir.isDir()
+       && sdir.dev() == adir.dev()
+       && ( Date::now()-sdir.mtime() > Date::month ) )
+      {
+       DBG << "Remove orphaned attach point " << sdir << std::endl;
+       filesystem::recursive_rmdir( sdir.path() );
+      }
+    }
+  }
 
-    if( path == mnt)
+  filesystem::TmpDir tmpdir( attach_root, "AP_0x" );
+  if ( tmpdir )
+  {
+    apoint = getRealPath( tmpdir.path().asString() );
+    if ( ! apoint.empty() )
     {
-      // already used as mountpoint
-      return false;
+      tmpdir.autoCleanup( false );     // Take responsibility for cleanup.
     }
     else
     {
-      std::string our(path.asString());
-
-      // mountpoint is bellow of path
-      // (would hide the content)
-      if( mnt.size() > our.size()   &&
-          mnt.at(our.size()) == '/' &&
-         !mnt.compare(0, our.size(), our))
-        return false;
+      ERR << "Unable to resolve real path for attach point " << tmpdir << std::endl;
     }
   }
+  else
+  {
+    ERR << "Unable to create attach point below " << attach_root << std::endl;
+  }
+  return apoint;
+}
 
-  return true;
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::isUseableAttachPoint
+//     METHOD TYPE : bool
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::isUseableAttachPoint(const Pathname &path, bool mtab) const
+{
+  MediaManager  manager;
+  return manager.isUseableAttachPoint(path, mtab);
 }
 
 
@@ -346,6 +482,19 @@ MediaHandler::attachedMedia() const
     return AttachedMedia();
 }
 
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : MediaHandler::isSharedMedia
+//     METHOD TYPE : bool
+//
+//     DESCRIPTION :
+//
+bool
+MediaHandler::isSharedMedia() const
+{
+  return !_mediaSource.unique();
+}
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -356,68 +505,137 @@ MediaHandler::attachedMedia() const
 //     DESCRIPTION :
 //
 bool
-MediaHandler::checkAttached(bool aDevice) const
+MediaHandler::checkAttached(bool matchMountFs) const
 {
   bool _isAttached = false;
 
-  AttachedMedia ref( attachedMedia());
-  if( ref.mediaSource)
+  AttachedMedia ref( attachedMedia() );
+  if( ref.mediaSource )
   {
-    MediaManager  manager;
-
-    time_t old = _attach_mtime;
-    _attach_mtime = manager.getMountTableMTime();
-    if( !(old <= 0 || _attach_mtime != old))
+    time_t old_mtime = _attach_mtime;
+    _attach_mtime = MediaManager::getMountTableMTime();
+    if( !(old_mtime <= 0 || _attach_mtime != old_mtime) )
     {
-      // OK, skip the check
+      // OK, skip the check (we've seen it at least once)
       _isAttached = true;
     }
     else
     {
-      DBG << "Mount table changed - rereading it" << std::endl;
-      MountEntries  entries( manager.getMountEntries());
-      MountEntries::const_iterator e;
-      for( e = entries.begin(); e != entries.end(); ++e)
+      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());
+      for_( e, entries.begin(), entries.end() )
       {
-       bool isDevice = (Pathname(e->src).dirname() == "/dev");
-        if( aDevice == isDevice)
+       if ( ref.attachPoint->path != Pathname(e->dir) )
+         continue;     // at least the mount points must match
+
+        bool        is_device = false;
+        PathInfo    dev_info;
+        if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
+            dev_info(e->src) && dev_info.isBlk() )
         {
-          PathInfo    dinfo(e->src);
-          MediaSource media(ref.mediaSource->type, e->src,
-                           dinfo.major(), dinfo.minor());
-
-         if( ref.mediaSource->equals( media) &&
-             ref.attachPoint->path == Pathname(e->dir))
-         {
-           DBG << "Found media "
-               << ref.mediaSource->asString()
-               << " in the mount table" << std::endl;
-           _isAttached = true;
-           break;
-         }
-         // differs
+          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.devMajor(), dev_info.devMinor());
+
+          if( ref.mediaSource->equals( media ) )
+          {
+            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()))
+        {
+         if( ref.mediaSource->bdir.empty())
+         {
+           // bnc#710269: Type nfs may appear as nfs4 in in the mount table
+           // and maybe vice versa. Similar cifs/smb. Need to unify these types:
+           if ( matchMountFs && e->type != ref.mediaSource->type )
+           {
+             if ( str::hasPrefix( e->type, "nfs" ) && str::hasPrefix( ref.mediaSource->type, "nfs" ) )
+               matchMountFs = false;
+             else if ( ( e->type == "cifs" || e->type == "smb" ) && ( ref.mediaSource->type == "cifs" || ref.mediaSource->type == "smb" ) )
+               matchMountFs = false;
+             else
+               continue;       // different types cannot match
+           }
+           // Here: Types are ok or not to check.
+           // Check the name except for nfs (bnc#804544; symlink resolution in mount path)
+           //
+           //   [fibonacci]$ ls -l /Local/ma/c12.1
+           //   lrwxrwxrwx  /Local/ma/c12.1 -> zypp-SuSE-Code-12_1-Branch/
+           //
+           //   [localhost]$ mount -t nfs4 fibonacci:/Local/ma/c12.1 /mnt
+           //   [localhost]$ mount
+           //   fibonacci:/Local/ma/zypp-SuSE-Code-12_1-Branch on /mnt
+
+           // std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
+           // MediaSource media(mtype, e->src);
+
+           if( ref.mediaSource->name == e->src || str::hasPrefix( ref.mediaSource->type, "nfs" ) )
+           {
+             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 )
+           {
+             DBG << "Found bound media "
+                 << ref.mediaSource->asString()
+                 << " in the mount table as " << e->src << std::endl;
+             _isAttached = true;
+             break;
+           }
+         }
+          // differs
         }
-       else
-       {
-          MediaSource media(ref.mediaSource->type, e->src);
-
-         if( ref.mediaSource->equals( media) &&
-             ref.attachPoint->path == Pathname(e->dir))
-         {
-           DBG << "Found media "
-               << ref.mediaSource->asString()
-               << " in the mount table" << std::endl;
-           _isAttached = true;
-           break;
-         }
-         // differs
-       }
       }
 
       if( !_isAttached)
       {
-        ERR << "Attached media not in mount entry table any more"
-            << std::endl;
+        MIL << "Looking for " << ref << endl;
+       if( entries.empty() )
+       {
+         ERR << "Unable to find any entry in the /etc/mtab file" << std::endl;
+       }
+       else
+       {
+          dumpRange( DBG << "MountEntries: ", entries.begin(), entries.end() ) << 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;
       }
     }
   }
@@ -441,20 +659,31 @@ void MediaHandler::attach( bool next )
   // that checks the media against /etc/mtab ...
   setMediaSource(MediaSourceRef());
 
-  attachTo( next ); // pass to concrete handler
+  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 MediaHandler::localPath( const Pathname & pathname ) const
+{
+    Pathname _localRoot( localRoot());
     if ( _localRoot.empty() )
         return _localRoot;
 
@@ -492,12 +721,13 @@ void MediaHandler::disconnect()
 //
 //     DESCRIPTION :
 //
-void MediaHandler::release( bool eject )
+void MediaHandler::release( const std::string & ejectDev )
 {
   if ( !isAttached() ) {
-    DBG << "Request to release media - not attached" << std::endl;
-    if ( eject )
-      forceEject();
+    DBG << "Request to release media - not attached; eject '" << ejectDev << "'"
+        << std::endl;
+    if ( !ejectDev.empty() )
+      forceEject(ejectDev);
     return;
   }
 
@@ -509,11 +739,24 @@ void MediaHandler::release( bool eject )
   if( _mediaSource.unique())
   {
     DBG << "Releasing media " << _mediaSource->asString() << std::endl;
-    releaseFrom( eject ); // pass to concrete handler
+    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( eject) {
+  else if( !ejectDev.empty() ) {
     //
     // Can't eject a shared media
     //
@@ -523,22 +766,206 @@ void MediaHandler::release( bool eject )
     _mediaSource.reset(NULL);
 
     MediaManager manager;
-    manager.forceMediaRelease(media);
+    manager.forceReleaseShared(media);
 
     setMediaSource(media);
     DBG << "Releasing media (forced) " << _mediaSource->asString() << std::endl;
-    releaseFrom( eject ); // pass to concrete handler
+    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);
+    setAttachPoint("", true);
   }
   MIL << "Released: " << *this << endl;
 }
 
+void MediaHandler::forceRelaseAllMedia(bool matchMountFs)
+{
+  forceRelaseAllMedia( attachedMedia().mediaSource, matchMountFs);
+}
+
+void MediaHandler::forceRelaseAllMedia(const MediaSourceRef &ref,
+                                       bool                  matchMountFs)
+{
+  if( !ref)
+    return;
+
+  MountEntries  entries( MediaManager::getMountEntries());
+  MountEntries::const_iterator e;
+  for( e = entries.begin(); e != entries.end(); ++e)
+  {
+    bool        is_device = false;
+    PathInfo    dev_info;
+
+    if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
+        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.devMajor(), dev_info.devMinor());
+
+      if( ref->equals( media) && e->type != "subfs")
+      {
+        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))
+      {
+       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;
+}
+
 ///////////////////////////////////////////////////////////////////
 //
 //
@@ -628,7 +1055,7 @@ void MediaHandler::releasePath( Pathname pathname ) const
   if ( info.isFile() ) {
     unlink( info.path() );
   } else if ( info.isDir() ) {
-    if ( info.path() != _localRoot ) {
+    if ( info.path() != localRoot() ) {
       recursive_rmdir( info.path() );
     } else {
       clean_dir( info.path() );
@@ -644,8 +1071,8 @@ void MediaHandler::releasePath( Pathname pathname ) const
 //
 //     DESCRIPTION :
 //
-void MediaHandler::dirInfo( list<string> & retlist,
-                              const Pathname & dirname, bool dots ) const
+void MediaHandler::dirInfo( std::list<std::string> & retlist,
+                            const Pathname & dirname, bool dots ) const
 {
   retlist.clear();
 
@@ -683,6 +1110,25 @@ void MediaHandler::dirInfo( filesystem::DirContent & retlist,
 ///////////////////////////////////////////////////////////////////
 //
 //
+//      METHOD NAME : MediaHandler::doesFileExist
+//      METHOD TYPE : PMError
+//
+//      DESCRIPTION :
+//
+bool MediaHandler::doesFileExist( const Pathname & filename ) const
+{
+  // TODO do some logging
+  if ( !isAttached() ) {
+    INT << "Error Not attached on doesFileExist(" << filename << ")" << endl;
+    ZYPP_THROW(MediaNotAttachedException(url()));
+  }
+  return getDoesFileExist( filename );
+  MIL << "doesFileExist(" << filename << ")" << endl;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
 //     METHOD NAME : MediaHandler::getDirectoryYast
 //     METHOD TYPE : PMError
 //
@@ -842,10 +1288,16 @@ void MediaHandler::getDirInfo( std::list<std::string> & retlist,
   {
 #endif
 
-  // readdir
+    // readdir
     int res = readdir( retlist, info.path(), dots );
-  if ( res )
-    ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
+    if ( res )
+    {
+      MediaSystemException nexcpt(url(), "readdir failed");
+#if NONREMOTE_DIRECTORY_YAST
+      nexcpt.remember(excpt_r);
+#endif
+      ZYPP_THROW(nexcpt);
+    }
 
 #if NONREMOTE_DIRECTORY_YAST
   }
@@ -880,14 +1332,64 @@ void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
   {
 #endif
 
-  // readdir
-  int res = readdir( retlist, info.path(), dots );
-  if ( res )
-    ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
+    // 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;
+}
+
+void MediaHandler::setDeltafile( const Pathname & filename ) const
+{
+  _deltafile = filename;
+}
+
+Pathname MediaHandler::deltafile() const {
+  return _deltafile;
+}
+
   } // namespace media
 } // namespace zypp
+// vim: set ts=8 sts=2 sw=2 ai noet: