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