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