Imported Upstream version 17.0.0
[platform/upstream/libzypp.git] / zypp / media / MediaHandler.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaHandler.cc
10  *
11 */
12
13 #include <iostream>
14 #include <fstream>
15 #include <sstream>
16
17 #include "zypp/ZConfig.h"
18 #include "zypp/TmpPath.h"
19 #include "zypp/Date.h"
20 #include "zypp/base/LogTools.h"
21 #include "zypp/base/Gettext.h"
22 #include "zypp/base/String.h"
23 #include "zypp/media/MediaHandler.h"
24 #include "zypp/media/MediaManager.h"
25 #include "zypp/media/Mount.h"
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <errno.h>
29
30
31 using namespace std;
32
33 // use directory.yast on every media (not just via ftp/http)
34 #define NONREMOTE_DIRECTORY_YAST 1
35
36 namespace zypp {
37   namespace media {
38
39   Pathname MediaHandler::_attachPrefix("");
40
41 ///////////////////////////////////////////////////////////////////
42 //
43 //      CLASS NAME : MediaHandler
44 //
45 ///////////////////////////////////////////////////////////////////
46
47 ///////////////////////////////////////////////////////////////////
48 //
49 //
50 //      METHOD NAME : MediaHandler::MediaHandler
51 //      METHOD TYPE : Constructor
52 //
53 //      DESCRIPTION :
54 //
55 MediaHandler::MediaHandler ( const Url &      url_r,
56                              const Pathname & attach_point_r,
57                              const Pathname & urlpath_below_attachpoint_r,
58                              const bool       does_download_r )
59     : _mediaSource()
60     , _attachPoint( new AttachPoint())
61     , _attachPointHint()
62     , _relativeRoot( urlpath_below_attachpoint_r)
63     , _does_download( does_download_r )
64     , _attach_mtime(0)
65     , _url( url_r )
66     , _parentId(0)
67 {
68   Pathname real_attach_point( getRealPath(attach_point_r.asString()));
69
70   if ( !real_attach_point.empty() ) {
71     ///////////////////////////////////////////////////////////////////
72     // check if provided attachpoint is usable.
73     ///////////////////////////////////////////////////////////////////
74
75     PathInfo adir( real_attach_point );
76     //
77     // The verify if attach_point_r isn't a mountpoint of another
78     // device is done in the particular media handler (if needed).
79     //
80     // We just verify, if attach_point_r is a directory and for
81     // schemes other than "file" and "dir", if it is absolute.
82     //
83     if ( !adir.isDir()
84          || (_url.getScheme() != "file"
85              && _url.getScheme() != "dir"
86              && !real_attach_point.absolute()) )
87     {
88       ERR << "Provided attach point is not a absolute directory: "
89           << adir << endl;
90     }
91     else {
92       attachPointHint( real_attach_point, false);
93       setAttachPoint( real_attach_point, false);
94     }
95   }
96 }
97
98 ///////////////////////////////////////////////////////////////////
99 //
100 //
101 //      METHOD NAME : MediaHandler::~MediaHandler
102 //      METHOD TYPE : Destructor
103 //
104 //      DESCRIPTION :
105 //
106 MediaHandler::~MediaHandler()
107 {
108   try
109     {
110       removeAttachPoint();
111     }
112   catch(...) {}
113 }
114
115 void
116 MediaHandler::resetParentId()
117 {
118   _parentId = 0;
119 }
120
121 std::string
122 MediaHandler::getRealPath(const std::string &path)
123 {
124   std::string real;
125   if( !path.empty())
126   {
127 #if __GNUC__ > 2
128     /** GNU extension */
129     char *ptr = ::realpath(path.c_str(), NULL);
130     if( ptr != NULL)
131     {
132       real = ptr;
133       free( ptr);
134     }
135     else
136     /** the SUSv2 way */
137     if( EINVAL == errno)
138     {
139       char buff[PATH_MAX + 2];
140       memset(buff, '\0', sizeof(buff));
141       if( ::realpath(path.c_str(), buff) != NULL)
142       {
143         real = buff;
144       }
145     }
146 #else
147     char buff[PATH_MAX + 2];
148     memset(buff, '\0', sizeof(buff));
149     if( ::realpath(path.c_str(), buff) != NULL)
150     {
151       real = buff;
152     }
153 #endif
154   }
155   return real;
156 }
157
158 zypp::Pathname
159 MediaHandler::getRealPath(const Pathname &path)
160 {
161   return zypp::Pathname(getRealPath(path.asString()));
162 }
163
164
165 ///////////////////////////////////////////////////////////////////
166 //
167 //
168 //      METHOD NAME : MediaHandler::removeAttachPoint
169 //      METHOD TYPE : void
170 //
171 //      DESCRIPTION :
172 //
173 void
174 MediaHandler::removeAttachPoint()
175 {
176   if ( _mediaSource ) {
177     INT << "MediaHandler deleted with media attached." << endl;
178     return; // no cleanup if media still mounted!
179   }
180
181   DBG << "MediaHandler - checking if to remove attach point" << endl;
182   if ( _attachPoint.unique() &&
183        _attachPoint->temp    &&
184        !_attachPoint->path.empty() &&
185        PathInfo(_attachPoint->path).isDir())
186   {
187     Pathname path(_attachPoint->path);
188
189     setAttachPoint("", true);
190
191     int res = recursive_rmdir( path );
192     if ( res == 0 ) {
193       MIL << "Deleted default attach point " << path << endl;
194     } else {
195       ERR << "Failed to Delete default attach point " << path
196         << " errno(" << res << ")" << endl;
197     }
198   }
199   else
200   {
201     if( !_attachPoint->path.empty() && !_attachPoint->temp)
202       DBG << "MediaHandler - attachpoint is not temporary" << endl;
203   }
204 }
205
206
207 ///////////////////////////////////////////////////////////////////
208 //
209 //
210 //      METHOD NAME : MediaHandler::attachPoint
211 //      METHOD TYPE : Pathname
212 //
213 //      DESCRIPTION :
214 //
215 Pathname
216 MediaHandler::attachPoint() const
217 {
218   return _attachPoint->path;
219 }
220
221
222 ///////////////////////////////////////////////////////////////////
223 //
224 //
225 //      METHOD NAME : MediaHandler::attachPoint
226 //      METHOD TYPE :
227 //
228 //      DESCRIPTION :
229 //
230 void
231 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
232 {
233   _attachPoint.reset( new AttachPoint(path, temporary));
234 }
235
236 Pathname
237 MediaHandler::localRoot() const
238 {
239   if( _attachPoint->path.empty())
240     return Pathname();
241   else
242     return _attachPoint->path + _relativeRoot;
243 }
244
245 ///////////////////////////////////////////////////////////////////
246 //
247 //
248 //      METHOD NAME : MediaHandler::attachPoint
249 //      METHOD TYPE :
250 //
251 //      DESCRIPTION :
252 //
253 void
254 MediaHandler::setAttachPoint(const AttachPointRef &ref)
255 {
256   if( ref)
257     AttachPointRef(ref).swap(_attachPoint);
258   else
259     _attachPoint.reset( new AttachPoint());
260 }
261
262 ///////////////////////////////////////////////////////////////////
263 //
264 //
265 //      METHOD NAME : MediaHandler::attachPointHint
266 //      METHOD TYPE : void
267 //
268 //      DESCRIPTION :
269 //
270 void
271 MediaHandler::attachPointHint(const Pathname &path, bool temporary)
272 {
273   _attachPointHint.path = path;
274   _attachPointHint.temp = temporary;
275 }
276
277 ///////////////////////////////////////////////////////////////////
278 //
279 //
280 //      METHOD NAME : MediaHandler::attachPointHint
281 //      METHOD TYPE : AttachPoint
282 //
283 //      DESCRIPTION :
284 //
285 AttachPoint
286 MediaHandler::attachPointHint() const
287 {
288   return _attachPointHint;
289 }
290
291 ///////////////////////////////////////////////////////////////////
292 //
293 //
294 //      METHOD NAME : MediaHandler::findAttachedMedia
295 //      METHOD TYPE : AttachedMedia
296 //
297 //      DESCRIPTION :
298 //
299 AttachedMedia
300 MediaHandler::findAttachedMedia(const MediaSourceRef &media) const
301 {
302         return MediaManager().findAttachedMedia(media);
303 }
304
305 ///////////////////////////////////////////////////////////////////
306 //
307 //
308 //      METHOD NAME : MediaHandler::setAttachPrefix
309 //      METHOD TYPE : void
310 //
311 //      DESCRIPTION :
312 //
313 bool
314 MediaHandler::setAttachPrefix(const Pathname &attach_prefix)
315 {
316   if( attach_prefix.empty())
317   {
318     MIL << "Reseting to built-in attach point prefixes."
319         << std::endl;
320     MediaHandler::_attachPrefix = attach_prefix;
321     return true;
322   }
323   else
324   if( MediaHandler::checkAttachPoint(attach_prefix, false, true))
325   {
326     MIL << "Setting user defined attach point prefix: "
327         << attach_prefix << std::endl;
328     MediaHandler::_attachPrefix = attach_prefix;
329     return true;
330   }
331   return false;
332 }
333
334 ///////////////////////////////////////////////////////////////////
335 //
336 //
337 //      METHOD NAME : MediaHandler::attach
338 //      METHOD TYPE : Pathname
339 //
340 //      DESCRIPTION :
341 //
342 Pathname
343 MediaHandler::createAttachPoint() const
344 {
345   Pathname aroot;
346   Pathname apoint;
347   {
348     aroot = MediaHandler::_attachPrefix;        // explicit request
349     if ( ! aroot.empty() )
350       apoint = createAttachPoint( aroot );
351   }
352
353   if ( apoint.empty() )                         // fallback to config value
354   {
355     aroot = ZConfig::instance().download_mediaMountdir();
356     if ( ! aroot.empty() )
357       apoint = createAttachPoint( aroot );
358   }
359
360   if ( apoint.empty() )                         // fall back to temp space
361   {
362     aroot = filesystem::TmpPath::defaultLocation();
363     if ( ! aroot.empty() )
364       apoint = createAttachPoint( aroot );
365   }
366
367   if ( apoint.empty() )
368   {
369     auto except = MediaBadAttachPointException( url() );
370     except.addHistory( _("Create attach point: Can't find a writable directory to create an attach point") );
371     ZYPP_THROW( std::move(except) );
372   }
373
374   MIL << "Created default attach point " << apoint << std::endl;
375   return apoint;
376 }
377
378 Pathname
379 MediaHandler::createAttachPoint(const Pathname &attach_root) const
380 {
381   Pathname apoint;
382
383   if( attach_root.empty() || !attach_root.absolute()) {
384     ERR << "Create attach point: invalid attach root: '"
385         << attach_root << "'" << std::endl;
386     return apoint;
387   }
388
389   PathInfo adir( attach_root );
390   if( !adir.isDir() || (geteuid() != 0 && !adir.userMayRWX())) {
391     DBG << "Create attach point: attach root is not a writable directory: '"
392         << attach_root << "'" << std::endl;
393     return apoint;
394   }
395
396   static bool cleanup_once( true );
397   if ( cleanup_once )
398   {
399     cleanup_once = false;
400     DBG << "Look for orphaned attach points in " << adir << std::endl;
401     std::list<std::string> entries;
402     filesystem::readdir( entries, attach_root, false );
403     for ( const std::string & entry : entries )
404     {
405       if ( ! str::hasPrefix( entry, "AP_0x" ) )
406         continue;
407       PathInfo sdir( attach_root + entry );
408       if ( sdir.isDir()
409         && sdir.dev() == adir.dev()
410         && ( Date::now()-sdir.mtime() > Date::month ) )
411       {
412         DBG << "Remove orphaned attach point " << sdir << std::endl;
413         filesystem::recursive_rmdir( sdir.path() );
414       }
415     }
416   }
417
418   filesystem::TmpDir tmpdir( attach_root, "AP_0x" );
419   if ( tmpdir )
420   {
421     apoint = getRealPath( tmpdir.path().asString() );
422     if ( ! apoint.empty() )
423     {
424       tmpdir.autoCleanup( false );      // Take responsibility for cleanup.
425     }
426     else
427     {
428       ERR << "Unable to resolve real path for attach point " << tmpdir << std::endl;
429     }
430   }
431   else
432   {
433     ERR << "Unable to create attach point below " << attach_root << std::endl;
434   }
435   return apoint;
436 }
437
438 ///////////////////////////////////////////////////////////////////
439 //
440 //
441 //      METHOD NAME : MediaHandler::isUseableAttachPoint
442 //      METHOD TYPE : bool
443 //
444 //      DESCRIPTION :
445 //
446 bool
447 MediaHandler::isUseableAttachPoint(const Pathname &path, bool mtab) const
448 {
449   MediaManager  manager;
450   return manager.isUseableAttachPoint(path, mtab);
451 }
452
453
454 ///////////////////////////////////////////////////////////////////
455 //
456 //
457 //      METHOD NAME : MediaHandler::setMediaSource
458 //      METHOD TYPE : void
459 //
460 //      DESCRIPTION :
461 //
462 void
463 MediaHandler::setMediaSource(const MediaSourceRef &ref)
464 {
465   _mediaSource.reset();
466   if( ref && !ref->type.empty() && !ref->name.empty())
467     _mediaSource = ref;
468 }
469
470 ///////////////////////////////////////////////////////////////////
471 //
472 //
473 //      METHOD NAME : MediaHandler::attachedMedia
474 //      METHOD TYPE : AttachedMedia
475 //
476 //      DESCRIPTION :
477 //
478 AttachedMedia
479 MediaHandler::attachedMedia() const
480 {
481   if ( _mediaSource && _attachPoint)
482     return AttachedMedia(_mediaSource, _attachPoint);
483   else
484     return AttachedMedia();
485 }
486
487 ///////////////////////////////////////////////////////////////////
488 //
489 //
490 //      METHOD NAME : MediaHandler::isSharedMedia
491 //      METHOD TYPE : bool
492 //
493 //      DESCRIPTION :
494 //
495 bool
496 MediaHandler::isSharedMedia() const
497 {
498   return !_mediaSource.unique();
499 }
500
501 ///////////////////////////////////////////////////////////////////
502 //
503 //
504 //      METHOD NAME : MediaHandler::checkAttached
505 //      METHOD TYPE : bool
506 //
507 //      DESCRIPTION :
508 //
509 bool
510 MediaHandler::checkAttached(bool matchMountFs) const
511 {
512   bool _isAttached = false;
513
514   AttachedMedia ref( attachedMedia() );
515   if( ref.mediaSource )
516   {
517     time_t old_mtime = _attach_mtime;
518     _attach_mtime = MediaManager::getMountTableMTime();
519     if( !(old_mtime <= 0 || _attach_mtime != old_mtime) )
520     {
521       // OK, skip the check (we've seen it at least once)
522       _isAttached = true;
523     }
524     else
525     {
526       if( old_mtime > 0)
527         DBG << "Mount table changed - rereading it" << std::endl;
528       else
529         DBG << "Forced check of the mount table" << std::endl;
530
531       MountEntries entries( MediaManager::getMountEntries());
532       for_( e, entries.begin(), entries.end() )
533       {
534         if ( ref.attachPoint->path != Pathname(e->dir) )
535           continue;     // at least the mount points must match
536
537         bool        is_device = false;
538         PathInfo    dev_info;
539         if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
540             dev_info(e->src) && dev_info.isBlk() )
541         {
542           is_device = true;
543         }
544
545         if( is_device &&  (ref.mediaSource->maj_nr &&
546                            ref.mediaSource->bdir.empty()))
547         {
548           std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
549           MediaSource media(mtype, e->src, dev_info.devMajor(), dev_info.devMinor());
550
551           if( ref.mediaSource->equals( media ) )
552           {
553             DBG << "Found media device "
554                 << ref.mediaSource->asString()
555                 << " in the mount table as " << e->src << std::endl;
556             _isAttached = true;
557             break;
558           }
559           // differs
560         }
561         else
562         if(!is_device && (!ref.mediaSource->maj_nr ||
563                           !ref.mediaSource->bdir.empty()))
564         {
565           if( ref.mediaSource->bdir.empty())
566           {
567             // bnc#710269: Type nfs may appear as nfs4 in in the mount table
568             // and maybe vice versa. Similar cifs/smb. Need to unify these types:
569             if ( matchMountFs && e->type != ref.mediaSource->type )
570             {
571               if ( str::hasPrefix( e->type, "nfs" ) && str::hasPrefix( ref.mediaSource->type, "nfs" ) )
572                 matchMountFs = false;
573               else if ( ( e->type == "cifs" || e->type == "smb" ) && ( ref.mediaSource->type == "cifs" || ref.mediaSource->type == "smb" ) )
574                 matchMountFs = false;
575               else
576                 continue;       // different types cannot match
577             }
578             // Here: Types are ok or not to check.
579             // Check the name except for nfs (bnc#804544; symlink resolution in mount path)
580             //
581             //   [fibonacci]$ ls -l /Local/ma/c12.1
582             //   lrwxrwxrwx  /Local/ma/c12.1 -> zypp-SuSE-Code-12_1-Branch/
583             //
584             //   [localhost]$ mount -t nfs4 fibonacci:/Local/ma/c12.1 /mnt
585             //   [localhost]$ mount
586             //   fibonacci:/Local/ma/zypp-SuSE-Code-12_1-Branch on /mnt
587
588             // std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
589             // MediaSource media(mtype, e->src);
590
591             if( ref.mediaSource->name == e->src || str::hasPrefix( ref.mediaSource->type, "nfs" ) )
592             {
593               DBG << "Found media name "
594               << ref.mediaSource->asString()
595               << " in the mount table as " << e->src << std::endl;
596               _isAttached = true;
597               break;
598             }
599           }
600           else
601           {
602             if ( ref.mediaSource->bdir == e->src )
603             {
604               DBG << "Found bound media "
605                   << ref.mediaSource->asString()
606                   << " in the mount table as " << e->src << std::endl;
607               _isAttached = true;
608               break;
609             }
610           }
611           // differs
612         }
613         else // mixed cases:
614         {
615           // Type ISO: Since 11.1 mtab might contain the name of
616           // the loop device instead of the iso file:
617           if ( ref.mediaSource->type == "iso"
618             && str::hasPrefix( Pathname(e->src).asString(), "/dev/loop" )
619             && ref.attachPoint->path == Pathname(e->dir) )
620           {
621             DBG << "Found bound media "
622             << ref.mediaSource->asString()
623             << " in the mount table as " << e->src << std::endl;
624             _isAttached = true;
625             break;
626           }
627         }
628       }
629
630       if( !_isAttached)
631       {
632         MIL << "Looking for " << ref << endl;
633         if( entries.empty() )
634         {
635           ERR << "Unable to find any entry in the /etc/mtab file" << std::endl;
636         }
637         else
638         {
639           dumpRange( DBG << "MountEntries: ", entries.begin(), entries.end() ) << endl;
640         }
641         if( old_mtime > 0 )
642         {
643           ERR << "Attached media not in mount table any more - forcing reset!"
644               << std::endl;
645
646           _mediaSource.reset();
647         }
648         else
649         {
650           WAR << "Attached media not in mount table ..." << std::endl;
651         }
652
653         // reset the mtime and force a new check to make sure,
654         // that we've found the media at least once in the mtab.
655         _attach_mtime = 0;
656       }
657     }
658   }
659   return _isAttached;
660 }
661
662 ///////////////////////////////////////////////////////////////////
663 //
664 //
665 //      METHOD NAME : MediaHandler::attach
666 //      METHOD TYPE : PMError
667 //
668 //      DESCRIPTION :
669 //
670 void MediaHandler::attach( bool next )
671 {
672   if ( isAttached() )
673     return;
674
675   // reset it in case of overloaded isAttached()
676   // that checks the media against /etc/mtab ...
677   setMediaSource(MediaSourceRef());
678
679   AttachPoint ap( attachPointHint());
680   setAttachPoint(ap.path, ap.temp);
681
682   try
683   {
684     attachTo( next ); // pass to concrete handler
685   }
686   catch(const MediaException &e)
687   {
688     removeAttachPoint();
689     ZYPP_RETHROW(e);
690   }
691   MIL << "Attached: " << *this << endl;
692 }
693
694
695 ///////////////////////////////////////////////////////////////////
696 //
697 //
698 //      METHOD NAME : MediaHandler::localPath
699 //      METHOD TYPE : Pathname
700 //
701 Pathname MediaHandler::localPath( const Pathname & pathname ) const
702 {
703     Pathname _localRoot( localRoot());
704     if ( _localRoot.empty() )
705         return _localRoot;
706
707     // we must check maximum file name length
708     // this is important for fetching the suseservers, the
709     // url with all parameters can get too long (bug #42021)
710
711     return _localRoot + pathname.absolutename();
712 }
713
714
715
716
717
718 ///////////////////////////////////////////////////////////////////
719 //
720 //
721 //      METHOD NAME : MediaHandler::disconnect
722 //      METHOD TYPE : PMError
723 //
724 void MediaHandler::disconnect()
725 {
726   if ( !isAttached() )
727     return;
728
729   disconnectFrom(); // pass to concrete handler
730   MIL << "Disconnected: " << *this << endl;
731 }
732
733 ///////////////////////////////////////////////////////////////////
734 //
735 //
736 //      METHOD NAME : MediaHandler::release
737 //      METHOD TYPE : PMError
738 //
739 //      DESCRIPTION :
740 //
741 void MediaHandler::release( const std::string & ejectDev )
742 {
743   if ( !isAttached() ) {
744     DBG << "Request to release media - not attached; eject '" << ejectDev << "'"
745         << std::endl;
746     if ( !ejectDev.empty() )
747       forceEject(ejectDev);
748     return;
749   }
750
751   DBG << "Request to release attached media "
752       << _mediaSource->asString()
753       << ", use count=" << _mediaSource.use_count()
754       << std::endl;
755
756   if( _mediaSource.unique())
757   {
758     DBG << "Releasing media " << _mediaSource->asString() << std::endl;
759     try {
760       releaseFrom( ejectDev ); // pass to concrete handler
761     }
762     catch(const MediaNotEjectedException &e)
763     {
764       // not ejected because the media
765       // is mounted by somebody else
766       // (if our attach point is busy,
767       //  we get an umount exception)
768       _mediaSource.reset(NULL);
769       removeAttachPoint();
770       // OK, retrow now
771       ZYPP_RETHROW(e);
772     }
773     _mediaSource.reset(NULL);
774     removeAttachPoint();
775   }
776   else if( !ejectDev.empty() ) {
777     //
778     // Can't eject a shared media
779     //
780     //ZYPP_THROW(MediaIsSharedException(_mediaSource->asString()));
781
782     MediaSourceRef media( new MediaSource(*_mediaSource));
783     _mediaSource.reset(NULL);
784
785     MediaManager manager;
786     manager.forceReleaseShared(media);
787
788     setMediaSource(media);
789     DBG << "Releasing media (forced) " << _mediaSource->asString() << std::endl;
790     try {
791       releaseFrom( ejectDev ); // pass to concrete handler
792     }
793     catch(const MediaNotEjectedException &e)
794     {
795       // not ejected because the media
796       // is mounted by somebody else
797       // (if our attach point is busy,
798       //  we get an umount exception)
799       _mediaSource.reset(NULL);
800       removeAttachPoint();
801       // OK, retrow now
802       ZYPP_RETHROW(e);
803     }
804     _mediaSource.reset(NULL);
805     removeAttachPoint();
806   }
807   else {
808     DBG << "Releasing shared media reference only" << std::endl;
809     _mediaSource.reset(NULL);
810     setAttachPoint("", true);
811   }
812   MIL << "Released: " << *this << endl;
813 }
814
815 void MediaHandler::forceRelaseAllMedia(bool matchMountFs)
816 {
817   forceRelaseAllMedia( attachedMedia().mediaSource, matchMountFs);
818 }
819
820 void MediaHandler::forceRelaseAllMedia(const MediaSourceRef &ref,
821                                        bool                  matchMountFs)
822 {
823   if( !ref)
824     return;
825
826   MountEntries  entries( MediaManager::getMountEntries());
827   MountEntries::const_iterator e;
828   for( e = entries.begin(); e != entries.end(); ++e)
829   {
830     bool        is_device = false;
831     PathInfo    dev_info;
832
833     if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
834         dev_info(e->src) && dev_info.isBlk())
835     {
836       is_device = true;
837     }
838
839     if( is_device &&  ref->maj_nr)
840     {
841       std::string mtype(matchMountFs ? e->type : ref->type);
842       MediaSource media(mtype, e->src, dev_info.devMajor(), dev_info.devMinor());
843
844       if( ref->equals( media) && e->type != "subfs")
845       {
846         DBG << "Forcing release of media device "
847             << ref->asString()
848             << " in the mount table as "
849             << e->src << std::endl;
850         try {
851           Mount mount;
852           mount.umount(e->dir);
853         }
854         catch (const Exception &e)
855         {
856           ZYPP_CAUGHT(e);
857         }
858       }
859     }
860     else
861     if(!is_device && !ref->maj_nr)
862     {
863       std::string mtype(matchMountFs ? e->type : ref->type);
864       MediaSource media(mtype, e->src);
865       if( ref->equals( media))
866       {
867         DBG << "Forcing release of media name "
868             << ref->asString()
869             << " in the mount table as "
870             << e->src << std::endl;
871         try {
872           Mount mount;
873           mount.umount(e->dir);
874         }
875         catch (const Exception &e)
876         {
877           ZYPP_CAUGHT(e);
878         }
879       }
880     }
881   }
882 }
883
884 bool
885 MediaHandler::checkAttachPoint(const Pathname &apoint) const
886 {
887   return MediaHandler::checkAttachPoint( apoint, true, false);
888 }
889
890 // STATIC
891 bool
892 MediaHandler::checkAttachPoint(const Pathname &apoint,
893                                bool            emptydir,
894                                bool            writeable)
895 {
896   if( apoint.empty() || !apoint.absolute())
897   {
898     ERR << "Attach point '" << apoint << "' is not absolute"
899         << std::endl;
900     return false;
901   }
902   if( apoint == "/")
903   {
904     ERR << "Attach point '" << apoint << "' is not allowed"
905         << std::endl;
906     return false;
907   }
908
909   PathInfo ainfo(apoint);
910   if( !ainfo.isDir())
911   {
912     ERR << "Attach point '" << apoint << "' is not a directory"
913         << std::endl;
914     return false;
915   }
916
917   if( emptydir)
918   {
919     if( 0 != zypp::filesystem::is_empty_dir(apoint))
920     {
921       ERR << "Attach point '" << apoint << "' is not a empty directory"
922           << std::endl;
923       return false;
924     }
925   }
926
927   if( writeable)
928   {
929     Pathname apath(apoint + "XXXXXX");
930     char    *atemp = ::strdup( apath.asString().c_str());
931     char    *atest = NULL;
932     if( !ainfo.userMayRWX() || atemp == NULL ||
933         (atest=::mkdtemp(atemp)) == NULL)
934     {
935       if( atemp != NULL)
936         ::free(atemp);
937
938       ERR << "Attach point '" << ainfo.path()
939           << "' is not a writeable directory" << std::endl;
940       return false;
941     }
942     else if( atest != NULL)
943       ::rmdir(atest);
944
945     if( atemp != NULL)
946       ::free(atemp);
947   }
948   return true;
949 }
950
951 ///////////////////////////////////////////////////////////////////
952 //
953 //      METHOD NAME : MediaHandler::dependsOnParent
954 //      METHOD TYPE : bool
955 //
956 //      DESCRIPTION :
957 //
958 bool
959 MediaHandler::dependsOnParent()
960 {
961   return _parentId != 0;
962 }
963
964 bool
965 MediaHandler::dependsOnParent(MediaAccessId parentId, bool exactIdMatch)
966 {
967   if( _parentId != 0)
968   {
969     if(parentId == _parentId)
970       return true;
971
972     if( !exactIdMatch)
973     {
974       MediaManager mm;
975       AttachedMedia am1 = mm.getAttachedMedia(_parentId);
976       AttachedMedia am2 = mm.getAttachedMedia(parentId);
977       if( am1.mediaSource && am2.mediaSource)
978       {
979         return am1.mediaSource->equals( *(am2.mediaSource));
980       }
981     }
982   }
983   return false;
984 }
985
986 ///////////////////////////////////////////////////////////////////
987 //
988 //
989 //      METHOD NAME : MediaHandler::provideFile
990 //      METHOD TYPE : PMError
991 //
992 //      DESCRIPTION :
993 //
994 void MediaHandler::provideFileCopy( Pathname srcFilename,
995                                        Pathname targetFilename ) const
996 {
997   if ( !isAttached() ) {
998     INT << "Media not_attached on provideFileCopy(" << srcFilename
999         << "," << targetFilename << ")" << endl;
1000     ZYPP_THROW(MediaNotAttachedException(url()));
1001   }
1002
1003   getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
1004   DBG << "provideFileCopy(" << srcFilename << "," << targetFilename  << ")" << endl;
1005 }
1006
1007 void MediaHandler::provideFile( Pathname filename ) const
1008 {
1009   if ( !isAttached() ) {
1010     INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
1011     ZYPP_THROW(MediaNotAttachedException(url()));
1012   }
1013
1014   getFile( filename ); // pass to concrete handler
1015   DBG << "provideFile(" << filename << ")" << endl;
1016 }
1017
1018
1019 ///////////////////////////////////////////////////////////////////
1020 //
1021 //
1022 //      METHOD NAME : MediaHandler::provideDir
1023 //      METHOD TYPE : PMError
1024 //
1025 //      DESCRIPTION :
1026 //
1027 void MediaHandler::provideDir( Pathname dirname ) const
1028 {
1029   if ( !isAttached() ) {
1030     INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
1031     ZYPP_THROW(MediaNotAttachedException(url()));
1032   }
1033
1034   getDir( dirname, /*recursive*/false ); // pass to concrete handler
1035   MIL << "provideDir(" << dirname << ")" << endl;
1036 }
1037
1038 ///////////////////////////////////////////////////////////////////
1039 //
1040 //
1041 //      METHOD NAME : MediaHandler::provideDirTree
1042 //      METHOD TYPE : PMError
1043 //
1044 //      DESCRIPTION :
1045 //
1046 void MediaHandler::provideDirTree( Pathname dirname ) const
1047 {
1048   if ( !isAttached() ) {
1049     INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
1050     ZYPP_THROW(MediaNotAttachedException(url()));
1051   }
1052
1053   getDir( dirname, /*recursive*/true ); // pass to concrete handler
1054   MIL << "provideDirTree(" << dirname << ")" << endl;
1055 }
1056
1057 ///////////////////////////////////////////////////////////////////
1058 //
1059 //
1060 //      METHOD NAME : MediaHandler::releasePath
1061 //      METHOD TYPE : PMError
1062 //
1063 //      DESCRIPTION :
1064 //
1065 void MediaHandler::releasePath( Pathname pathname ) const
1066 {
1067   if ( ! _does_download || _attachPoint->empty() )
1068     return;
1069
1070   PathInfo info( localPath( pathname ) );
1071
1072   if ( info.isFile() ) {
1073     unlink( info.path() );
1074   } else if ( info.isDir() ) {
1075     if ( info.path() != localRoot() ) {
1076       recursive_rmdir( info.path() );
1077     } else {
1078       clean_dir( info.path() );
1079     }
1080   }
1081 }
1082
1083 ///////////////////////////////////////////////////////////////////
1084 //
1085 //
1086 //      METHOD NAME : MediaHandler::dirInfo
1087 //      METHOD TYPE : PMError
1088 //
1089 //      DESCRIPTION :
1090 //
1091 void MediaHandler::dirInfo( std::list<std::string> & retlist,
1092                             const Pathname & dirname, bool dots ) const
1093 {
1094   retlist.clear();
1095
1096   if ( !isAttached() ) {
1097     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
1098     ZYPP_THROW(MediaNotAttachedException(url()));
1099   }
1100
1101   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
1102   MIL << "dirInfo(" << dirname << ")" << endl;
1103 }
1104
1105 ///////////////////////////////////////////////////////////////////
1106 //
1107 //
1108 //      METHOD NAME : MediaHandler::dirInfo
1109 //      METHOD TYPE : PMError
1110 //
1111 //      DESCRIPTION :
1112 //
1113 void MediaHandler::dirInfo( filesystem::DirContent & retlist,
1114                             const Pathname & dirname, bool dots ) const
1115 {
1116   retlist.clear();
1117
1118   if ( !isAttached() ) {
1119     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
1120     ZYPP_THROW(MediaNotAttachedException(url()));
1121   }
1122
1123   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
1124   MIL << "dirInfo(" << dirname << ")" << endl;
1125 }
1126
1127 ///////////////////////////////////////////////////////////////////
1128 //
1129 //
1130 //      METHOD NAME : MediaHandler::doesFileExist
1131 //      METHOD TYPE : PMError
1132 //
1133 //      DESCRIPTION :
1134 //
1135 bool MediaHandler::doesFileExist( const Pathname & filename ) const
1136 {
1137   // TODO do some logging
1138   if ( !isAttached() ) {
1139     INT << "Error Not attached on doesFileExist(" << filename << ")" << endl;
1140     ZYPP_THROW(MediaNotAttachedException(url()));
1141   }
1142   return getDoesFileExist( filename );
1143   MIL << "doesFileExist(" << filename << ")" << endl;
1144 }
1145
1146 ///////////////////////////////////////////////////////////////////
1147 //
1148 //
1149 //      METHOD NAME : MediaHandler::getDirectoryYast
1150 //      METHOD TYPE : PMError
1151 //
1152 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
1153                                         const Pathname & dirname, bool dots ) const
1154 {
1155   retlist.clear();
1156
1157   filesystem::DirContent content;
1158   getDirectoryYast( content, dirname, dots );
1159
1160   // convert to std::list<std::string>
1161   for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
1162     retlist.push_back( it->name );
1163   }
1164 }
1165
1166 ///////////////////////////////////////////////////////////////////
1167 //
1168 //
1169 //      METHOD NAME : MediaHandler::getDirectoryYast
1170 //      METHOD TYPE : PMError
1171 //
1172 void MediaHandler::getDirectoryYast( filesystem::DirContent & retlist,
1173                                      const Pathname & dirname, bool dots ) const
1174 {
1175   retlist.clear();
1176
1177   // look for directory.yast
1178   Pathname dirFile = dirname + "directory.yast";
1179   getFile( dirFile );
1180   DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
1181
1182   // using directory.yast
1183   ifstream dir( localPath( dirFile ).asString().c_str() );
1184   if ( dir.fail() ) {
1185     ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
1186     ZYPP_THROW(MediaSystemException(url(),
1187       "Unable to load '" + localPath( dirFile ).asString() + "'"));
1188   }
1189
1190   string line;
1191   while( getline( dir, line ) ) {
1192     if ( line.empty() ) continue;
1193     if ( line == "directory.yast" ) continue;
1194
1195     // Newer directory.yast append '/' to directory names
1196     // Remaining entries are unspecified, although most probabely files.
1197     filesystem::FileType type = filesystem::FT_NOT_AVAIL;
1198     if ( *line.rbegin() == '/' ) {
1199       line.erase( line.end()-1 );
1200       type = filesystem::FT_DIR;
1201     }
1202
1203     if ( dots ) {
1204       if ( line == "." || line == ".." ) continue;
1205     } else {
1206       if ( *line.begin() == '.' ) continue;
1207     }
1208
1209     retlist.push_back( filesystem::DirEntry( line, type ) );
1210   }
1211 }
1212
1213 /******************************************************************
1214 **
1215 **
1216 **      FUNCTION NAME : operator<<
1217 **      FUNCTION TYPE : ostream &
1218 */
1219 ostream & operator<<( ostream & str, const MediaHandler & obj )
1220 {
1221   str << obj.url() << ( obj.isAttached() ? "" : " not" )
1222     << " attached; localRoot \"" << obj.localRoot() << "\"";
1223   return str;
1224 }
1225
1226 ///////////////////////////////////////////////////////////////////
1227 //
1228 //
1229 //      METHOD NAME : MediaHandler::getFile
1230 //      METHOD TYPE : PMError
1231 //
1232 //      DESCRIPTION : Asserted that media is attached.
1233 //                    Default implementation of pure virtual.
1234 //
1235 void MediaHandler::getFile( const Pathname & filename ) const
1236 {
1237     PathInfo info( localPath( filename ) );
1238     if( info.isFile() ) {
1239         return;
1240     }
1241
1242     if (info.isExist())
1243       ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
1244     else
1245       ZYPP_THROW(MediaFileNotFoundException(url(), filename));
1246 }
1247
1248
1249 void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
1250 {
1251   getFile(srcFilename);
1252
1253   if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
1254     ZYPP_THROW(MediaWriteException(targetFilename));
1255   }
1256 }
1257
1258
1259
1260 ///////////////////////////////////////////////////////////////////
1261 //
1262 //
1263 //      METHOD NAME : MediaHandler::getDir
1264 //      METHOD TYPE : PMError
1265 //
1266 //      DESCRIPTION : Asserted that media is attached.
1267 //                    Default implementation of pure virtual.
1268 //
1269 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
1270 {
1271   PathInfo info( localPath( dirname ) );
1272   if( info.isDir() ) {
1273     return;
1274   }
1275
1276   if (info.isExist())
1277     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1278   else
1279     ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
1280 }
1281
1282 ///////////////////////////////////////////////////////////////////
1283 //
1284 //
1285 //      METHOD NAME : MediaHandler::getDirInfo
1286 //      METHOD TYPE : PMError
1287 //
1288 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
1289 //                    Default implementation of pure virtual.
1290 //
1291 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
1292                                const Pathname & dirname, bool dots ) const
1293 {
1294   PathInfo info( localPath( dirname ) );
1295   if( ! info.isDir() ) {
1296     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1297   }
1298
1299 #if NONREMOTE_DIRECTORY_YAST
1300   // use directory.yast if available
1301   try {
1302     getDirectoryYast( retlist, dirname, dots );
1303   }
1304   catch (const MediaException & excpt_r)
1305   {
1306 #endif
1307
1308     // readdir
1309     int res = readdir( retlist, info.path(), dots );
1310     if ( res )
1311     {
1312       MediaSystemException nexcpt(url(), "readdir failed");
1313 #if NONREMOTE_DIRECTORY_YAST
1314       nexcpt.remember(excpt_r);
1315 #endif
1316       ZYPP_THROW(nexcpt);
1317     }
1318
1319 #if NONREMOTE_DIRECTORY_YAST
1320   }
1321 #endif
1322
1323   return;
1324 }
1325
1326 ///////////////////////////////////////////////////////////////////
1327 //
1328 //
1329 //      METHOD NAME : MediaHandler::getDirInfo
1330 //      METHOD TYPE : PMError
1331 //
1332 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
1333 //                    Default implementation of pure virtual.
1334 //
1335 void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
1336                                const Pathname & dirname, bool dots ) const
1337 {
1338   PathInfo info( localPath( dirname ) );
1339   if( ! info.isDir() ) {
1340     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1341   }
1342
1343 #if NONREMOTE_DIRECTORY_YAST
1344   // use directory.yast if available
1345   try {
1346     getDirectoryYast( retlist, dirname, dots );
1347   }
1348   catch (const MediaException & excpt_r)
1349   {
1350 #endif
1351
1352     // readdir
1353     int res = readdir( retlist, info.path(), dots );
1354     if ( res )
1355     {
1356         MediaSystemException nexcpt(url(), "readdir failed");
1357 #if NONREMOTE_DIRECTORY_YAST
1358         nexcpt.remember(excpt_r);
1359 #endif
1360         ZYPP_THROW(nexcpt);
1361     }
1362 #if NONREMOTE_DIRECTORY_YAST
1363   }
1364 #endif
1365 }
1366
1367 ///////////////////////////////////////////////////////////////////
1368 //
1369 //
1370 //      METHOD NAME : MediaHandler::getDoesFileExist
1371 //      METHOD TYPE : PMError
1372 //
1373 //      DESCRIPTION : Asserted that file is not a directory
1374 //                    Default implementation of pure virtual.
1375 //
1376 bool MediaHandler::getDoesFileExist( const Pathname & filename ) const
1377 {
1378   PathInfo info( localPath( filename ) );
1379   if( info.isDir() ) {
1380     ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
1381   }
1382   return info.isExist();
1383 }
1384
1385 bool MediaHandler::hasMoreDevices()
1386 {
1387   return false;
1388 }
1389
1390 void MediaHandler::getDetectedDevices(std::vector<std::string> & devices,
1391                                       unsigned int & index) const
1392 {
1393   // clear the vector by default
1394   if (!devices.empty())
1395     devices.clear();
1396   index = 0;
1397
1398   DBG << "No devices for this medium" << endl;
1399 }
1400
1401 void MediaHandler::setDeltafile( const Pathname & filename ) const
1402 {
1403   _deltafile = filename;
1404 }
1405
1406 Pathname MediaHandler::deltafile() const {
1407   return _deltafile;
1408 }
1409
1410   } // namespace media
1411 } // namespace zypp
1412 // vim: set ts=8 sts=2 sw=2 ai noet: