1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaManager.cc
17 #include "zypp/media/MediaException.h"
18 #include "zypp/media/MediaManager.h"
19 #include "zypp/media/MediaHandler.h"
20 #include "zypp/media/Mount.h"
21 #include "zypp/thread/Mutex.h"
22 #include "zypp/thread/MutexLock.h"
24 #include "zypp/base/String.h"
25 #include "zypp/base/Logger.h"
26 #include "zypp/Pathname.h"
27 #include "zypp/PathInfo.h"
29 //////////////////////////////////////////////////////////////////////
31 { ////////////////////////////////////////////////////////////////////
33 ////////////////////////////////////////////////////////////////////
35 { //////////////////////////////////////////////////////////////////
37 using zypp::thread::Mutex;
38 using zypp::thread::MutexLock;
40 //////////////////////////////////////////////////////////////////
41 namespace // anonymous
42 { ////////////////////////////////////////////////////////////////
45 // -------------------------------------------------------------
50 // -------------------------------------------------------------
60 ManagedMedia(const ManagedMedia &m)
63 , verifier(m.verifier)
66 ManagedMedia(const MediaAccessRef &h, const MediaVerifierRef &v)
73 checkAttached(MediaAccessId id)
75 if( !handler->isAttached())
77 DBG << "checkAttached(" << id << ") not attached" << std::endl;
79 ZYPP_THROW(MediaNotAttachedException(
86 checkDesired(MediaAccessId id)
93 desired = verifier->isDesiredMedia(handler);
95 catch(const zypp::Exception &e) {
102 DBG << "checkDesired(" << id << "): not desired (report by "
103 << verifier->info() << ")" << std::endl;
104 ZYPP_THROW(MediaNotDesiredException(
109 DBG << "checkDesired(" << id << "): desired (report by "
110 << verifier->info() << ")" << std::endl;
112 DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
117 MediaAccessRef handler;
118 MediaVerifierRef verifier;
122 // -------------------------------------------------------------
123 typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
125 ////////////////////////////////////////////////////////////////
127 //////////////////////////////////////////////////////////////////
130 //////////////////////////////////////////////////////////////////
132 MediaVerifierBase::info() const
134 return std::string(typeid((*this)).name());
138 //////////////////////////////////////////////////////////////////
140 NoVerifier::info() const
142 return std::string("zypp::media::NoVerifier");
146 //////////////////////////////////////////////////////////////////
147 class MediaManager_Impl
150 friend class MediaManager;
152 MediaAccessId last_accessid;
153 ManagedMediaMap mediaMap;
162 MutexLock glock(g_Mutex);
166 // remove depending (iso) handlers first
167 ManagedMediaMap::iterator it;
172 for(it = mediaMap.begin(); it != mediaMap.end(); /**/)
174 if( it->second.handler->dependsOnParent())
177 // let it forget its parent, we will
178 // destroy it later (in clear())...
179 it->second.handler->resetParentId();
180 mediaMap.erase( it++ ); // postfix! Incrementing before erase
187 // remove all other handlers
197 return ++last_accessid;
201 hasId(MediaAccessId accessId) const
203 return mediaMap.find(accessId) != mediaMap.end();
206 inline ManagedMedia &
207 findMM(MediaAccessId accessId)
209 ManagedMediaMap::iterator it( mediaMap.find(accessId));
210 if( it == mediaMap.end())
212 ZYPP_THROW(MediaNotOpenException(
213 "Invalid media access id " + str::numstring(accessId)
222 time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
225 WAR << "Failed to retrieve modification time of '/etc/mtab'"
231 static inline MountEntries
234 return Mount::getEntries();
240 //////////////////////////////////////////////////////////////////
242 zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl;
245 //////////////////////////////////////////////////////////////////
246 MediaManager::MediaManager()
248 MutexLock glock(g_Mutex);
251 m_impl.reset( new MediaManager_Impl());
255 // ---------------------------------------------------------------
256 MediaManager::~MediaManager()
260 // ---------------------------------------------------------------
262 MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
264 MutexLock glock(g_Mutex);
266 // create new access handler for it
267 MediaAccessRef handler( new MediaAccess());
268 MediaVerifierRef verifier( new NoVerifier());
269 ManagedMedia tmp( handler, verifier);
271 tmp.handler->open(url, preferred_attach_point);
273 MediaAccessId nextId = m_impl->nextAccessId();
275 m_impl->mediaMap[nextId] = tmp;
277 DBG << "Opened new media access using id " << nextId
278 << " to " << url.asString() << std::endl;
282 // ---------------------------------------------------------------
284 MediaManager::close(MediaAccessId accessId)
286 MutexLock glock(g_Mutex);
289 // The MediaISO handler internally requests an accessId
290 // of a "parent" handler providing the iso file.
291 // The parent handler accessId is private to MediaISO,
292 // but the attached media source may be shared reference.
293 // This means, that if the accessId exactly matches the
294 // parent handler id, close was used on uninitialized
295 // accessId variable (or the accessId was guessed) and
296 // the close request to this id will be rejected here.
298 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
299 for( ; m != m_impl->mediaMap.end(); ++m)
301 if( m->second.handler->dependsOnParent(accessId, true))
303 ZYPP_THROW(MediaIsSharedException(
304 m->second.handler->url().asString()
309 DBG << "Close to access handler using id "
310 << accessId << " requested" << std::endl;
312 ManagedMedia &ref( m_impl->findMM(accessId));
313 ref.handler->close();
315 m_impl->mediaMap.erase(accessId);
318 // ---------------------------------------------------------------
320 MediaManager::isOpen(MediaAccessId accessId) const
322 MutexLock glock(g_Mutex);
324 ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
325 return it != m_impl->mediaMap.end() &&
326 it->second.handler->isOpen();
329 // ---------------------------------------------------------------
331 MediaManager::protocol(MediaAccessId accessId) const
333 MutexLock glock(g_Mutex);
335 ManagedMedia &ref( m_impl->findMM(accessId));
337 return ref.handler->protocol();
340 // ---------------------------------------------------------------
342 MediaManager::downloads(MediaAccessId accessId) const
344 MutexLock glock(g_Mutex);
346 ManagedMedia &ref( m_impl->findMM(accessId));
348 return ref.handler->downloads();
351 // ---------------------------------------------------------------
353 MediaManager::url(MediaAccessId accessId) const
355 MutexLock glock(g_Mutex);
357 ManagedMedia &ref( m_impl->findMM(accessId));
359 return ref.handler->url();
362 // ---------------------------------------------------------------
364 MediaManager::addVerifier(MediaAccessId accessId,
365 const MediaVerifierRef &verifier)
367 MutexLock glock(g_Mutex);
370 ZYPP_THROW(MediaException("Invalid verifier reference"));
372 ManagedMedia &ref( m_impl->findMM(accessId));
375 MediaVerifierRef(verifier).swap(ref.verifier);
377 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
378 << verifier->info() << std::endl;
381 // ---------------------------------------------------------------
383 MediaManager::delVerifier(MediaAccessId accessId)
385 MutexLock glock(g_Mutex);
387 ManagedMedia &ref( m_impl->findMM(accessId));
389 MediaVerifierRef verifier( new NoVerifier());
391 ref.verifier.swap(verifier);
393 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
394 << verifier->info() << std::endl;
397 // ---------------------------------------------------------------
399 MediaManager::setAttachPrefix(const Pathname &attach_prefix)
401 MutexLock glock(g_Mutex);
403 return MediaHandler::setAttachPrefix(attach_prefix);
406 // ---------------------------------------------------------------
407 void MediaManager::attach(MediaAccessId accessId)
409 MutexLock glock(g_Mutex);
411 ManagedMedia &ref( m_impl->findMM(accessId));
413 DBG << "attach(id=" << accessId << ")" << std::endl;
415 // try first mountable/mounted device
416 ref.handler->attach(false);
419 ref.checkDesired(accessId);
422 catch (const MediaException & ex)
426 if (!ref.handler->hasMoreDevices())
429 if (ref.handler->isAttached())
430 ref.handler->release();
433 MIL << "checkDesired(" << accessId << ") of first device failed,"
434 " going to try others with attach(true)" << std::endl;
436 while (ref.handler->hasMoreDevices())
440 // try to attach next device
441 ref.handler->attach(true);
442 ref.checkDesired(accessId);
445 catch (const MediaNotDesiredException & ex)
449 if (!ref.handler->hasMoreDevices())
451 MIL << "No desired media found after trying all detected devices." << std::endl;
455 AttachedMedia media(ref.handler->attachedMedia());
456 DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
458 ref.handler->release();
460 catch (const MediaException & ex)
464 if (!ref.handler->hasMoreDevices())
467 AttachedMedia media(ref.handler->attachedMedia());
468 DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
470 if (ref.handler->isAttached()) ref.handler->release();
475 // ---------------------------------------------------------------
477 MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
479 MutexLock glock(g_Mutex);
481 ManagedMedia &ref( m_impl->findMM(accessId));
483 DBG << "release(id=" << accessId;
484 if (!ejectDev.empty())
485 DBG << ", " << ejectDev;
486 DBG << ")" << std::endl;
488 if(!ejectDev.empty())
491 // release MediaISO handlers, that are using the one
492 // specified with accessId, because it provides the
493 // iso file and it will disappear now (forced release
496 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
497 for( ; m != m_impl->mediaMap.end(); ++m)
499 if( m->second.handler->dependsOnParent(accessId, false))
503 DBG << "Forcing release of handler depending on access id "
504 << accessId << std::endl;
505 m->second.desired = false;
506 m->second.handler->release();
508 catch(const MediaException &e)
516 ref.handler->release(ejectDev);
519 // ---------------------------------------------------------------
521 MediaManager::releaseAll()
523 MutexLock glock(g_Mutex);
525 MIL << "Releasing all attached media" << std::endl;
527 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
528 for( ; m != m_impl->mediaMap.end(); ++m)
530 if( m->second.handler->dependsOnParent())
535 if(m->second.handler->isAttached())
537 DBG << "Releasing media id " << m->first << std::endl;
538 m->second.desired = false;
539 m->second.handler->release();
543 DBG << "Media id " << m->first << " not attached " << std::endl;
546 catch(const MediaException & e)
549 ERR << "Failed to release media id " << m->first << std::endl;
553 MIL << "Exit" << std::endl;
556 // ---------------------------------------------------------------
558 MediaManager::disconnect(MediaAccessId accessId)
560 MutexLock glock(g_Mutex);
562 ManagedMedia &ref( m_impl->findMM(accessId));
564 ref.handler->disconnect();
567 // ---------------------------------------------------------------
569 MediaManager::isAttached(MediaAccessId accessId) const
571 MutexLock glock(g_Mutex);
573 ManagedMedia &ref( m_impl->findMM(accessId));
575 return ref.handler->isAttached();
578 // ---------------------------------------------------------------
579 bool MediaManager::isSharedMedia(MediaAccessId accessId) const
581 MutexLock glock(g_Mutex);
583 ManagedMedia &ref( m_impl->findMM(accessId));
585 return ref.handler->isSharedMedia();
588 // ---------------------------------------------------------------
590 MediaManager::isDesiredMedia(MediaAccessId accessId) const
592 MutexLock glock(g_Mutex);
594 ManagedMedia &ref( m_impl->findMM(accessId));
596 if( !ref.handler->isAttached())
603 ref.desired = ref.verifier->isDesiredMedia(ref.handler);
605 catch(const zypp::Exception &e) {
610 DBG << "isDesiredMedia(" << accessId << "): "
611 << (ref.desired ? "" : "not ")
612 << "desired (report by "
613 << ref.verifier->info() << ")" << std::endl;
617 // ---------------------------------------------------------------
619 MediaManager::isDesiredMedia(MediaAccessId accessId,
620 const MediaVerifierRef &verifier) const
622 MutexLock glock(g_Mutex);
624 MediaVerifierRef v(verifier);
626 ZYPP_THROW(MediaException("Invalid verifier reference"));
628 ManagedMedia &ref( m_impl->findMM(accessId));
630 bool desired = false;
631 if( ref.handler->isAttached())
634 desired = v->isDesiredMedia(ref.handler);
636 catch(const zypp::Exception &e) {
641 DBG << "isDesiredMedia(" << accessId << "): "
642 << (desired ? "" : "not ")
643 << "desired (report by "
644 << v->info() << ")" << std::endl;
648 // ---------------------------------------------------------------
650 MediaManager::isChangeable(MediaAccessId accessId)
652 return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
655 // ---------------------------------------------------------------
657 MediaManager::localRoot(MediaAccessId accessId) const
659 MutexLock glock(g_Mutex);
661 ManagedMedia &ref( m_impl->findMM(accessId));
664 path = ref.handler->localRoot();
668 // ---------------------------------------------------------------
670 MediaManager::localPath(MediaAccessId accessId,
671 const Pathname & pathname) const
673 MutexLock glock(g_Mutex);
675 ManagedMedia &ref( m_impl->findMM(accessId));
678 path = ref.handler->localPath(pathname);
683 MediaManager::provideFile(MediaAccessId accessId,
684 const Pathname &filename,
685 const ByteCount &expectedFileSize ) const
687 MutexLock glock(g_Mutex);
689 ManagedMedia &ref( m_impl->findMM(accessId));
691 ref.checkDesired(accessId);
693 ref.handler->provideFile(filename, expectedFileSize);
696 // ---------------------------------------------------------------
698 MediaManager::provideFile(MediaAccessId accessId,
699 const Pathname &filename ) const
701 provideFile( accessId, filename, 0);
704 // ---------------------------------------------------------------
706 MediaManager::setDeltafile(MediaAccessId accessId,
707 const Pathname &filename ) const
709 MutexLock glock(g_Mutex);
711 ManagedMedia &ref( m_impl->findMM(accessId));
713 ref.checkDesired(accessId);
715 ref.handler->setDeltafile(filename);
718 // ---------------------------------------------------------------
720 MediaManager::provideDir(MediaAccessId accessId,
721 const Pathname &dirname) const
723 MutexLock glock(g_Mutex);
725 ManagedMedia &ref( m_impl->findMM(accessId));
727 ref.checkDesired(accessId);
729 ref.handler->provideDir(dirname);
732 // ---------------------------------------------------------------
734 MediaManager::provideDirTree(MediaAccessId accessId,
735 const Pathname &dirname) const
737 MutexLock glock(g_Mutex);
739 ManagedMedia &ref( m_impl->findMM(accessId));
741 ref.checkDesired(accessId);
743 ref.handler->provideDirTree(dirname);
746 // ---------------------------------------------------------------
748 MediaManager::releaseFile(MediaAccessId accessId,
749 const Pathname &filename) const
751 MutexLock glock(g_Mutex);
753 ManagedMedia &ref( m_impl->findMM(accessId));
755 ref.checkAttached(accessId);
757 ref.handler->releaseFile(filename);
760 // ---------------------------------------------------------------
762 MediaManager::releaseDir(MediaAccessId accessId,
763 const Pathname &dirname) const
765 MutexLock glock(g_Mutex);
767 ManagedMedia &ref( m_impl->findMM(accessId));
769 ref.checkAttached(accessId);
771 ref.handler->releaseDir(dirname);
775 // ---------------------------------------------------------------
777 MediaManager::releasePath(MediaAccessId accessId,
778 const Pathname &pathname) const
780 MutexLock glock(g_Mutex);
782 ManagedMedia &ref( m_impl->findMM(accessId));
784 ref.checkAttached(accessId);
786 ref.handler->releasePath(pathname);
789 // ---------------------------------------------------------------
791 MediaManager::dirInfo(MediaAccessId accessId,
792 std::list<std::string> &retlist,
793 const Pathname &dirname,
796 MutexLock glock(g_Mutex);
798 ManagedMedia &ref( m_impl->findMM(accessId));
800 // FIXME: ref.checkDesired(accessId); ???
801 ref.checkAttached(accessId);
803 ref.handler->dirInfo(retlist, dirname, dots);
806 // ---------------------------------------------------------------
808 MediaManager::dirInfo(MediaAccessId accessId,
809 filesystem::DirContent &retlist,
810 const Pathname &dirname,
813 MutexLock glock(g_Mutex);
815 ManagedMedia &ref( m_impl->findMM(accessId));
817 // FIXME: ref.checkDesired(accessId); ???
818 ref.checkAttached(accessId);
820 ref.handler->dirInfo(retlist, dirname, dots);
823 // ---------------------------------------------------------------
825 MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
827 MutexLock glock(g_Mutex);
828 ManagedMedia &ref( m_impl->findMM(accessId));
830 // FIXME: ref.checkDesired(accessId); ???
831 ref.checkAttached(accessId);
833 return ref.handler->doesFileExist(filename);
836 // ---------------------------------------------------------------
838 MediaManager::getDetectedDevices(MediaAccessId accessId,
839 std::vector<std::string> & devices,
840 unsigned int & index) const
842 MutexLock glock(g_Mutex);
843 ManagedMedia &ref( m_impl->findMM(accessId));
844 return ref.handler->getDetectedDevices(devices, index);
847 // ---------------------------------------------------------------
850 MediaManager::getMountTableMTime()
852 MutexLock glock(g_Mutex);
853 return MediaManager_Impl::getMountTableMTime();
856 // ---------------------------------------------------------------
859 MediaManager::getMountEntries()
861 MutexLock glock(g_Mutex);
863 return MediaManager_Impl::getMountEntries();
866 // ---------------------------------------------------------------
868 MediaManager::isUseableAttachPoint(const Pathname &path,
871 if( path.empty() || path == "/" || !PathInfo(path).isDir())
874 MutexLock glock(g_Mutex);
877 // check against our current attach points
879 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
880 for( ; m != m_impl->mediaMap.end(); ++m)
882 AttachedMedia ret = m->second.handler->attachedMedia();
883 if( ret.mediaSource && ret.attachPoint)
885 std::string mnt(ret.attachPoint->path.asString());
886 std::string our(path.asString());
890 // already used as attach point
894 if( mnt.size() > our.size() &&
895 mnt.at(our.size()) == '/' &&
896 !mnt.compare(0, our.size(), our))
898 // mountpoint is bellow of path
899 // (would hide the content)
909 // check against system mount entries
911 MountEntries entries( m_impl->getMountEntries());
912 MountEntries::const_iterator e;
913 for( e = entries.begin(); e != entries.end(); ++e)
915 std::string mnt(Pathname(e->dir).asString());
916 std::string our(path.asString());
920 // already used as mountpoint
924 if( mnt.size() > our.size() &&
925 mnt.at(our.size()) == '/' &&
926 !mnt.compare(0, our.size(), our))
928 // mountpoint is bellow of path
929 // (would hide the content)
937 // ---------------------------------------------------------------
939 MediaManager::getAttachedMedia(MediaAccessId &accessId) const
941 MutexLock glock(g_Mutex);
943 ManagedMedia &ref( m_impl->findMM(accessId));
945 return ref.handler->attachedMedia();
948 // ---------------------------------------------------------------
950 MediaManager::findAttachedMedia(const MediaSourceRef &media) const
952 MutexLock glock(g_Mutex);
954 if( !media || media->type.empty())
955 return AttachedMedia();
957 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
958 for( ; m != m_impl->mediaMap.end(); ++m)
960 if( !m->second.handler->isAttached())
963 AttachedMedia ret = m->second.handler->attachedMedia();
964 if( ret.mediaSource && ret.mediaSource->equals( *media))
967 return AttachedMedia();
970 // ---------------------------------------------------------------
972 MediaManager::forceReleaseShared(const MediaSourceRef &media)
974 MutexLock glock(g_Mutex);
976 if( !media || media->type.empty())
979 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
980 for( ; m != m_impl->mediaMap.end(); ++m)
982 if( !m->second.handler->isAttached())
985 AttachedMedia ret = m->second.handler->attachedMedia();
986 if( ret.mediaSource && ret.mediaSource->equals( *media))
988 m->second.handler->release();
989 m->second.desired = false;
994 //////////////////////////////////////////////////////////////////
996 ////////////////////////////////////////////////////////////////////
998 ////////////////////////////////////////////////////////////////////
1000 //////////////////////////////////////////////////////////////////////
1002 ** vim: set ts=2 sts=2 sw=2 ai et: