/** \file zypp/media/MediaISO.cc
*
*/
-#include "zypp/media/MediaISO.h"
+#include <iostream>
+
#include "zypp/base/Logger.h"
#include "zypp/media/Mount.h"
-#include <iostream>
+#include "zypp/media/MediaISO.h"
+
+
+#define LOSETUP_TOOL_PATH "/sbin/losetup"
+
+using std::string;
+using std::endl;
//////////////////////////////////////////////////////////////////////
namespace zypp
zypp::Url src;
try
{
+ // this percent-decodes the query parameter, it must be later encoded
+ // again before used in a Url object
arg = _url.getQueryParam("url");
if( arg.empty() && _isofile.dirname().absolute())
{
src = std::string("dir:///");
- src.setPathName(_isofile.dirname().asString());
+ src.setPathName(url::encode(_isofile.dirname().asString(), URL_SAFE_CHARS));
_isofile = _isofile.basename();
}
else
{
- src = arg;
+ src = url::encode(arg, URL_SAFE_CHARS);
}
}
catch(const zypp::url::UrlException &e)
{
ZYPP_CAUGHT(e);
ERR << "Unable to parse iso filename source media url" << std::endl;
- ZYPP_THROW(MediaBadUrlException(_url));
+ MediaBadUrlException ne(_url);
+ ne.remember(e);
+ ZYPP_THROW(ne);
}
if( !src.isValid())
{
<< src.asString() << std::endl;
ZYPP_THROW(MediaUnsupportedUrlSchemeException(src));
}
-#if 1
else
if( !(src.getScheme() == "hd" ||
src.getScheme() == "dir" ||
src.getScheme() == "file" ||
src.getScheme() == "nfs" ||
+ src.getScheme() == "nfs4" ||
src.getScheme() == "smb" ||
src.getScheme() == "cifs"))
{
<< src.asString() << std::endl;
ZYPP_THROW(MediaUnsupportedUrlSchemeException(src));
}
-#endif
MediaManager manager;
{
release();
- MediaManager manager;
- manager.close(_parentId);
+ if( _parentId)
+ {
+ DBG << "Closing parent handler..." << std::endl;
+ MediaManager manager;
+ if(manager.isOpen(_parentId))
+ manager.close(_parentId);
+ _parentId = 0;
+ }
}
catch( ... )
{}
bool
MediaISO::isAttached() const
{
- return checkAttached(false, false);
+ return checkAttached(false);
+ }
+
+ // ---------------------------------------------------------------
+ string MediaISO::findUnusedLoopDevice()
+ {
+ const char* argv[] =
+ {
+ LOSETUP_TOOL_PATH,
+ "-f",
+ NULL
+ };
+ ExternalProgram losetup(argv, ExternalProgram::Stderr_To_Stdout);
+
+ string out = losetup.receiveLine();
+ string device = out.substr(0, out.size() - 1); // remove the trailing endl
+ for(; out.length(); out = losetup.receiveLine())
+ DBG << "losetup: " << out;
+
+ if (losetup.close() != 0)
+ {
+ ERR << LOSETUP_TOOL_PATH " failed to find an unused loop device." << std::endl;
+ ZYPP_THROW(MediaNoLoopDeviceException(_url));
+ }
+
+ DBG << "found " << device << endl;
+ return device;
}
// ---------------------------------------------------------------
ZYPP_THROW(MediaNotSupportedException(_url));
MediaManager manager;
- manager.attach(_parentId, false);
+ manager.attach(_parentId);
try
{
ZYPP_CAUGHT(e1);
try
{
- manager.release(_parentId, false);
+ manager.release(_parentId);
}
catch(const MediaException &e2)
{
ZYPP_CAUGHT(e2);
}
- ZYPP_THROW(MediaMountException(
+
+ MediaMountException e3(
"Unable to find iso filename on source media",
_url.asString(), attachPoint().asString()
- ));
+ );
+ e3.remember(e1);
+ ZYPP_THROW(e3);
}
- Pathname isofile = manager.localPath(_parentId, _isofile);
- PathInfo isoinfo( isofile, PathInfo::LSTAT);
- if( !isoinfo.isFile())
+ // if the provided file is a symlink, expand it (#274651)
+ // (this will probably work only for file/dir and cd/dvd schemes)
+ Pathname isofile = expandlink(manager.localPath(_parentId, _isofile));
+ if( isofile.empty() || !PathInfo(isofile).isFile())
{
ZYPP_THROW(MediaNotSupportedException(_url));
}
- MediaSourceRef media( new MediaSource(
- "iso", isofile.asString()
- ));
+ //! \todo make this thread-safe - another thread might pick up the same device
+ string loopdev = findUnusedLoopDevice(); // (bnc #428009)
+
+ MediaSourceRef media( new MediaSource("iso", loopdev));
+ PathInfo dinfo(loopdev);
+ if( dinfo.isBlk())
+ {
+ media->maj_nr = dinfo.devMajor();
+ media->min_nr = dinfo.devMinor();
+ }
+ else
+ ERR << loopdev << " is not a block device" << endl;
AttachedMedia ret( findAttachedMedia( media));
if( ret.mediaSource &&
return;
}
- std::string mountpoint = attachPoint().asString();
- if( !isUseableAttachPoint(attachPoint()))
+ if( !isUseableAttachPoint( attachPoint() ) )
{
- mountpoint = createAttachPoint().asString();
- if( mountpoint.empty())
- ZYPP_THROW( MediaBadAttachPointException(url()));
- setAttachPoint( mountpoint, true);
+ setAttachPoint( createAttachPoint(), true );
}
-
- std::string mountopts("ro,loop");
+ std::string mountpoint( attachPoint().asString() );
+ std::string mountopts("ro,loop=" + loopdev);
Mount mount;
mount.mount(isofile.asString(), mountpoint,
{
ZYPP_CAUGHT(excpt_r);
}
- ZYPP_THROW(MediaMountException(isofile.asString(), mountpoint,
- "Unable to verify that the media was mounted"
+ ZYPP_THROW(MediaMountException(
+ "Unable to verify that the media was mounted",
+ isofile.asString(), mountpoint
));
}
}
// ---------------------------------------------------------------
- void MediaISO::releaseFrom(bool eject)
+
+ void MediaISO::releaseFrom(const std::string & ejectDev)
{
Mount mount;
mount.umount(attachPoint().asString());
- MediaManager manager;
- manager.release(_parentId);
+ if( _parentId)
+ {
+ // Unmounting the iso already succeeded,
+ // so don't let exceptions escape.
+ MediaManager manager;
+ try
+ {
+ manager.release(_parentId);
+ }
+ catch ( const Exception & excpt_r )
+ {
+ ZYPP_CAUGHT( excpt_r );
+ WAR << "Not been able to cleanup the parent mount." << endl;
+ }
+ }
+ // else:
+ // the media manager has reset the _parentId
+ // and will destroy the parent handler itself.
}
// ---------------------------------------------------------------
MediaHandler::getDirInfo(retlist, dirname, dots);
}
+ bool MediaISO::getDoesFileExist( const Pathname & filename ) const
+ {
+ return MediaHandler::getDoesFileExist( filename );
+ }
//////////////////////////////////////////////////////////////////
} // namespace media