#include <fstream>
#include "zypp/base/LogTools.h"
+#include "zypp/base/Regex.h"
+#include "zypp/base/UserRequestException.h"
#include "zypp/ZYppCallbacks.h"
#include "zypp/MediaSetAccess.h"
#include "zypp/PathInfo.h"
///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
+
+IMPL_PTR_TYPE(MediaSetAccess);
+
///////////////////////////////////////////////////////////////////
- ChecksumFileChecker::ChecksumFileChecker( const CheckSum &checksum )
- : _checksum(checksum)
+ MediaSetAccess::MediaSetAccess(const Url &url,
+ const Pathname & prefered_attach_point)
+ : _url(url)
+ , _prefAttachPoint(prefered_attach_point)
+ {}
+
+ MediaSetAccess::MediaSetAccess(const std::string & label_r,
+ const Url &url,
+ const Pathname & prefered_attach_point)
+ : _url(url)
+ , _prefAttachPoint(prefered_attach_point)
+ , _label( label_r )
+ {}
+
+ MediaSetAccess::~MediaSetAccess()
{
+ try
+ {
+ release();
+ }
+ catch(...) {} // don't let exception escape a dtor.
}
- bool ChecksumFileChecker::operator()( const Pathname &file )
+
+ void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
{
- // FIXME probably this funcionality should be in CheckSum itself
- CheckSum real_checksum( _checksum.type(), filesystem::checksum( file, _checksum.type() ));
- if ( real_checksum == _checksum )
+ if (_medias.find(media_nr) != _medias.end())
{
- return true;
+ // the media already exists, set theverifier
+ media::MediaAccessId id = _medias[media_nr];
+ media::MediaManager media_mgr;
+ media_mgr.addVerifier( id, verifier );
+ // remove any saved verifier for this media
+ _verifiers.erase(media_nr);
}
else
{
- ERR << "Got " << real_checksum << ", expected " << _checksum << std::endl;
- return false;
+ // save the verifier in the map, and set it when
+ // the media number is first attached
+ _verifiers[media_nr] = verifier;
}
}
- bool NullFileChecker::operator()(const Pathname &file )
+ void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
{
- return true;
+ releaseFile( on_media_file.filename(), on_media_file.medianr() );
}
- MediaSetAccess::MediaSetAccess( const Url &url, const Pathname &path )
- : _url(url),
- _path(path)
- {
- MIL << "initializing.." << std::endl;
- //std::vector<media::MediaVerifierRef> single_media;
- //single_media[0] = media::MediaVerifierRef(new media::NoVerifier());
- //_verifiers = single_media;
- }
-
- MediaSetAccess::~MediaSetAccess()
+ void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
{
+ media::MediaManager media_mgr;
+ media::MediaAccessId media;
+
+ media = getMediaAccessId( media_nr);
+ DBG << "Going to release file " << file
+ << " from media number " << media_nr << endl;
+
+ if ( ! media_mgr.isAttached(media) )
+ return; //disattached media is free
+
+ media_mgr.releaseFile (media, file);
}
- void MediaSetAccess::setVerifiers( const std::vector<media::MediaVerifierRef> &verifiers )
+ void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
+ bool dots, unsigned media_nr )
{
- _verifiers = verifiers;
+ media::MediaManager media_mgr;
+ media::MediaAccessId media;
+ media = getMediaAccessId(media_nr);
+
+ // try to attach the media
+ if ( ! media_mgr.isAttached(media) )
+ media_mgr.attach(media);
+
+ media_mgr.dirInfo(media, retlist, dirname, dots);
}
-// callback::SendReport<source::DownloadFileReport> report;
-// DownloadProgressFileReceiver download_report( report );
-// SourceFactory source_factory;
-// Url file_url( url().asString() + file_r.asString() );
-// report->start( source_factory.createFrom(this), file_url );
-// callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
-// Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
-// report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
-// return file;
+ struct ProvideFileOperation
+ {
+ Pathname result;
+ void operator()( media::MediaAccessId media, const Pathname &file )
+ {
+ media::MediaManager media_mgr;
+ media_mgr.provideFile(media, file);
+ result = media_mgr.localPath(media, file);
+ }
+ };
+ struct ProvideDirTreeOperation
+ {
+ Pathname result;
+ void operator()( media::MediaAccessId media, const Pathname &file )
+ {
+ media::MediaManager media_mgr;
+ media_mgr.provideDirTree(media, file);
+ result = media_mgr.localPath(media, file);
+ }
+ };
- void MediaSetAccess::providePossiblyCachedMetadataFile( const Pathname &file_to_download, unsigned medianr, const Pathname &destination, const Pathname &cached_file, const CheckSum &checksum )
+ struct ProvideDirOperation
{
- Url file_url( _url.asString() + file_to_download.asString() );
- // if we have a cached file and its the same
- if ( PathInfo(cached_file).isExist() && (! checksum.empty()) && is_checksum( cached_file, checksum ) )
+ Pathname result;
+ void operator()( media::MediaAccessId media, const Pathname &file )
{
- MIL << "file " << file_url << " found in previous cache. Using cached copy." << std::endl;
- // checksum is already checked.
- // we could later implement double failover and try to download if file copy fails.
- if ( filesystem::copy(cached_file, destination) != 0 )
- ZYPP_THROW(Exception("Can't copy " + cached_file.asString() + " to " + destination.asString()));
+ media::MediaManager media_mgr;
+ media_mgr.provideDir(media, file);
+ result = media_mgr.localPath(media, file);
}
- else
+ };
+
+ struct ProvideFileExistenceOperation
+ {
+ bool result;
+ ProvideFileExistenceOperation()
+ : result(false)
+ {}
+
+ void operator()( media::MediaAccessId media, const Pathname &file )
{
- // we dont have it or its not the same, download it.
- Pathname downloaded_file = provideFile( file_to_download, medianr, ChecksumFileChecker(checksum) );
-
- if ( filesystem::copy(downloaded_file, destination) != 0 )
- ZYPP_THROW(Exception("Can't copy " + downloaded_file.asString() + " to " + destination.asString()));
+ media::MediaManager media_mgr;
+ result = media_mgr.doesFileExist(media, file);
}
+ };
+
+
+
+ Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
+ {
+ ProvideFileOperation op;
+ provide( boost::ref(op), resource, options, deltafile );
+ return op.result;
}
- Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr )
+ Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
{
- return provideFileInternal( file, media_nr, false, false);
+ OnMediaLocation resource;
+ ProvideFileOperation op;
+ resource.setLocation(file, media_nr);
+ provide( boost::ref(op), resource, options, Pathname() );
+ return op.result;
}
- Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, FileChecker checker )
+ bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
{
- Pathname p = provideFileInternal( file, media_nr, false, false);
-
- if ( ! checker(p) )
- {
- ZYPP_THROW(Exception("Error checker"));
- }
- return p;
+ ProvideFileExistenceOperation op;
+ OnMediaLocation resource;
+ resource.setLocation(file, media_nr);
+ provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
+ return op.result;
}
- Pathname MediaSetAccess::provideFileInternal(const Pathname & file, unsigned media_nr, bool cached, bool checkonly )
+ void MediaSetAccess::provide( ProvideOperation op,
+ const OnMediaLocation &resource,
+ ProvideFileOptions options,
+ const Pathname &deltafile )
{
+ Pathname file(resource.filename());
+ unsigned media_nr(resource.medianr());
+
callback::SendReport<media::MediaChangeReport> report;
media::MediaManager media_mgr;
- // get the mediaId, but don't try to attach it here
- media::MediaAccessId media = getMediaAccessId( media_nr);
-
+
+ media::MediaAccessId media;
+
do
{
+ // get the mediaId, but don't try to attach it here
+ media = getMediaAccessId( media_nr);
+ bool deltafileset = false;
+
try
{
- DBG << "Going to try provide file " << file << " from " << media_nr << endl;
+ DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
+ << " from media number " << media_nr << endl;
// try to attach the media
if ( ! media_mgr.isAttached(media) )
- media_mgr.attach(media);
- media_mgr.provideFile (media, file, false, false);
+ media_mgr.attach(media);
+ media_mgr.setDeltafile(media, deltafile);
+ deltafileset = true;
+ op(media, file);
+ media_mgr.setDeltafile(media, Pathname());
break;
}
- catch ( Exception & excp )
+ catch ( media::MediaException & excp )
{
ZYPP_CAUGHT(excp);
- media::MediaChangeReport::Action user;
+ if (deltafileset)
+ media_mgr.setDeltafile(media, Pathname());
+ media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
+ unsigned int devindex = 0;
+ vector<string> devices;
+ media_mgr.getDetectedDevices(media, devices, devindex);
+
do
{
- DBG << "Media couldn't provide file " << file << " , releasing." << endl;
- try
- {
- media_mgr.release (media, false);
- }
- catch (const Exception & excpt_r)
- {
- ZYPP_CAUGHT(excpt_r);
- MIL << "Failed to release media " << media << endl;
- }
-
- MIL << "Releasing all medias of all sources" << endl;
- try
- {
- //zypp::SourceManager::sourceManager()->releaseAllSources();
- }
- catch (const zypp::Exception& excpt_r)
+ if (user != media::MediaChangeReport::EJECT) // no use in calling this again
{
- ZYPP_CAUGHT(excpt_r);
- ERR << "Failed to release all sources" << endl;
+ DBG << "Media couldn't provide file " << file << " , releasing." << endl;
+ try
+ {
+ media_mgr.release(media);
+ }
+ catch (const Exception & excpt_r)
+ {
+ ZYPP_CAUGHT(excpt_r);
+ MIL << "Failed to release media " << media << endl;
+ }
}
// set up the reason
media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
-
+
if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
typeid(excp) == typeid( media::MediaNotAFileException ) )
{
reason = media::MediaChangeReport::NOT_FOUND;
- }
+ }
else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
typeid(excp) == typeid( media::MediaNotAttachedException) )
{
reason = media::MediaChangeReport::WRONG;
}
+ else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
+ typeid(excp) == typeid( media::MediaTemporaryProblemException))
+ {
+ reason = media::MediaChangeReport::IO_SOFT;
+ }
+
+ // Propagate the original error if _no_ callback receiver is connected, or
+ // non_interactive mode (for optional files) is used (except for wrong media).
+ if ( ! callback::SendReport<media::MediaChangeReport>::connected()
+ || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
+ {
+ MIL << "Can't provide file. Non-Interactive mode." << endl;
+ ZYPP_RETHROW(excp);
+ }
+ else
+ {
+ // release all media before requesting another (#336881)
+ media_mgr.releaseAll();
- user = checkonly ? media::MediaChangeReport::ABORT :
- report->requestMedia (
- Source_Ref::noSource,
+ user = report->requestMedia (
+ _url,
media_nr,
+ _label,
reason,
- excp.asUserString()
+ excp.asUserString(),
+ devices,
+ devindex
);
+ }
- DBG << "ProvideFile exception caught, callback answer: " << user << endl;
+ MIL << "ProvideFile exception caught, callback answer: " << user << endl;
if( user == media::MediaChangeReport::ABORT )
{
DBG << "Aborting" << endl;
- ZYPP_RETHROW ( excp );
+ AbortRequestException aexcp("Aborting requested by user");
+ aexcp.remember(excp);
+ ZYPP_THROW(aexcp);
}
else if ( user == media::MediaChangeReport::IGNORE )
{
DBG << "Skipping" << endl;
- ZYPP_THROW ( source::SkipRequestedException("User-requested skipping of a file") );
- }
+ SkipRequestException nexcp("User-requested skipping of a file");
+ nexcp.remember(excp);
+ ZYPP_THROW(nexcp);
+ }
else if ( user == media::MediaChangeReport::EJECT )
{
DBG << "Eject: try to release" << endl;
- try
- {
- //zypp::SourceManager::sourceManager()->releaseAllSources();
- }
- catch (const zypp::Exception& excpt_r)
- {
- ZYPP_CAUGHT(excpt_r);
- ERR << "Failed to release all sources" << endl;
- }
- media_mgr.release (media, true); // one more release needed for eject
- // FIXME: this will not work, probably
+ try
+ {
+ media_mgr.releaseAll();
+ media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
+ }
+ catch ( const Exception & e)
+ {
+ ZYPP_CAUGHT(e);
+ }
}
else if ( user == media::MediaChangeReport::RETRY ||
user == media::MediaChangeReport::CHANGE_URL )
{
// retry
DBG << "Going to try again" << endl;
+ // invalidate current media access id
+ media_mgr.close(media);
+ _medias.erase(media_nr);
// not attaching, media set will do that for us
// this could generate uncaught exception (#158620)
// retry or change URL
} while( true );
+ }
- return media_mgr.localPath( media, file );
+ Pathname MediaSetAccess::provideDir(const Pathname & dir,
+ bool recursive,
+ unsigned media_nr,
+ ProvideFileOptions options )
+ {
+ OnMediaLocation resource;
+ resource.setLocation(dir, media_nr);
+ if ( recursive )
+ {
+ ProvideDirTreeOperation op;
+ provide( boost::ref(op), resource, options, Pathname());
+ return op.result;
+ }
+ ProvideDirOperation op;
+ provide( boost::ref(op), resource, options, Pathname());
+ return op.result;
}
media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
{
media::MediaManager media_mgr;
- if (medias.find(medianr) != medias.end())
+ if (_medias.find(medianr) != _medias.end())
{
- media::MediaAccessId id = medias[medianr];
- //if (! noattach && ! media_mgr.isAttached(id))
- //media_mgr.attach(id);
+ media::MediaAccessId id = _medias[medianr];
return id;
}
Url url;
url = rewriteUrl (_url, medianr);
- media::MediaAccessId id = media_mgr.open(url, _path);
- //try {
- // MIL << "Adding media verifier" << endl;
- // media_mgr.delVerifier(id);
- // media_mgr.addVerifier(id, _source.verifier(medianr));
- //}
- //catch (const Exception & excpt_r)
- //{
- // ZYPP_CAUGHT(excpt_r);
- // WAR << "Verifier not found" << endl;
- //}
- medias[medianr] = id;
-
- //if (! noattach)
- // media_mgr.attach(id);
+ media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
+ _medias[medianr] = id;
+
+ try
+ {
+ if (_verifiers.find(medianr) != _verifiers.end())
+ {
+ // a verifier is set for this media
+ // FIXME check the case where the verifier exists
+ // but we have no access id for the media
+ media::MediaAccessId id = _medias[medianr];
+ media::MediaManager media_mgr;
+ media_mgr.delVerifier(id);
+ media_mgr.addVerifier( id, _verifiers[medianr] );
+ // remove any saved verifier for this media
+ _verifiers.erase(medianr);
+ }
+ }
+ catch ( const Exception &e )
+ {
+ ZYPP_CAUGHT(e);
+ WAR << "Verifier not found" << endl;
+ }
return id;
}
+
Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
{
std::string scheme = url_r.getScheme();
if (scheme == "cd" || scheme == "dvd")
- return url_r;
+ return url_r;
DBG << "Rewriting url " << url_r << endl;
if( scheme == "iso")
{
+ // TODO the iso parameter will not be required in the future, this
+ // code has to be adapted together with the MediaISO change.
+ // maybe some MediaISOURL interface should be used.
std::string isofile = url_r.getQueryParam("iso");
- boost::regex e("^(.*(cd|dvd))([0-9]+)(\\.iso)$", boost::regex::icase);
- boost::smatch what;
- if(boost::regex_match(isofile, what, e, boost::match_extra))
+ str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
+
+ str::smatch what;
+ if(str::regex_match(isofile, what, e))
{
Url url( url_r);
- isofile = what[1] + str::numstring(medianr) + what[4];
+ isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
url.setQueryParam("iso", isofile);
DBG << "Url rewrite result: " << url << endl;
return url;
else
{
std::string pathname = url_r.getPathName();
- boost::regex e("^(.*(cd|dvd))([0-9]+)(/?)$", boost::regex::icase);
- boost::smatch what;
- if(boost::regex_match(pathname, what, e, boost::match_extra))
+ str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
+ str::smatch what;
+ if(str::regex_match(pathname, what, e))
{
Url url( url_r);
- pathname = what[1] + str::numstring(medianr) + what[4];
+ pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
url.setPathName(pathname);
DBG << "Url rewrite result: " << url << endl;
return url;
return url_r;
}
- std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
+ void MediaSetAccess::release()
{
- return str;
+ DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
+ media::MediaManager manager;
+ for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
+ manager.release(m->second, "");
}
-// media::MediaVerifierRef MediaSetAccess::verifier(unsigned media_nr)
-// { return media::MediaVerifierRef(new media::NoVerifier()); }
-
- MediaVerifier::MediaVerifier(const std::string & vendor_r, const std::string & id_r, const media::MediaNr media_nr)
- : _media_vendor(vendor_r)
- , _media_id(id_r)
- , _media_nr(media_nr)
- {}
-
- bool MediaVerifier::isDesiredMedia(const media::MediaAccessRef &ref)
+ std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
{
- if (_media_vendor.empty() || _media_id.empty())
- return true;
-
- Pathname media_file = "/media." + str::numstring(_media_nr) + "/media";
- ref->provideFile (media_file);
- media_file = ref->localPath(media_file);
- std::ifstream str(media_file.asString().c_str());
- std::string vendor;
- std::string id;
-
-#warning check the stream status
- getline(str, vendor);
- getline(str, id);
-
- return (vendor == _media_vendor && id == _media_id );
+ str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
+ return str;
}
-
/////////////////////////////////////////////////////////////////
-} // namespace source
+} // namespace zypp
///////////////////////////////////////////////////////////////////