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