libzypp  10.5.0
MediaHandler.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <iostream>
00014 #include <fstream>
00015 #include <sstream>
00016 
00017 #include "zypp/TmpPath.h"
00018 #include "zypp/Date.h"
00019 #include "zypp/base/LogTools.h"
00020 #include "zypp/base/String.h"
00021 #include "zypp/media/MediaHandler.h"
00022 #include "zypp/media/MediaManager.h"
00023 #include "zypp/media/Mount.h"
00024 #include <limits.h>
00025 #include <stdlib.h>
00026 #include <errno.h>
00027 
00028 
00029 using namespace std;
00030 
00031 // use directory.yast on every media (not just via ftp/http)
00032 #define NONREMOTE_DIRECTORY_YAST 1
00033 
00034 namespace zypp {
00035   namespace media {
00036 
00037   Pathname MediaHandler::_attachPrefix("");
00038 
00040 //
00041 //      CLASS NAME : MediaHandler
00042 //
00044 
00046 //
00047 //
00048 //      METHOD NAME : MediaHandler::MediaHandler
00049 //      METHOD TYPE : Constructor
00050 //
00051 //      DESCRIPTION :
00052 //
00053 MediaHandler::MediaHandler ( const Url &      url_r,
00054                              const Pathname & attach_point_r,
00055                              const Pathname & urlpath_below_attachpoint_r,
00056                              const bool       does_download_r )
00057     : _mediaSource()
00058     , _attachPoint( new AttachPoint())
00059     , _AttachPointHint()
00060     , _relativeRoot( urlpath_below_attachpoint_r)
00061     , _does_download( does_download_r )
00062     , _attach_mtime(0)
00063     , _url( url_r )
00064     , _parentId(0)
00065 {
00066   Pathname real_attach_point( getRealPath(attach_point_r.asString()));
00067 
00068   if ( !real_attach_point.empty() ) {
00070     // check if provided attachpoint is usable.
00072 
00073     PathInfo adir( real_attach_point );
00074     //
00075     // The verify if attach_point_r isn't a mountpoint of another
00076     // device is done in the particular media handler (if needed).
00077     //
00078     // We just verify, if attach_point_r is a directory and for
00079     // schemes other than "file" and "dir", if it is absolute.
00080     //
00081     if ( !adir.isDir()
00082          || (_url.getScheme() != "file"
00083              && _url.getScheme() != "dir"
00084              && !real_attach_point.absolute()) )
00085     {
00086       ERR << "Provided attach point is not a absolute directory: "
00087           << adir << endl;
00088     }
00089     else {
00090       attachPointHint( real_attach_point, false);
00091       setAttachPoint( real_attach_point, false);
00092     }
00093   }
00094 }
00095 
00097 //
00098 //
00099 //      METHOD NAME : MediaHandler::~MediaHandler
00100 //      METHOD TYPE : Destructor
00101 //
00102 //      DESCRIPTION :
00103 //
00104 MediaHandler::~MediaHandler()
00105 {
00106   try
00107     {
00108       removeAttachPoint();
00109     }
00110   catch(...) {}
00111 }
00112 
00113 void
00114 MediaHandler::resetParentId()
00115 {
00116   _parentId = 0;
00117 }
00118 
00119 std::string
00120 MediaHandler::getRealPath(const std::string &path)
00121 {
00122   std::string real;
00123   if( !path.empty())
00124   {
00125 #if __GNUC__ > 2
00126 
00127     char *ptr = ::realpath(path.c_str(), NULL);
00128     if( ptr != NULL)
00129     {
00130       real = ptr;
00131       free( ptr);
00132     }
00133     else
00135     if( EINVAL == errno)
00136     {
00137       char buff[PATH_MAX + 2];
00138       memset(buff, '\0', sizeof(buff));
00139       if( ::realpath(path.c_str(), buff) != NULL)
00140       {
00141         real = buff;
00142       }
00143     }
00144 #else
00145     char buff[PATH_MAX + 2];
00146     memset(buff, '\0', sizeof(buff));
00147     if( ::realpath(path.c_str(), buff) != NULL)
00148     {
00149       real = buff;
00150     }
00151 #endif
00152   }
00153   return real;
00154 }
00155 
00156 zypp::Pathname
00157 MediaHandler::getRealPath(const Pathname &path)
00158 {
00159   return zypp::Pathname(getRealPath(path.asString()));
00160 }
00161 
00162 
00164 //
00165 //
00166 //      METHOD NAME : MediaHandler::removeAttachPoint
00167 //      METHOD TYPE : void
00168 //
00169 //      DESCRIPTION :
00170 //
00171 void
00172 MediaHandler::removeAttachPoint()
00173 {
00174   if ( _mediaSource ) {
00175     INT << "MediaHandler deleted with media attached." << endl;
00176     return; // no cleanup if media still mounted!
00177   }
00178 
00179   DBG << "MediaHandler - checking if to remove attach point" << endl;
00180   if ( _attachPoint.unique() &&
00181        _attachPoint->temp    &&
00182        !_attachPoint->path.empty() &&
00183        PathInfo(_attachPoint->path).isDir())
00184   {
00185     Pathname path(_attachPoint->path);
00186 
00187     setAttachPoint("", true);
00188 
00189     int res = recursive_rmdir( path );
00190     if ( res == 0 ) {
00191       MIL << "Deleted default attach point " << path << endl;
00192     } else {
00193       ERR << "Failed to Delete default attach point " << path
00194         << " errno(" << res << ")" << endl;
00195     }
00196   }
00197   else
00198   {
00199     if( !_attachPoint->path.empty() && !_attachPoint->temp)
00200       DBG << "MediaHandler - attachpoint is not temporary" << endl;
00201   }
00202 }
00203 
00204 
00206 //
00207 //
00208 //      METHOD NAME : MediaHandler::attachPoint
00209 //      METHOD TYPE : Pathname
00210 //
00211 //      DESCRIPTION :
00212 //
00213 Pathname
00214 MediaHandler::attachPoint() const
00215 {
00216   return _attachPoint->path;
00217 }
00218 
00219 
00221 //
00222 //
00223 //      METHOD NAME : MediaHandler::attachPoint
00224 //      METHOD TYPE :
00225 //
00226 //      DESCRIPTION :
00227 //
00228 void
00229 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
00230 {
00231   _attachPoint.reset( new AttachPoint(path, temporary));
00232 }
00233 
00234 Pathname
00235 MediaHandler::localRoot() const
00236 {
00237   if( _attachPoint->path.empty())
00238     return Pathname();
00239   else
00240     return _attachPoint->path + _relativeRoot;
00241 }
00242 
00244 //
00245 //
00246 //      METHOD NAME : MediaHandler::attachPoint
00247 //      METHOD TYPE :
00248 //
00249 //      DESCRIPTION :
00250 //
00251 void
00252 MediaHandler::setAttachPoint(const AttachPointRef &ref)
00253 {
00254   if( ref)
00255     AttachPointRef(ref).swap(_attachPoint);
00256   else
00257     _attachPoint.reset( new AttachPoint());
00258 }
00259 
00261 //
00262 //
00263 //      METHOD NAME : MediaHandler::attachPointHint
00264 //      METHOD TYPE : void
00265 //
00266 //      DESCRIPTION :
00267 //
00268 void
00269 MediaHandler::attachPointHint(const Pathname &path, bool temporary)
00270 {
00271   _AttachPointHint.path = path;
00272   _AttachPointHint.temp = temporary;
00273 }
00274 
00276 //
00277 //
00278 //      METHOD NAME : MediaHandler::attachPointHint
00279 //      METHOD TYPE : AttachPoint
00280 //
00281 //      DESCRIPTION :
00282 //
00283 AttachPoint
00284 MediaHandler::attachPointHint() const
00285 {
00286   return _AttachPointHint;
00287 }
00288 
00290 //
00291 //
00292 //      METHOD NAME : MediaHandler::findAttachedMedia
00293 //      METHOD TYPE : AttachedMedia
00294 //
00295 //      DESCRIPTION :
00296 //
00297 AttachedMedia
00298 MediaHandler::findAttachedMedia(const MediaSourceRef &media) const
00299 {
00300         return MediaManager().findAttachedMedia(media);
00301 }
00302 
00304 //
00305 //
00306 //      METHOD NAME : MediaHandler::setAttachPrefix
00307 //      METHOD TYPE : void
00308 //
00309 //      DESCRIPTION :
00310 //
00311 bool
00312 MediaHandler::setAttachPrefix(const Pathname &attach_prefix)
00313 {
00314   if( attach_prefix.empty())
00315   {
00316     MIL << "Reseting to built-in attach point prefixes."
00317         << std::endl;
00318     MediaHandler::_attachPrefix = attach_prefix;
00319     return true;
00320   }
00321   else
00322   if( MediaHandler::checkAttachPoint(attach_prefix, false, true))
00323   {
00324     MIL << "Setting user defined attach point prefix: "
00325         << attach_prefix << std::endl;
00326     MediaHandler::_attachPrefix = attach_prefix;
00327     return true;
00328   }
00329   return false;
00330 }
00331 
00333 //
00334 //
00335 //      METHOD NAME : MediaHandler::attach
00336 //      METHOD TYPE : Pathname
00337 //
00338 //      DESCRIPTION :
00339 //
00340 Pathname
00341 MediaHandler::createAttachPoint() const
00342 {
00344   // provide a default (temporary) attachpoint
00346   const char * defmounts[] = {
00347       "/var/adm/mount", filesystem::TmpPath::defaultLocation().c_str(), NULL
00348   };
00349 
00350   Pathname apoint;
00351   Pathname aroot( MediaHandler::_attachPrefix);
00352 
00353   if( !aroot.empty())
00354   {
00355     apoint = createAttachPoint(aroot);
00356   }
00357   for ( const char ** def = defmounts; *def && apoint.empty(); ++def ) {
00358     aroot = *def;
00359     if( aroot.empty())
00360       continue;
00361 
00362     apoint = createAttachPoint(aroot);
00363   }
00364 
00365   if ( aroot.empty() ) {
00366     ERR << "Create attach point: Can't find a writable directory to create an attach point" << std::endl;
00367     return aroot;
00368   }
00369 
00370   if ( !apoint.empty() ) {
00371     MIL << "Created default attach point " << apoint << std::endl;
00372   }
00373   return apoint;
00374 }
00375 
00376 Pathname
00377 MediaHandler::createAttachPoint(const Pathname &attach_root) const
00378 {
00379   Pathname apoint;
00380 
00381   if( attach_root.empty() || !attach_root.absolute()) {
00382     ERR << "Create attach point: invalid attach root: '"
00383         << attach_root << "'" << std::endl;
00384     return apoint;
00385   }
00386 
00387   PathInfo adir( attach_root );
00388   if( !adir.isDir() || (getuid() != 0 && !adir.userMayRWX())) {
00389     DBG << "Create attach point: attach root is not a writable directory: '"
00390         << attach_root << "'" << std::endl;
00391     return apoint;
00392   }
00393 
00394   static bool cleanup_once( true );
00395   if ( cleanup_once )
00396   {
00397     cleanup_once = false;
00398     DBG << "Look for orphaned attach points in " << adir << std::endl;
00399     std::list<std::string> entries;
00400     filesystem::readdir( entries, attach_root, false );
00401     for_each_( it, entries )
00402     {
00403       const std::string & entry( *it );
00404 
00405       if ( ! str::hasPrefix( entry, "AP_0x" ) )
00406         continue;
00407       PathInfo sdir( attach_root + entry );
00408       if ( sdir.isDir()
00409         && sdir.dev() == adir.dev()
00410         && ( Date::now()-sdir.mtime() > Date::month ) )
00411       {
00412         DBG << "Remove orphaned attach point " << sdir << std::endl;
00413         filesystem::recursive_rmdir( sdir.path() );
00414       }
00415     }
00416   }
00417 
00418   filesystem::TmpDir tmpdir( attach_root, "AP_0x" );
00419   if ( tmpdir )
00420   {
00421     apoint = getRealPath( tmpdir.path().asString() );
00422     if ( ! apoint.empty() )
00423     {
00424       tmpdir.autoCleanup( false );      // Take responsibility for cleanup.
00425     }
00426     else
00427     {
00428       ERR << "Unable to resolve real path for attach point " << tmpdir << std::endl;
00429     }
00430   }
00431   else
00432   {
00433     ERR << "Unable to create attach point below " << attach_root << std::endl;
00434   }
00435   return apoint;
00436 }
00437 
00439 //
00440 //
00441 //      METHOD NAME : MediaHandler::isUseableAttachPoint
00442 //      METHOD TYPE : bool
00443 //
00444 //      DESCRIPTION :
00445 //
00446 bool
00447 MediaHandler::isUseableAttachPoint(const Pathname &path, bool mtab) const
00448 {
00449   MediaManager  manager;
00450   return manager.isUseableAttachPoint(path, mtab);
00451 }
00452 
00453 
00455 //
00456 //
00457 //      METHOD NAME : MediaHandler::setMediaSource
00458 //      METHOD TYPE : void
00459 //
00460 //      DESCRIPTION :
00461 //
00462 void
00463 MediaHandler::setMediaSource(const MediaSourceRef &ref)
00464 {
00465   _mediaSource.reset();
00466   if( ref && !ref->type.empty() && !ref->name.empty())
00467     _mediaSource = ref;
00468 }
00469 
00471 //
00472 //
00473 //      METHOD NAME : MediaHandler::attachedMedia
00474 //      METHOD TYPE : AttachedMedia
00475 //
00476 //      DESCRIPTION :
00477 //
00478 AttachedMedia
00479 MediaHandler::attachedMedia() const
00480 {
00481   if ( _mediaSource && _attachPoint)
00482     return AttachedMedia(_mediaSource, _attachPoint);
00483   else
00484     return AttachedMedia();
00485 }
00486 
00488 //
00489 //
00490 //      METHOD NAME : MediaHandler::isSharedMedia
00491 //      METHOD TYPE : bool
00492 //
00493 //      DESCRIPTION :
00494 //
00495 bool
00496 MediaHandler::isSharedMedia() const
00497 {
00498   return !_mediaSource.unique();
00499 }
00500 
00502 //
00503 //
00504 //      METHOD NAME : MediaHandler::checkAttached
00505 //      METHOD TYPE : bool
00506 //
00507 //      DESCRIPTION :
00508 //
00509 bool
00510 MediaHandler::checkAttached(bool matchMountFs) const
00511 {
00512   bool _isAttached = false;
00513 
00514   AttachedMedia ref( attachedMedia());
00515   if( ref.mediaSource )
00516   {
00517     time_t old_mtime = _attach_mtime;
00518     _attach_mtime = MediaManager::getMountTableMTime();
00519     if( !(old_mtime <= 0 || _attach_mtime != old_mtime) )
00520     {
00521       // OK, skip the check (we've seen it at least once)
00522       _isAttached = true;
00523     }
00524     else
00525     {
00526       if( old_mtime > 0)
00527         DBG << "Mount table changed - rereading it" << std::endl;
00528       else
00529         DBG << "Forced check of the mount table" << std::endl;
00530 
00531       MountEntries entries( MediaManager::getMountEntries());
00532       for_( e, entries.begin(), entries.end() )
00533       {
00534         bool        is_device = false;
00535         PathInfo    dev_info;
00536 
00537         if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
00538             dev_info(e->src) && dev_info.isBlk())
00539         {
00540           is_device = true;
00541         }
00542 
00543         if( is_device &&  (ref.mediaSource->maj_nr &&
00544                            ref.mediaSource->bdir.empty()))
00545         {
00546           std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
00547           MediaSource media(mtype, e->src, dev_info.major(), dev_info.minor());
00548 
00549           if( ref.mediaSource->equals( media) &&
00550               ref.attachPoint->path == Pathname(e->dir))
00551           {
00552             DBG << "Found media device "
00553                 << ref.mediaSource->asString()
00554                 << " in the mount table as " << e->src << std::endl;
00555             _isAttached = true;
00556             break;
00557           }
00558           // differs
00559         }
00560         else
00561         if(!is_device && (!ref.mediaSource->maj_nr ||
00562                           !ref.mediaSource->bdir.empty()))
00563         {
00564           if( ref.mediaSource->bdir.empty())
00565           {
00566             // bnc#710269: Type nfs may appear as nfs4 in in the mount table
00567             // and maybe vice versa. Similar cifs/smb. Need to unify these types:
00568             if ( matchMountFs && e->type != ref.mediaSource->type )
00569             {
00570               if ( str::hasPrefix( e->type, "nfs" ) && str::hasPrefix( ref.mediaSource->type, "nfs" ) )
00571                 matchMountFs = false;
00572               else if ( ( e->type == "cifs" || e->type == "smb" ) && ( ref.mediaSource->type == "cifs" || ref.mediaSource->type == "smb" ) )
00573                 matchMountFs = false;
00574             }
00575             std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
00576             MediaSource media(mtype, e->src);
00577 
00578             if( ref.mediaSource->equals( media) &&
00579                 ref.attachPoint->path == Pathname(e->dir))
00580             {
00581               DBG << "Found media name "
00582                   << ref.mediaSource->asString()
00583                   << " in the mount table as " << e->src << std::endl;
00584               _isAttached = true;
00585               break;
00586             }
00587           }
00588           else
00589           {
00590             if(ref.mediaSource->bdir == e->src &&
00591                ref.attachPoint->path == Pathname(e->dir))
00592             {
00593               DBG << "Found bound media "
00594                   << ref.mediaSource->asString()
00595                   << " in the mount table as " << e->src << std::endl;
00596               _isAttached = true;
00597               break;
00598             }
00599           }
00600           // differs
00601         }
00602       }
00603 
00604       if( !_isAttached)
00605       {
00606         MIL << "Looking for " << ref << endl;
00607         if( entries.empty() )
00608         {
00609           ERR << "Unable to find any entry in the /etc/mtab file" << std::endl;
00610         }
00611         else
00612         {
00613           dumpRange( DBG << "MountEntries: ", entries.begin(), entries.end() ) << endl;
00614         }
00615         if( old_mtime > 0 )
00616         {
00617           ERR << "Attached media not in mount table any more - forcing reset!"
00618               << std::endl;
00619 
00620           _mediaSource.reset();
00621         }
00622         else
00623         {
00624           WAR << "Attached media not in mount table ..." << std::endl;
00625         }
00626 
00627         // reset the mtime and force a new check to make sure,
00628         // that we've found the media at least once in the mtab.
00629         _attach_mtime = 0;
00630       }
00631     }
00632   }
00633   return _isAttached;
00634 }
00635 
00637 //
00638 //
00639 //      METHOD NAME : MediaHandler::attach
00640 //      METHOD TYPE : PMError
00641 //
00642 //      DESCRIPTION :
00643 //
00644 void MediaHandler::attach( bool next )
00645 {
00646   if ( isAttached() )
00647     return;
00648 
00649   // reset it in case of overloaded isAttached()
00650   // that checks the media against /etc/mtab ...
00651   setMediaSource(MediaSourceRef());
00652 
00653   AttachPoint ap( attachPointHint());
00654   setAttachPoint(ap.path, ap.temp);
00655 
00656   try
00657   {
00658     attachTo( next ); // pass to concrete handler
00659   }
00660   catch(const MediaException &e)
00661   {
00662     removeAttachPoint();
00663     ZYPP_RETHROW(e);
00664   }
00665   MIL << "Attached: " << *this << endl;
00666 }
00667 
00668 
00670 //
00671 //
00672 //      METHOD NAME : MediaHandler::localPath
00673 //      METHOD TYPE : Pathname
00674 //
00675 Pathname MediaHandler::localPath( const Pathname & pathname ) const
00676 {
00677     Pathname _localRoot( localRoot());
00678     if ( _localRoot.empty() )
00679         return _localRoot;
00680 
00681     // we must check maximum file name length
00682     // this is important for fetching the suseservers, the
00683     // url with all parameters can get too long (bug #42021)
00684 
00685     return _localRoot + pathname.absolutename();
00686 }
00687 
00688 
00689 
00690 
00691 
00693 //
00694 //
00695 //      METHOD NAME : MediaHandler::disconnect
00696 //      METHOD TYPE : PMError
00697 //
00698 void MediaHandler::disconnect()
00699 {
00700   if ( !isAttached() )
00701     return;
00702 
00703   disconnectFrom(); // pass to concrete handler
00704   MIL << "Disconnected: " << *this << endl;
00705 }
00706 
00708 //
00709 //
00710 //      METHOD NAME : MediaHandler::release
00711 //      METHOD TYPE : PMError
00712 //
00713 //      DESCRIPTION :
00714 //
00715 void MediaHandler::release( const std::string & ejectDev )
00716 {
00717   if ( !isAttached() ) {
00718     DBG << "Request to release media - not attached; eject '" << ejectDev << "'"
00719         << std::endl;
00720     if ( !ejectDev.empty() )
00721       forceEject(ejectDev);
00722     return;
00723   }
00724 
00725   DBG << "Request to release attached media "
00726       << _mediaSource->asString()
00727       << ", use count=" << _mediaSource.use_count()
00728       << std::endl;
00729 
00730   if( _mediaSource.unique())
00731   {
00732     DBG << "Releasing media " << _mediaSource->asString() << std::endl;
00733     try {
00734       releaseFrom( ejectDev ); // pass to concrete handler
00735     }
00736     catch(const MediaNotEjectedException &e)
00737     {
00738       // not ejected because the media
00739       // is mounted by somebody else
00740       // (if our attach point is busy,
00741       //  we get an umount exception)
00742       _mediaSource.reset(NULL);
00743       removeAttachPoint();
00744       // OK, retrow now
00745       ZYPP_RETHROW(e);
00746     }
00747     _mediaSource.reset(NULL);
00748     removeAttachPoint();
00749   }
00750   else if( !ejectDev.empty() ) {
00751     //
00752     // Can't eject a shared media
00753     //
00754     //ZYPP_THROW(MediaIsSharedException(_mediaSource->asString()));
00755 
00756     MediaSourceRef media( new MediaSource(*_mediaSource));
00757     _mediaSource.reset(NULL);
00758 
00759     MediaManager manager;
00760     manager.forceReleaseShared(media);
00761 
00762     setMediaSource(media);
00763     DBG << "Releasing media (forced) " << _mediaSource->asString() << std::endl;
00764     try {
00765       releaseFrom( ejectDev ); // pass to concrete handler
00766     }
00767     catch(const MediaNotEjectedException &e)
00768     {
00769       // not ejected because the media
00770       // is mounted by somebody else
00771       // (if our attach point is busy,
00772       //  we get an umount exception)
00773       _mediaSource.reset(NULL);
00774       removeAttachPoint();
00775       // OK, retrow now
00776       ZYPP_RETHROW(e);
00777     }
00778     _mediaSource.reset(NULL);
00779     removeAttachPoint();
00780   }
00781   else {
00782     DBG << "Releasing shared media reference only" << std::endl;
00783     _mediaSource.reset(NULL);
00784     setAttachPoint("", true);
00785   }
00786   MIL << "Released: " << *this << endl;
00787 }
00788 
00789 void MediaHandler::forceRelaseAllMedia(bool matchMountFs)
00790 {
00791   forceRelaseAllMedia( attachedMedia().mediaSource, matchMountFs);
00792 }
00793 
00794 void MediaHandler::forceRelaseAllMedia(const MediaSourceRef &ref,
00795                                        bool                  matchMountFs)
00796 {
00797   if( !ref)
00798     return;
00799 
00800   MountEntries  entries( MediaManager::getMountEntries());
00801   MountEntries::const_iterator e;
00802   for( e = entries.begin(); e != entries.end(); ++e)
00803   {
00804     bool        is_device = false;
00805     PathInfo    dev_info;
00806 
00807     if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
00808         dev_info(e->src) && dev_info.isBlk())
00809     {
00810       is_device = true;
00811     }
00812 
00813     if( is_device &&  ref->maj_nr)
00814     {
00815       std::string mtype(matchMountFs ? e->type : ref->type);
00816       MediaSource media(mtype, e->src, dev_info.major(), dev_info.minor());
00817 
00818       if( ref->equals( media) && e->type != "subfs")
00819       {
00820         DBG << "Forcing release of media device "
00821             << ref->asString()
00822             << " in the mount table as "
00823             << e->src << std::endl;
00824         try {
00825           Mount mount;
00826           mount.umount(e->dir);
00827         }
00828         catch (const Exception &e)
00829         {
00830           ZYPP_CAUGHT(e);
00831         }
00832       }
00833     }
00834     else
00835     if(!is_device && !ref->maj_nr)
00836     {
00837       std::string mtype(matchMountFs ? e->type : ref->type);
00838       MediaSource media(mtype, e->src);
00839       if( ref->equals( media))
00840       {
00841         DBG << "Forcing release of media name "
00842             << ref->asString()
00843             << " in the mount table as "
00844             << e->src << std::endl;
00845         try {
00846           Mount mount;
00847           mount.umount(e->dir);
00848         }
00849         catch (const Exception &e)
00850         {
00851           ZYPP_CAUGHT(e);
00852         }
00853       }
00854     }
00855   }
00856 }
00857 
00858 bool
00859 MediaHandler::checkAttachPoint(const Pathname &apoint) const
00860 {
00861   return MediaHandler::checkAttachPoint( apoint, true, false);
00862 }
00863 
00864 // STATIC
00865 bool
00866 MediaHandler::checkAttachPoint(const Pathname &apoint,
00867                                bool            emptydir,
00868                                bool            writeable)
00869 {
00870   if( apoint.empty() || !apoint.absolute())
00871   {
00872     ERR << "Attach point '" << apoint << "' is not absolute"
00873         << std::endl;
00874     return false;
00875   }
00876   if( apoint == "/")
00877   {
00878     ERR << "Attach point '" << apoint << "' is not allowed"
00879         << std::endl;
00880     return false;
00881   }
00882 
00883   PathInfo ainfo(apoint);
00884   if( !ainfo.isDir())
00885   {
00886     ERR << "Attach point '" << apoint << "' is not a directory"
00887         << std::endl;
00888     return false;
00889   }
00890 
00891   if( emptydir)
00892   {
00893     if( 0 != zypp::filesystem::is_empty_dir(apoint))
00894     {
00895       ERR << "Attach point '" << apoint << "' is not a empty directory"
00896           << std::endl;
00897       return false;
00898     }
00899   }
00900 
00901   if( writeable)
00902   {
00903     Pathname apath(apoint + "XXXXXX");
00904     char    *atemp = ::strdup( apath.asString().c_str());
00905     char    *atest = NULL;
00906     if( !ainfo.userMayRWX() || atemp == NULL ||
00907         (atest=::mkdtemp(atemp)) == NULL)
00908     {
00909       if( atemp != NULL)
00910         ::free(atemp);
00911 
00912       ERR << "Attach point '" << ainfo.path()
00913           << "' is not a writeable directory" << std::endl;
00914       return false;
00915     }
00916     else if( atest != NULL)
00917       ::rmdir(atest);
00918 
00919     if( atemp != NULL)
00920       ::free(atemp);
00921   }
00922   return true;
00923 }
00924 
00926 //
00927 //      METHOD NAME : MediaHandler::dependsOnParent
00928 //      METHOD TYPE : bool
00929 //
00930 //      DESCRIPTION :
00931 //
00932 bool
00933 MediaHandler::dependsOnParent()
00934 {
00935   return _parentId != 0;
00936 }
00937 
00938 bool
00939 MediaHandler::dependsOnParent(MediaAccessId parentId, bool exactIdMatch)
00940 {
00941   if( _parentId != 0)
00942   {
00943     if(parentId == _parentId)
00944       return true;
00945 
00946     if( !exactIdMatch)
00947     {
00948       MediaManager mm;
00949       AttachedMedia am1 = mm.getAttachedMedia(_parentId);
00950       AttachedMedia am2 = mm.getAttachedMedia(parentId);
00951       if( am1.mediaSource && am2.mediaSource)
00952       {
00953         return am1.mediaSource->equals( *(am2.mediaSource));
00954       }
00955     }
00956   }
00957   return false;
00958 }
00959 
00961 //
00962 //
00963 //      METHOD NAME : MediaHandler::provideFile
00964 //      METHOD TYPE : PMError
00965 //
00966 //      DESCRIPTION :
00967 //
00968 void MediaHandler::provideFileCopy( Pathname srcFilename,
00969                                        Pathname targetFilename ) const
00970 {
00971   if ( !isAttached() ) {
00972     INT << "Media not_attached on provideFileCopy(" << srcFilename
00973         << "," << targetFilename << ")" << endl;
00974     ZYPP_THROW(MediaNotAttachedException(url()));
00975   }
00976 
00977   getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
00978   DBG << "provideFileCopy(" << srcFilename << "," << targetFilename  << ")" << endl;
00979 }
00980 
00981 void MediaHandler::provideFile( Pathname filename ) const
00982 {
00983   if ( !isAttached() ) {
00984     INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
00985     ZYPP_THROW(MediaNotAttachedException(url()));
00986   }
00987 
00988   getFile( filename ); // pass to concrete handler
00989   DBG << "provideFile(" << filename << ")" << endl;
00990 }
00991 
00992 
00994 //
00995 //
00996 //      METHOD NAME : MediaHandler::provideDir
00997 //      METHOD TYPE : PMError
00998 //
00999 //      DESCRIPTION :
01000 //
01001 void MediaHandler::provideDir( Pathname dirname ) const
01002 {
01003   if ( !isAttached() ) {
01004     INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
01005     ZYPP_THROW(MediaNotAttachedException(url()));
01006   }
01007 
01008   getDir( dirname, /*recursive*/false ); // pass to concrete handler
01009   MIL << "provideDir(" << dirname << ")" << endl;
01010 }
01011 
01013 //
01014 //
01015 //      METHOD NAME : MediaHandler::provideDirTree
01016 //      METHOD TYPE : PMError
01017 //
01018 //      DESCRIPTION :
01019 //
01020 void MediaHandler::provideDirTree( Pathname dirname ) const
01021 {
01022   if ( !isAttached() ) {
01023     INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
01024     ZYPP_THROW(MediaNotAttachedException(url()));
01025   }
01026 
01027   getDir( dirname, /*recursive*/true ); // pass to concrete handler
01028   MIL << "provideDirTree(" << dirname << ")" << endl;
01029 }
01030 
01032 //
01033 //
01034 //      METHOD NAME : MediaHandler::releasePath
01035 //      METHOD TYPE : PMError
01036 //
01037 //      DESCRIPTION :
01038 //
01039 void MediaHandler::releasePath( Pathname pathname ) const
01040 {
01041   if ( ! _does_download || _attachPoint->empty() )
01042     return;
01043 
01044   PathInfo info( localPath( pathname ) );
01045 
01046   if ( info.isFile() ) {
01047     unlink( info.path() );
01048   } else if ( info.isDir() ) {
01049     if ( info.path() != localRoot() ) {
01050       recursive_rmdir( info.path() );
01051     } else {
01052       clean_dir( info.path() );
01053     }
01054   }
01055 }
01056 
01058 //
01059 //
01060 //      METHOD NAME : MediaHandler::dirInfo
01061 //      METHOD TYPE : PMError
01062 //
01063 //      DESCRIPTION :
01064 //
01065 void MediaHandler::dirInfo( std::list<std::string> & retlist,
01066                             const Pathname & dirname, bool dots ) const
01067 {
01068   retlist.clear();
01069 
01070   if ( !isAttached() ) {
01071     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
01072     ZYPP_THROW(MediaNotAttachedException(url()));
01073   }
01074 
01075   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
01076   MIL << "dirInfo(" << dirname << ")" << endl;
01077 }
01078 
01080 //
01081 //
01082 //      METHOD NAME : MediaHandler::dirInfo
01083 //      METHOD TYPE : PMError
01084 //
01085 //      DESCRIPTION :
01086 //
01087 void MediaHandler::dirInfo( filesystem::DirContent & retlist,
01088                             const Pathname & dirname, bool dots ) const
01089 {
01090   retlist.clear();
01091 
01092   if ( !isAttached() ) {
01093     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
01094     ZYPP_THROW(MediaNotAttachedException(url()));
01095   }
01096 
01097   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
01098   MIL << "dirInfo(" << dirname << ")" << endl;
01099 }
01100 
01102 //
01103 //
01104 //      METHOD NAME : MediaHandler::doesFileExist
01105 //      METHOD TYPE : PMError
01106 //
01107 //      DESCRIPTION :
01108 //
01109 bool MediaHandler::doesFileExist( const Pathname & filename ) const
01110 {
01111   // TODO do some logging
01112   if ( !isAttached() ) {
01113     INT << "Error Not attached on doesFileExist(" << filename << ")" << endl;
01114     ZYPP_THROW(MediaNotAttachedException(url()));
01115   }
01116   return getDoesFileExist( filename );
01117   MIL << "doesFileExist(" << filename << ")" << endl;
01118 }
01119 
01121 //
01122 //
01123 //      METHOD NAME : MediaHandler::getDirectoryYast
01124 //      METHOD TYPE : PMError
01125 //
01126 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
01127                                         const Pathname & dirname, bool dots ) const
01128 {
01129   retlist.clear();
01130 
01131   filesystem::DirContent content;
01132   getDirectoryYast( content, dirname, dots );
01133 
01134   // convert to std::list<std::string>
01135   for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
01136     retlist.push_back( it->name );
01137   }
01138 }
01139 
01141 //
01142 //
01143 //      METHOD NAME : MediaHandler::getDirectoryYast
01144 //      METHOD TYPE : PMError
01145 //
01146 void MediaHandler::getDirectoryYast( filesystem::DirContent & retlist,
01147                                      const Pathname & dirname, bool dots ) const
01148 {
01149   retlist.clear();
01150 
01151   // look for directory.yast
01152   Pathname dirFile = dirname + "directory.yast";
01153   getFile( dirFile );
01154   DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
01155 
01156   // using directory.yast
01157   ifstream dir( localPath( dirFile ).asString().c_str() );
01158   if ( dir.fail() ) {
01159     ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
01160     ZYPP_THROW(MediaSystemException(url(),
01161       "Unable to load '" + localPath( dirFile ).asString() + "'"));
01162   }
01163 
01164   string line;
01165   while( getline( dir, line ) ) {
01166     if ( line.empty() ) continue;
01167     if ( line == "directory.yast" ) continue;
01168 
01169     // Newer directory.yast append '/' to directory names
01170     // Remaining entries are unspecified, although most probabely files.
01171     filesystem::FileType type = filesystem::FT_NOT_AVAIL;
01172     if ( *line.rbegin() == '/' ) {
01173       line.erase( line.end()-1 );
01174       type = filesystem::FT_DIR;
01175     }
01176 
01177     if ( dots ) {
01178       if ( line == "." || line == ".." ) continue;
01179     } else {
01180       if ( *line.begin() == '.' ) continue;
01181     }
01182 
01183     retlist.push_back( filesystem::DirEntry( line, type ) );
01184   }
01185 }
01186 
01187 /******************************************************************
01188 **
01189 **
01190 **      FUNCTION NAME : operator<<
01191 **      FUNCTION TYPE : ostream &
01192 */
01193 ostream & operator<<( ostream & str, const MediaHandler & obj )
01194 {
01195   str << obj.url() << ( obj.isAttached() ? "" : " not" )
01196     << " attached; localRoot \"" << obj.localRoot() << "\"";
01197   return str;
01198 }
01199 
01201 //
01202 //
01203 //      METHOD NAME : MediaHandler::getFile
01204 //      METHOD TYPE : PMError
01205 //
01206 //      DESCRIPTION : Asserted that media is attached.
01207 //                    Default implementation of pure virtual.
01208 //
01209 void MediaHandler::getFile( const Pathname & filename ) const
01210 {
01211     PathInfo info( localPath( filename ) );
01212     if( info.isFile() ) {
01213         return;
01214     }
01215 
01216     if (info.isExist())
01217       ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
01218     else
01219       ZYPP_THROW(MediaFileNotFoundException(url(), filename));
01220 }
01221 
01222 
01223 void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
01224 {
01225   getFile(srcFilename);
01226 
01227   if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
01228     ZYPP_THROW(MediaWriteException(targetFilename));
01229   }
01230 }
01231 
01232 
01233 
01235 //
01236 //
01237 //      METHOD NAME : MediaHandler::getDir
01238 //      METHOD TYPE : PMError
01239 //
01240 //      DESCRIPTION : Asserted that media is attached.
01241 //                    Default implementation of pure virtual.
01242 //
01243 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
01244 {
01245   PathInfo info( localPath( dirname ) );
01246   if( info.isDir() ) {
01247     return;
01248   }
01249 
01250   if (info.isExist())
01251     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
01252   else
01253     ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
01254 }
01255 
01257 //
01258 //
01259 //      METHOD NAME : MediaHandler::getDirInfo
01260 //      METHOD TYPE : PMError
01261 //
01262 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
01263 //                    Default implementation of pure virtual.
01264 //
01265 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
01266                                const Pathname & dirname, bool dots ) const
01267 {
01268   PathInfo info( localPath( dirname ) );
01269   if( ! info.isDir() ) {
01270     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
01271   }
01272 
01273 #if NONREMOTE_DIRECTORY_YAST
01274   // use directory.yast if available
01275   try {
01276     getDirectoryYast( retlist, dirname, dots );
01277   }
01278   catch (const MediaException & excpt_r)
01279   {
01280 #endif
01281 
01282     // readdir
01283     int res = readdir( retlist, info.path(), dots );
01284     if ( res )
01285     {
01286       MediaSystemException nexcpt(url(), "readdir failed");
01287 #if NONREMOTE_DIRECTORY_YAST
01288       nexcpt.remember(excpt_r);
01289 #endif
01290       ZYPP_THROW(nexcpt);
01291     }
01292 
01293 #if NONREMOTE_DIRECTORY_YAST
01294   }
01295 #endif
01296 
01297   return;
01298 }
01299 
01301 //
01302 //
01303 //      METHOD NAME : MediaHandler::getDirInfo
01304 //      METHOD TYPE : PMError
01305 //
01306 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
01307 //                    Default implementation of pure virtual.
01308 //
01309 void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
01310                                const Pathname & dirname, bool dots ) const
01311 {
01312   PathInfo info( localPath( dirname ) );
01313   if( ! info.isDir() ) {
01314     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
01315   }
01316 
01317 #if NONREMOTE_DIRECTORY_YAST
01318   // use directory.yast if available
01319   try {
01320     getDirectoryYast( retlist, dirname, dots );
01321   }
01322   catch (const MediaException & excpt_r)
01323   {
01324 #endif
01325 
01326     // readdir
01327     int res = readdir( retlist, info.path(), dots );
01328     if ( res )
01329     {
01330         MediaSystemException nexcpt(url(), "readdir failed");
01331 #if NONREMOTE_DIRECTORY_YAST
01332         nexcpt.remember(excpt_r);
01333 #endif
01334         ZYPP_THROW(nexcpt);
01335     }
01336 #if NONREMOTE_DIRECTORY_YAST
01337   }
01338 #endif
01339 }
01340 
01342 //
01343 //
01344 //      METHOD NAME : MediaHandler::getDoesFileExist
01345 //      METHOD TYPE : PMError
01346 //
01347 //      DESCRIPTION : Asserted that file is not a directory
01348 //                    Default implementation of pure virtual.
01349 //
01350 bool MediaHandler::getDoesFileExist( const Pathname & filename ) const
01351 {
01352   PathInfo info( localPath( filename ) );
01353   if( info.isDir() ) {
01354     ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
01355   }
01356   return info.isExist();
01357 }
01358 
01359 bool MediaHandler::hasMoreDevices()
01360 {
01361   return false;
01362 }
01363 
01364 void MediaHandler::getDetectedDevices(std::vector<std::string> & devices,
01365                                       unsigned int & index) const
01366 {
01367   // clear the vector by default
01368   if (!devices.empty())
01369     devices.clear();
01370   index = 0;
01371 
01372   DBG << "No devices for this medium" << endl;
01373 }
01374 
01375 void MediaHandler::setDeltafile( const Pathname & filename ) const
01376 {
01377   _deltafile = filename;
01378 }
01379 
01380 Pathname MediaHandler::deltafile() const {
01381   return _deltafile;
01382 }
01383 
01384   } // namespace media
01385 } // namespace zypp
01386 // vim: set ts=8 sts=2 sw=2 ai noet: