28c581baf0882bdb9a5cd43dee3ee30fc82e02eb
[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         else // mixed cases:
612         {
613           // Type ISO: Since 11.1 mtab might contain the name of
614           // the loop device instead of the iso file:
615           if ( ref.mediaSource->type == "iso"
616             && str::hasPrefix( Pathname(e->src).asString(), "/dev/loop" )
617             && ref.attachPoint->path == Pathname(e->dir) )
618           {
619             DBG << "Found bound media "
620             << ref.mediaSource->asString()
621             << " in the mount table as " << e->src << std::endl;
622             _isAttached = true;
623             break;
624           }
625         }
626       }
627
628       if( !_isAttached)
629       {
630         MIL << "Looking for " << ref << endl;
631         if( entries.empty() )
632         {
633           ERR << "Unable to find any entry in the /etc/mtab file" << std::endl;
634         }
635         else
636         {
637           dumpRange( DBG << "MountEntries: ", entries.begin(), entries.end() ) << endl;
638         }
639         if( old_mtime > 0 )
640         {
641           ERR << "Attached media not in mount table any more - forcing reset!"
642               << std::endl;
643
644           _mediaSource.reset();
645         }
646         else
647         {
648           WAR << "Attached media not in mount table ..." << std::endl;
649         }
650
651         // reset the mtime and force a new check to make sure,
652         // that we've found the media at least once in the mtab.
653         _attach_mtime = 0;
654       }
655     }
656   }
657   return _isAttached;
658 }
659
660 ///////////////////////////////////////////////////////////////////
661 //
662 //
663 //      METHOD NAME : MediaHandler::attach
664 //      METHOD TYPE : PMError
665 //
666 //      DESCRIPTION :
667 //
668 void MediaHandler::attach( bool next )
669 {
670   if ( isAttached() )
671     return;
672
673   // reset it in case of overloaded isAttached()
674   // that checks the media against /etc/mtab ...
675   setMediaSource(MediaSourceRef());
676
677   AttachPoint ap( attachPointHint());
678   setAttachPoint(ap.path, ap.temp);
679
680   try
681   {
682     attachTo( next ); // pass to concrete handler
683   }
684   catch(const MediaException &e)
685   {
686     removeAttachPoint();
687     ZYPP_RETHROW(e);
688   }
689   MIL << "Attached: " << *this << endl;
690 }
691
692
693 ///////////////////////////////////////////////////////////////////
694 //
695 //
696 //      METHOD NAME : MediaHandler::localPath
697 //      METHOD TYPE : Pathname
698 //
699 Pathname MediaHandler::localPath( const Pathname & pathname ) const
700 {
701     Pathname _localRoot( localRoot());
702     if ( _localRoot.empty() )
703         return _localRoot;
704
705     // we must check maximum file name length
706     // this is important for fetching the suseservers, the
707     // url with all parameters can get too long (bug #42021)
708
709     return _localRoot + pathname.absolutename();
710 }
711
712
713
714
715
716 ///////////////////////////////////////////////////////////////////
717 //
718 //
719 //      METHOD NAME : MediaHandler::disconnect
720 //      METHOD TYPE : PMError
721 //
722 void MediaHandler::disconnect()
723 {
724   if ( !isAttached() )
725     return;
726
727   disconnectFrom(); // pass to concrete handler
728   MIL << "Disconnected: " << *this << endl;
729 }
730
731 ///////////////////////////////////////////////////////////////////
732 //
733 //
734 //      METHOD NAME : MediaHandler::release
735 //      METHOD TYPE : PMError
736 //
737 //      DESCRIPTION :
738 //
739 void MediaHandler::release( const std::string & ejectDev )
740 {
741   if ( !isAttached() ) {
742     DBG << "Request to release media - not attached; eject '" << ejectDev << "'"
743         << std::endl;
744     if ( !ejectDev.empty() )
745       forceEject(ejectDev);
746     return;
747   }
748
749   DBG << "Request to release attached media "
750       << _mediaSource->asString()
751       << ", use count=" << _mediaSource.use_count()
752       << std::endl;
753
754   if( _mediaSource.unique())
755   {
756     DBG << "Releasing media " << _mediaSource->asString() << std::endl;
757     try {
758       releaseFrom( ejectDev ); // pass to concrete handler
759     }
760     catch(const MediaNotEjectedException &e)
761     {
762       // not ejected because the media
763       // is mounted by somebody else
764       // (if our attach point is busy,
765       //  we get an umount exception)
766       _mediaSource.reset(NULL);
767       removeAttachPoint();
768       // OK, retrow now
769       ZYPP_RETHROW(e);
770     }
771     _mediaSource.reset(NULL);
772     removeAttachPoint();
773   }
774   else if( !ejectDev.empty() ) {
775     //
776     // Can't eject a shared media
777     //
778     //ZYPP_THROW(MediaIsSharedException(_mediaSource->asString()));
779
780     MediaSourceRef media( new MediaSource(*_mediaSource));
781     _mediaSource.reset(NULL);
782
783     MediaManager manager;
784     manager.forceReleaseShared(media);
785
786     setMediaSource(media);
787     DBG << "Releasing media (forced) " << _mediaSource->asString() << std::endl;
788     try {
789       releaseFrom( ejectDev ); // pass to concrete handler
790     }
791     catch(const MediaNotEjectedException &e)
792     {
793       // not ejected because the media
794       // is mounted by somebody else
795       // (if our attach point is busy,
796       //  we get an umount exception)
797       _mediaSource.reset(NULL);
798       removeAttachPoint();
799       // OK, retrow now
800       ZYPP_RETHROW(e);
801     }
802     _mediaSource.reset(NULL);
803     removeAttachPoint();
804   }
805   else {
806     DBG << "Releasing shared media reference only" << std::endl;
807     _mediaSource.reset(NULL);
808     setAttachPoint("", true);
809   }
810   MIL << "Released: " << *this << endl;
811 }
812
813 void MediaHandler::forceRelaseAllMedia(bool matchMountFs)
814 {
815   forceRelaseAllMedia( attachedMedia().mediaSource, matchMountFs);
816 }
817
818 void MediaHandler::forceRelaseAllMedia(const MediaSourceRef &ref,
819                                        bool                  matchMountFs)
820 {
821   if( !ref)
822     return;
823
824   MountEntries  entries( MediaManager::getMountEntries());
825   MountEntries::const_iterator e;
826   for( e = entries.begin(); e != entries.end(); ++e)
827   {
828     bool        is_device = false;
829     PathInfo    dev_info;
830
831     if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
832         dev_info(e->src) && dev_info.isBlk())
833     {
834       is_device = true;
835     }
836
837     if( is_device &&  ref->maj_nr)
838     {
839       std::string mtype(matchMountFs ? e->type : ref->type);
840       MediaSource media(mtype, e->src, dev_info.devMajor(), dev_info.devMinor());
841
842       if( ref->equals( media) && e->type != "subfs")
843       {
844         DBG << "Forcing release of media device "
845             << ref->asString()
846             << " in the mount table as "
847             << e->src << std::endl;
848         try {
849           Mount mount;
850           mount.umount(e->dir);
851         }
852         catch (const Exception &e)
853         {
854           ZYPP_CAUGHT(e);
855         }
856       }
857     }
858     else
859     if(!is_device && !ref->maj_nr)
860     {
861       std::string mtype(matchMountFs ? e->type : ref->type);
862       MediaSource media(mtype, e->src);
863       if( ref->equals( media))
864       {
865         DBG << "Forcing release of media name "
866             << ref->asString()
867             << " in the mount table as "
868             << e->src << std::endl;
869         try {
870           Mount mount;
871           mount.umount(e->dir);
872         }
873         catch (const Exception &e)
874         {
875           ZYPP_CAUGHT(e);
876         }
877       }
878     }
879   }
880 }
881
882 bool
883 MediaHandler::checkAttachPoint(const Pathname &apoint) const
884 {
885   return MediaHandler::checkAttachPoint( apoint, true, false);
886 }
887
888 // STATIC
889 bool
890 MediaHandler::checkAttachPoint(const Pathname &apoint,
891                                bool            emptydir,
892                                bool            writeable)
893 {
894   if( apoint.empty() || !apoint.absolute())
895   {
896     ERR << "Attach point '" << apoint << "' is not absolute"
897         << std::endl;
898     return false;
899   }
900   if( apoint == "/")
901   {
902     ERR << "Attach point '" << apoint << "' is not allowed"
903         << std::endl;
904     return false;
905   }
906
907   PathInfo ainfo(apoint);
908   if( !ainfo.isDir())
909   {
910     ERR << "Attach point '" << apoint << "' is not a directory"
911         << std::endl;
912     return false;
913   }
914
915   if( emptydir)
916   {
917     if( 0 != zypp::filesystem::is_empty_dir(apoint))
918     {
919       ERR << "Attach point '" << apoint << "' is not a empty directory"
920           << std::endl;
921       return false;
922     }
923   }
924
925   if( writeable)
926   {
927     Pathname apath(apoint + "XXXXXX");
928     char    *atemp = ::strdup( apath.asString().c_str());
929     char    *atest = NULL;
930     if( !ainfo.userMayRWX() || atemp == NULL ||
931         (atest=::mkdtemp(atemp)) == NULL)
932     {
933       if( atemp != NULL)
934         ::free(atemp);
935
936       ERR << "Attach point '" << ainfo.path()
937           << "' is not a writeable directory" << std::endl;
938       return false;
939     }
940     else if( atest != NULL)
941       ::rmdir(atest);
942
943     if( atemp != NULL)
944       ::free(atemp);
945   }
946   return true;
947 }
948
949 ///////////////////////////////////////////////////////////////////
950 //
951 //      METHOD NAME : MediaHandler::dependsOnParent
952 //      METHOD TYPE : bool
953 //
954 //      DESCRIPTION :
955 //
956 bool
957 MediaHandler::dependsOnParent()
958 {
959   return _parentId != 0;
960 }
961
962 bool
963 MediaHandler::dependsOnParent(MediaAccessId parentId, bool exactIdMatch)
964 {
965   if( _parentId != 0)
966   {
967     if(parentId == _parentId)
968       return true;
969
970     if( !exactIdMatch)
971     {
972       MediaManager mm;
973       AttachedMedia am1 = mm.getAttachedMedia(_parentId);
974       AttachedMedia am2 = mm.getAttachedMedia(parentId);
975       if( am1.mediaSource && am2.mediaSource)
976       {
977         return am1.mediaSource->equals( *(am2.mediaSource));
978       }
979     }
980   }
981   return false;
982 }
983
984 ///////////////////////////////////////////////////////////////////
985 //
986 //
987 //      METHOD NAME : MediaHandler::provideFile
988 //      METHOD TYPE : PMError
989 //
990 //      DESCRIPTION :
991 //
992 void MediaHandler::provideFileCopy(Pathname srcFilename,
993                                        Pathname targetFilename , const ByteCount &expectedFileSize_r) const
994 {
995   if ( !isAttached() ) {
996     INT << "Media not_attached on provideFileCopy(" << srcFilename
997         << "," << targetFilename << ")" << endl;
998     ZYPP_THROW(MediaNotAttachedException(url()));
999   }
1000
1001   getFileCopy( srcFilename, targetFilename, expectedFileSize_r ); // pass to concrete handler
1002   DBG << "provideFileCopy(" << srcFilename << "," << targetFilename  << ")" << endl;
1003 }
1004
1005 void MediaHandler::provideFile(Pathname filename , const ByteCount &expectedFileSize_r) const
1006 {
1007   if ( !isAttached() ) {
1008     INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
1009     ZYPP_THROW(MediaNotAttachedException(url()));
1010   }
1011
1012   getFile( filename, expectedFileSize_r ); // pass to concrete handler
1013   DBG << "provideFile(" << filename << ")" << endl;
1014 }
1015
1016
1017 ///////////////////////////////////////////////////////////////////
1018 //
1019 //
1020 //      METHOD NAME : MediaHandler::provideDir
1021 //      METHOD TYPE : PMError
1022 //
1023 //      DESCRIPTION :
1024 //
1025 void MediaHandler::provideDir( Pathname dirname ) const
1026 {
1027   if ( !isAttached() ) {
1028     INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
1029     ZYPP_THROW(MediaNotAttachedException(url()));
1030   }
1031
1032   getDir( dirname, /*recursive*/false ); // pass to concrete handler
1033   MIL << "provideDir(" << dirname << ")" << endl;
1034 }
1035
1036 ///////////////////////////////////////////////////////////////////
1037 //
1038 //
1039 //      METHOD NAME : MediaHandler::provideDirTree
1040 //      METHOD TYPE : PMError
1041 //
1042 //      DESCRIPTION :
1043 //
1044 void MediaHandler::provideDirTree( Pathname dirname ) const
1045 {
1046   if ( !isAttached() ) {
1047     INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
1048     ZYPP_THROW(MediaNotAttachedException(url()));
1049   }
1050
1051   getDir( dirname, /*recursive*/true ); // pass to concrete handler
1052   MIL << "provideDirTree(" << dirname << ")" << endl;
1053 }
1054
1055 ///////////////////////////////////////////////////////////////////
1056 //
1057 //
1058 //      METHOD NAME : MediaHandler::releasePath
1059 //      METHOD TYPE : PMError
1060 //
1061 //      DESCRIPTION :
1062 //
1063 void MediaHandler::releasePath( Pathname pathname ) const
1064 {
1065   if ( ! _does_download || _attachPoint->empty() )
1066     return;
1067
1068   PathInfo info( localPath( pathname ) );
1069
1070   if ( info.isFile() ) {
1071     unlink( info.path() );
1072   } else if ( info.isDir() ) {
1073     if ( info.path() != localRoot() ) {
1074       recursive_rmdir( info.path() );
1075     } else {
1076       clean_dir( info.path() );
1077     }
1078   }
1079 }
1080
1081 ///////////////////////////////////////////////////////////////////
1082 //
1083 //
1084 //      METHOD NAME : MediaHandler::dirInfo
1085 //      METHOD TYPE : PMError
1086 //
1087 //      DESCRIPTION :
1088 //
1089 void MediaHandler::dirInfo( std::list<std::string> & retlist,
1090                             const Pathname & dirname, bool dots ) const
1091 {
1092   retlist.clear();
1093
1094   if ( !isAttached() ) {
1095     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
1096     ZYPP_THROW(MediaNotAttachedException(url()));
1097   }
1098
1099   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
1100   MIL << "dirInfo(" << dirname << ")" << endl;
1101 }
1102
1103 ///////////////////////////////////////////////////////////////////
1104 //
1105 //
1106 //      METHOD NAME : MediaHandler::dirInfo
1107 //      METHOD TYPE : PMError
1108 //
1109 //      DESCRIPTION :
1110 //
1111 void MediaHandler::dirInfo( filesystem::DirContent & retlist,
1112                             const Pathname & dirname, bool dots ) const
1113 {
1114   retlist.clear();
1115
1116   if ( !isAttached() ) {
1117     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
1118     ZYPP_THROW(MediaNotAttachedException(url()));
1119   }
1120
1121   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
1122   MIL << "dirInfo(" << dirname << ")" << endl;
1123 }
1124
1125 ///////////////////////////////////////////////////////////////////
1126 //
1127 //
1128 //      METHOD NAME : MediaHandler::doesFileExist
1129 //      METHOD TYPE : PMError
1130 //
1131 //      DESCRIPTION :
1132 //
1133 bool MediaHandler::doesFileExist( const Pathname & filename ) const
1134 {
1135   // TODO do some logging
1136   if ( !isAttached() ) {
1137     INT << "Error Not attached on doesFileExist(" << filename << ")" << endl;
1138     ZYPP_THROW(MediaNotAttachedException(url()));
1139   }
1140   return getDoesFileExist( filename );
1141   MIL << "doesFileExist(" << filename << ")" << endl;
1142 }
1143
1144 ///////////////////////////////////////////////////////////////////
1145 //
1146 //
1147 //      METHOD NAME : MediaHandler::getDirectoryYast
1148 //      METHOD TYPE : PMError
1149 //
1150 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
1151                                         const Pathname & dirname, bool dots ) const
1152 {
1153   retlist.clear();
1154
1155   filesystem::DirContent content;
1156   getDirectoryYast( content, dirname, dots );
1157
1158   // convert to std::list<std::string>
1159   for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
1160     retlist.push_back( it->name );
1161   }
1162 }
1163
1164 ///////////////////////////////////////////////////////////////////
1165 //
1166 //
1167 //      METHOD NAME : MediaHandler::getDirectoryYast
1168 //      METHOD TYPE : PMError
1169 //
1170 void MediaHandler::getDirectoryYast( filesystem::DirContent & retlist,
1171                                      const Pathname & dirname, bool dots ) const
1172 {
1173   retlist.clear();
1174
1175   // look for directory.yast
1176   Pathname dirFile = dirname + "directory.yast";
1177   getFile( dirFile, 0 );
1178   DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
1179
1180   // using directory.yast
1181   ifstream dir( localPath( dirFile ).asString().c_str() );
1182   if ( dir.fail() ) {
1183     ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
1184     ZYPP_THROW(MediaSystemException(url(),
1185       "Unable to load '" + localPath( dirFile ).asString() + "'"));
1186   }
1187
1188   string line;
1189   while( getline( dir, line ) ) {
1190     if ( line.empty() ) continue;
1191     if ( line == "directory.yast" ) continue;
1192
1193     // Newer directory.yast append '/' to directory names
1194     // Remaining entries are unspecified, although most probabely files.
1195     filesystem::FileType type = filesystem::FT_NOT_AVAIL;
1196     if ( *line.rbegin() == '/' ) {
1197       line.erase( line.end()-1 );
1198       type = filesystem::FT_DIR;
1199     }
1200
1201     if ( dots ) {
1202       if ( line == "." || line == ".." ) continue;
1203     } else {
1204       if ( *line.begin() == '.' ) continue;
1205     }
1206
1207     retlist.push_back( filesystem::DirEntry( line, type ) );
1208   }
1209 }
1210
1211 /******************************************************************
1212 **
1213 **
1214 **      FUNCTION NAME : operator<<
1215 **      FUNCTION TYPE : ostream &
1216 */
1217 ostream & operator<<( ostream & str, const MediaHandler & obj )
1218 {
1219   str << obj.url() << ( obj.isAttached() ? "" : " not" )
1220     << " attached; localRoot \"" << obj.localRoot() << "\"";
1221   return str;
1222 }
1223
1224 ///////////////////////////////////////////////////////////////////
1225 //
1226 //
1227 //      METHOD NAME : MediaHandler::getFile
1228 //      METHOD TYPE : PMError
1229 //
1230 //      DESCRIPTION : Asserted that media is attached.
1231 //                    Default implementation of pure virtual.
1232 //
1233 void MediaHandler::getFile(const Pathname & filename , const ByteCount &) const
1234 {
1235     PathInfo info( localPath( filename ) );
1236     if( info.isFile() ) {
1237         return;
1238     }
1239
1240     if (info.isExist())
1241       ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
1242     else
1243       ZYPP_THROW(MediaFileNotFoundException(url(), filename));
1244 }
1245
1246
1247 void MediaHandler::getFileCopy (const Pathname & srcFilename, const Pathname & targetFilename , const ByteCount &expectedFileSize_r) const
1248 {
1249   getFile(srcFilename, expectedFileSize_r);
1250
1251   if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
1252     ZYPP_THROW(MediaWriteException(targetFilename));
1253   }
1254 }
1255
1256
1257
1258 ///////////////////////////////////////////////////////////////////
1259 //
1260 //
1261 //      METHOD NAME : MediaHandler::getDir
1262 //      METHOD TYPE : PMError
1263 //
1264 //      DESCRIPTION : Asserted that media is attached.
1265 //                    Default implementation of pure virtual.
1266 //
1267 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
1268 {
1269   PathInfo info( localPath( dirname ) );
1270   if( info.isDir() ) {
1271     return;
1272   }
1273
1274   if (info.isExist())
1275     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1276   else
1277     ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
1278 }
1279
1280 ///////////////////////////////////////////////////////////////////
1281 //
1282 //
1283 //      METHOD NAME : MediaHandler::getDirInfo
1284 //      METHOD TYPE : PMError
1285 //
1286 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
1287 //                    Default implementation of pure virtual.
1288 //
1289 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
1290                                const Pathname & dirname, bool dots ) const
1291 {
1292   PathInfo info( localPath( dirname ) );
1293   if( ! info.isDir() ) {
1294     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1295   }
1296
1297 #if NONREMOTE_DIRECTORY_YAST
1298   // use directory.yast if available
1299   try {
1300     getDirectoryYast( retlist, dirname, dots );
1301   }
1302   catch (const MediaException & excpt_r)
1303   {
1304 #endif
1305
1306     // readdir
1307     int res = readdir( retlist, info.path(), dots );
1308     if ( res )
1309     {
1310       MediaSystemException nexcpt(url(), "readdir failed");
1311 #if NONREMOTE_DIRECTORY_YAST
1312       nexcpt.remember(excpt_r);
1313 #endif
1314       ZYPP_THROW(nexcpt);
1315     }
1316
1317 #if NONREMOTE_DIRECTORY_YAST
1318   }
1319 #endif
1320
1321   return;
1322 }
1323
1324 ///////////////////////////////////////////////////////////////////
1325 //
1326 //
1327 //      METHOD NAME : MediaHandler::getDirInfo
1328 //      METHOD TYPE : PMError
1329 //
1330 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
1331 //                    Default implementation of pure virtual.
1332 //
1333 void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
1334                                const Pathname & dirname, bool dots ) const
1335 {
1336   PathInfo info( localPath( dirname ) );
1337   if( ! info.isDir() ) {
1338     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1339   }
1340
1341 #if NONREMOTE_DIRECTORY_YAST
1342   // use directory.yast if available
1343   try {
1344     getDirectoryYast( retlist, dirname, dots );
1345   }
1346   catch (const MediaException & excpt_r)
1347   {
1348 #endif
1349
1350     // readdir
1351     int res = readdir( retlist, info.path(), dots );
1352     if ( res )
1353     {
1354         MediaSystemException nexcpt(url(), "readdir failed");
1355 #if NONREMOTE_DIRECTORY_YAST
1356         nexcpt.remember(excpt_r);
1357 #endif
1358         ZYPP_THROW(nexcpt);
1359     }
1360 #if NONREMOTE_DIRECTORY_YAST
1361   }
1362 #endif
1363 }
1364
1365 ///////////////////////////////////////////////////////////////////
1366 //
1367 //
1368 //      METHOD NAME : MediaHandler::getDoesFileExist
1369 //      METHOD TYPE : PMError
1370 //
1371 //      DESCRIPTION : Asserted that file is not a directory
1372 //                    Default implementation of pure virtual.
1373 //
1374 bool MediaHandler::getDoesFileExist( const Pathname & filename ) const
1375 {
1376   PathInfo info( localPath( filename ) );
1377   if( info.isDir() ) {
1378     ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
1379   }
1380   return info.isExist();
1381 }
1382
1383 bool MediaHandler::hasMoreDevices()
1384 {
1385   return false;
1386 }
1387
1388 void MediaHandler::getDetectedDevices(std::vector<std::string> & devices,
1389                                       unsigned int & index) const
1390 {
1391   // clear the vector by default
1392   if (!devices.empty())
1393     devices.clear();
1394   index = 0;
1395
1396   DBG << "No devices for this medium" << endl;
1397 }
1398
1399 void MediaHandler::setDeltafile( const Pathname & filename ) const
1400 {
1401   _deltafile = filename;
1402 }
1403
1404 Pathname MediaHandler::deltafile() const {
1405   return _deltafile;
1406 }
1407
1408   } // namespace media
1409 } // namespace zypp
1410 // vim: set ts=8 sts=2 sw=2 ai noet: