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(
85 inline void checkDesired( MediaAccessId id )
92 desired = verifier->isDesiredMedia(handler);
93 } catch ( const zypp::Exception &e ) {
96 media::MediaNotDesiredException newEx ( handler->url() );
103 DBG << "checkDesired(" << id << "): not desired (report by " << verifier->info() << ")" << std::endl;
104 ZYPP_THROW( MediaNotDesiredException( handler->url() ) );
107 DBG << "checkDesired(" << id << "): desired (report by " << verifier->info() << ")" << std::endl;
109 DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
114 MediaAccessRef handler;
115 MediaVerifierRef verifier;
119 // -------------------------------------------------------------
120 typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
122 ////////////////////////////////////////////////////////////////
124 //////////////////////////////////////////////////////////////////
127 //////////////////////////////////////////////////////////////////
129 MediaVerifierBase::info() const
131 return std::string(typeid((*this)).name());
135 //////////////////////////////////////////////////////////////////
137 NoVerifier::info() const
139 return std::string("zypp::media::NoVerifier");
143 //////////////////////////////////////////////////////////////////
144 class MediaManager_Impl
147 friend class MediaManager;
149 MediaAccessId last_accessid;
150 ManagedMediaMap mediaMap;
159 MutexLock glock(g_Mutex);
163 // remove depending (iso) handlers first
164 ManagedMediaMap::iterator it;
169 for(it = mediaMap.begin(); it != mediaMap.end(); /**/)
171 if( it->second.handler->dependsOnParent())
174 // let it forget its parent, we will
175 // destroy it later (in clear())...
176 it->second.handler->resetParentId();
177 mediaMap.erase( it++ ); // postfix! Incrementing before erase
184 // remove all other handlers
194 return ++last_accessid;
198 hasId(MediaAccessId accessId) const
200 return mediaMap.find(accessId) != mediaMap.end();
203 inline ManagedMedia &
204 findMM(MediaAccessId accessId)
206 ManagedMediaMap::iterator it( mediaMap.find(accessId));
207 if( it == mediaMap.end())
209 ZYPP_THROW(MediaNotOpenException(
210 "Invalid media access id " + str::numstring(accessId)
219 time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
222 WAR << "Failed to retrieve modification time of '/etc/mtab'"
228 static inline MountEntries
231 return Mount::getEntries();
237 //////////////////////////////////////////////////////////////////
239 zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl;
242 //////////////////////////////////////////////////////////////////
243 MediaManager::MediaManager()
245 MutexLock glock(g_Mutex);
248 m_impl.reset( new MediaManager_Impl());
252 // ---------------------------------------------------------------
253 MediaManager::~MediaManager()
257 // ---------------------------------------------------------------
259 MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
261 MutexLock glock(g_Mutex);
263 // create new access handler for it
264 MediaAccessRef handler( new MediaAccess());
265 MediaVerifierRef verifier( new NoVerifier());
266 ManagedMedia tmp( handler, verifier);
268 tmp.handler->open(url, preferred_attach_point);
270 MediaAccessId nextId = m_impl->nextAccessId();
272 m_impl->mediaMap[nextId] = tmp;
274 DBG << "Opened new media access using id " << nextId
275 << " to " << url.asString() << std::endl;
279 // ---------------------------------------------------------------
281 MediaManager::close(MediaAccessId accessId)
283 MutexLock glock(g_Mutex);
286 // The MediaISO handler internally requests an accessId
287 // of a "parent" handler providing the iso file.
288 // The parent handler accessId is private to MediaISO,
289 // but the attached media source may be shared reference.
290 // This means, that if the accessId exactly matches the
291 // parent handler id, close was used on uninitialized
292 // accessId variable (or the accessId was guessed) and
293 // the close request to this id will be rejected here.
295 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
296 for( ; m != m_impl->mediaMap.end(); ++m)
298 if( m->second.handler->dependsOnParent(accessId, true))
300 ZYPP_THROW(MediaIsSharedException(
301 m->second.handler->url().asString()
306 DBG << "Close to access handler using id "
307 << accessId << " requested" << std::endl;
309 ManagedMedia &ref( m_impl->findMM(accessId));
310 ref.handler->close();
312 m_impl->mediaMap.erase(accessId);
315 // ---------------------------------------------------------------
317 MediaManager::isOpen(MediaAccessId accessId) const
319 MutexLock glock(g_Mutex);
321 ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
322 return it != m_impl->mediaMap.end() &&
323 it->second.handler->isOpen();
326 // ---------------------------------------------------------------
328 MediaManager::protocol(MediaAccessId accessId) const
330 MutexLock glock(g_Mutex);
332 ManagedMedia &ref( m_impl->findMM(accessId));
334 return ref.handler->protocol();
337 // ---------------------------------------------------------------
339 MediaManager::downloads(MediaAccessId accessId) const
341 MutexLock glock(g_Mutex);
343 ManagedMedia &ref( m_impl->findMM(accessId));
345 return ref.handler->downloads();
348 // ---------------------------------------------------------------
350 MediaManager::url(MediaAccessId accessId) const
352 MutexLock glock(g_Mutex);
354 ManagedMedia &ref( m_impl->findMM(accessId));
356 return ref.handler->url();
359 // ---------------------------------------------------------------
361 MediaManager::addVerifier(MediaAccessId accessId,
362 const MediaVerifierRef &verifier)
364 MutexLock glock(g_Mutex);
367 ZYPP_THROW(MediaException("Invalid verifier reference"));
369 ManagedMedia &ref( m_impl->findMM(accessId));
372 MediaVerifierRef(verifier).swap(ref.verifier);
374 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
375 << verifier->info() << std::endl;
378 // ---------------------------------------------------------------
380 MediaManager::delVerifier(MediaAccessId accessId)
382 MutexLock glock(g_Mutex);
384 ManagedMedia &ref( m_impl->findMM(accessId));
386 MediaVerifierRef verifier( new NoVerifier());
388 ref.verifier.swap(verifier);
390 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
391 << verifier->info() << std::endl;
394 // ---------------------------------------------------------------
396 MediaManager::setAttachPrefix(const Pathname &attach_prefix)
398 MutexLock glock(g_Mutex);
400 return MediaHandler::setAttachPrefix(attach_prefix);
403 // ---------------------------------------------------------------
404 void MediaManager::attach(MediaAccessId accessId)
406 MutexLock glock(g_Mutex);
408 ManagedMedia &ref( m_impl->findMM(accessId));
410 DBG << "attach(id=" << accessId << ")" << std::endl;
412 // try first mountable/mounted device
413 ref.handler->attach(false);
416 ref.checkDesired(accessId);
419 catch (const MediaException & ex)
423 if (!ref.handler->hasMoreDevices())
426 if (ref.handler->isAttached())
427 ref.handler->release();
430 MIL << "checkDesired(" << accessId << ") of first device failed,"
431 " going to try others with attach(true)" << std::endl;
433 while (ref.handler->hasMoreDevices())
437 // try to attach next device
438 ref.handler->attach(true);
439 ref.checkDesired(accessId);
442 catch (const MediaNotDesiredException & ex)
446 if (!ref.handler->hasMoreDevices())
448 MIL << "No desired media found after trying all detected devices." << std::endl;
452 AttachedMedia media(ref.handler->attachedMedia());
453 DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
455 ref.handler->release();
457 catch (const MediaException & ex)
461 if (!ref.handler->hasMoreDevices())
464 AttachedMedia media(ref.handler->attachedMedia());
465 DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
467 if (ref.handler->isAttached()) ref.handler->release();
472 // ---------------------------------------------------------------
474 MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
476 MutexLock glock(g_Mutex);
478 ManagedMedia &ref( m_impl->findMM(accessId));
480 DBG << "release(id=" << accessId;
481 if (!ejectDev.empty())
482 DBG << ", " << ejectDev;
483 DBG << ")" << std::endl;
485 if(!ejectDev.empty())
488 // release MediaISO handlers, that are using the one
489 // specified with accessId, because it provides the
490 // iso file and it will disappear now (forced release
493 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
494 for( ; m != m_impl->mediaMap.end(); ++m)
496 if( m->second.handler->dependsOnParent(accessId, false))
500 DBG << "Forcing release of handler depending on access id "
501 << accessId << std::endl;
502 m->second.desired = false;
503 m->second.handler->release();
505 catch(const MediaException &e)
513 ref.handler->release(ejectDev);
516 // ---------------------------------------------------------------
518 MediaManager::releaseAll()
520 MutexLock glock(g_Mutex);
522 MIL << "Releasing all attached media" << std::endl;
524 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
525 for( ; m != m_impl->mediaMap.end(); ++m)
527 if( m->second.handler->dependsOnParent())
532 if(m->second.handler->isAttached())
534 DBG << "Releasing media id " << m->first << std::endl;
535 m->second.desired = false;
536 m->second.handler->release();
540 DBG << "Media id " << m->first << " not attached " << std::endl;
543 catch(const MediaException & e)
546 ERR << "Failed to release media id " << m->first << std::endl;
550 MIL << "Exit" << std::endl;
553 // ---------------------------------------------------------------
555 MediaManager::disconnect(MediaAccessId accessId)
557 MutexLock glock(g_Mutex);
559 ManagedMedia &ref( m_impl->findMM(accessId));
561 ref.handler->disconnect();
564 // ---------------------------------------------------------------
566 MediaManager::isAttached(MediaAccessId accessId) const
568 MutexLock glock(g_Mutex);
570 ManagedMedia &ref( m_impl->findMM(accessId));
572 return ref.handler->isAttached();
575 // ---------------------------------------------------------------
576 bool MediaManager::isSharedMedia(MediaAccessId accessId) const
578 MutexLock glock(g_Mutex);
580 ManagedMedia &ref( m_impl->findMM(accessId));
582 return ref.handler->isSharedMedia();
585 // ---------------------------------------------------------------
587 MediaManager::isDesiredMedia(MediaAccessId accessId) const
589 MutexLock glock(g_Mutex);
591 ManagedMedia &ref( m_impl->findMM(accessId));
593 if( !ref.handler->isAttached())
600 ref.desired = ref.verifier->isDesiredMedia(ref.handler);
602 catch(const zypp::Exception &e) {
607 DBG << "isDesiredMedia(" << accessId << "): "
608 << (ref.desired ? "" : "not ")
609 << "desired (report by "
610 << ref.verifier->info() << ")" << std::endl;
614 // ---------------------------------------------------------------
616 MediaManager::isDesiredMedia(MediaAccessId accessId,
617 const MediaVerifierRef &verifier) const
619 MutexLock glock(g_Mutex);
621 MediaVerifierRef v(verifier);
623 ZYPP_THROW(MediaException("Invalid verifier reference"));
625 ManagedMedia &ref( m_impl->findMM(accessId));
627 bool desired = false;
628 if( ref.handler->isAttached())
631 desired = v->isDesiredMedia(ref.handler);
633 catch(const zypp::Exception &e) {
638 DBG << "isDesiredMedia(" << accessId << "): "
639 << (desired ? "" : "not ")
640 << "desired (report by "
641 << v->info() << ")" << std::endl;
645 // ---------------------------------------------------------------
647 MediaManager::isChangeable(MediaAccessId accessId)
649 return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
652 // ---------------------------------------------------------------
654 MediaManager::localRoot(MediaAccessId accessId) const
656 MutexLock glock(g_Mutex);
658 ManagedMedia &ref( m_impl->findMM(accessId));
661 path = ref.handler->localRoot();
665 // ---------------------------------------------------------------
667 MediaManager::localPath(MediaAccessId accessId,
668 const Pathname & pathname) const
670 MutexLock glock(g_Mutex);
672 ManagedMedia &ref( m_impl->findMM(accessId));
675 path = ref.handler->localPath(pathname);
680 MediaManager::provideFile(MediaAccessId accessId,
681 const Pathname &filename,
682 const ByteCount &expectedFileSize ) const
684 MutexLock glock(g_Mutex);
686 ManagedMedia &ref( m_impl->findMM(accessId));
688 ref.checkDesired(accessId);
690 ref.handler->provideFile(filename, expectedFileSize);
693 // ---------------------------------------------------------------
695 MediaManager::provideFile(MediaAccessId accessId,
696 const Pathname &filename ) const
698 provideFile( accessId, filename, 0);
701 // ---------------------------------------------------------------
703 MediaManager::setDeltafile(MediaAccessId accessId,
704 const Pathname &filename ) const
706 MutexLock glock(g_Mutex);
708 ManagedMedia &ref( m_impl->findMM(accessId));
710 ref.checkDesired(accessId);
712 ref.handler->setDeltafile(filename);
715 // ---------------------------------------------------------------
717 MediaManager::provideDir(MediaAccessId accessId,
718 const Pathname &dirname) const
720 MutexLock glock(g_Mutex);
722 ManagedMedia &ref( m_impl->findMM(accessId));
724 ref.checkDesired(accessId);
726 ref.handler->provideDir(dirname);
729 // ---------------------------------------------------------------
731 MediaManager::provideDirTree(MediaAccessId accessId,
732 const Pathname &dirname) const
734 MutexLock glock(g_Mutex);
736 ManagedMedia &ref( m_impl->findMM(accessId));
738 ref.checkDesired(accessId);
740 ref.handler->provideDirTree(dirname);
743 // ---------------------------------------------------------------
745 MediaManager::releaseFile(MediaAccessId accessId,
746 const Pathname &filename) const
748 MutexLock glock(g_Mutex);
750 ManagedMedia &ref( m_impl->findMM(accessId));
752 ref.checkAttached(accessId);
754 ref.handler->releaseFile(filename);
757 // ---------------------------------------------------------------
759 MediaManager::releaseDir(MediaAccessId accessId,
760 const Pathname &dirname) const
762 MutexLock glock(g_Mutex);
764 ManagedMedia &ref( m_impl->findMM(accessId));
766 ref.checkAttached(accessId);
768 ref.handler->releaseDir(dirname);
772 // ---------------------------------------------------------------
774 MediaManager::releasePath(MediaAccessId accessId,
775 const Pathname &pathname) const
777 MutexLock glock(g_Mutex);
779 ManagedMedia &ref( m_impl->findMM(accessId));
781 ref.checkAttached(accessId);
783 ref.handler->releasePath(pathname);
786 // ---------------------------------------------------------------
788 MediaManager::dirInfo(MediaAccessId accessId,
789 std::list<std::string> &retlist,
790 const Pathname &dirname,
793 MutexLock glock(g_Mutex);
795 ManagedMedia &ref( m_impl->findMM(accessId));
797 // FIXME: ref.checkDesired(accessId); ???
798 ref.checkAttached(accessId);
800 ref.handler->dirInfo(retlist, dirname, dots);
803 // ---------------------------------------------------------------
805 MediaManager::dirInfo(MediaAccessId accessId,
806 filesystem::DirContent &retlist,
807 const Pathname &dirname,
810 MutexLock glock(g_Mutex);
812 ManagedMedia &ref( m_impl->findMM(accessId));
814 // FIXME: ref.checkDesired(accessId); ???
815 ref.checkAttached(accessId);
817 ref.handler->dirInfo(retlist, dirname, dots);
820 // ---------------------------------------------------------------
822 MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
824 MutexLock glock(g_Mutex);
825 ManagedMedia &ref( m_impl->findMM(accessId));
827 // FIXME: ref.checkDesired(accessId); ???
828 ref.checkAttached(accessId);
830 return ref.handler->doesFileExist(filename);
833 // ---------------------------------------------------------------
835 MediaManager::getDetectedDevices(MediaAccessId accessId,
836 std::vector<std::string> & devices,
837 unsigned int & index) const
839 MutexLock glock(g_Mutex);
840 ManagedMedia &ref( m_impl->findMM(accessId));
841 return ref.handler->getDetectedDevices(devices, index);
844 // ---------------------------------------------------------------
847 MediaManager::getMountTableMTime()
849 MutexLock glock(g_Mutex);
850 return MediaManager_Impl::getMountTableMTime();
853 // ---------------------------------------------------------------
856 MediaManager::getMountEntries()
858 MutexLock glock(g_Mutex);
860 return MediaManager_Impl::getMountEntries();
863 // ---------------------------------------------------------------
865 MediaManager::isUseableAttachPoint(const Pathname &path,
868 if( path.empty() || path == "/" || !PathInfo(path).isDir())
871 MutexLock glock(g_Mutex);
874 // check against our current attach points
876 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
877 for( ; m != m_impl->mediaMap.end(); ++m)
879 AttachedMedia ret = m->second.handler->attachedMedia();
880 if( ret.mediaSource && ret.attachPoint)
882 std::string mnt(ret.attachPoint->path.asString());
883 std::string our(path.asString());
887 // already used as attach point
891 if( mnt.size() > our.size() &&
892 mnt.at(our.size()) == '/' &&
893 !mnt.compare(0, our.size(), our))
895 // mountpoint is bellow of path
896 // (would hide the content)
906 // check against system mount entries
908 MountEntries entries( m_impl->getMountEntries());
909 MountEntries::const_iterator e;
910 for( e = entries.begin(); e != entries.end(); ++e)
912 std::string mnt(Pathname(e->dir).asString());
913 std::string our(path.asString());
917 // already used as mountpoint
921 if( mnt.size() > our.size() &&
922 mnt.at(our.size()) == '/' &&
923 !mnt.compare(0, our.size(), our))
925 // mountpoint is bellow of path
926 // (would hide the content)
934 // ---------------------------------------------------------------
936 MediaManager::getAttachedMedia(MediaAccessId &accessId) const
938 MutexLock glock(g_Mutex);
940 ManagedMedia &ref( m_impl->findMM(accessId));
942 return ref.handler->attachedMedia();
945 // ---------------------------------------------------------------
947 MediaManager::findAttachedMedia(const MediaSourceRef &media) const
949 MutexLock glock(g_Mutex);
951 if( !media || media->type.empty())
952 return AttachedMedia();
954 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
955 for( ; m != m_impl->mediaMap.end(); ++m)
957 if( !m->second.handler->isAttached())
960 AttachedMedia ret = m->second.handler->attachedMedia();
961 if( ret.mediaSource && ret.mediaSource->equals( *media))
964 return AttachedMedia();
967 // ---------------------------------------------------------------
969 MediaManager::forceReleaseShared(const MediaSourceRef &media)
971 MutexLock glock(g_Mutex);
973 if( !media || media->type.empty())
976 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
977 for( ; m != m_impl->mediaMap.end(); ++m)
979 if( !m->second.handler->isAttached())
982 AttachedMedia ret = m->second.handler->attachedMedia();
983 if( ret.mediaSource && ret.mediaSource->equals( *media))
985 m->second.handler->release();
986 m->second.desired = false;
991 //////////////////////////////////////////////////////////////////
993 ////////////////////////////////////////////////////////////////////
995 ////////////////////////////////////////////////////////////////////
997 //////////////////////////////////////////////////////////////////////
999 ** vim: set ts=2 sts=2 sw=2 ai et: