1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaHandler.cc
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/String.h"
19 #include "zypp/media/MediaHandler.h"
20 #include "zypp/media/MediaManager.h"
24 // use directory.yast on every media (not just via ftp/http)
25 #define NONREMOTE_DIRECTORY_YAST 1
32 ///////////////////////////////////////////////////////////////////
34 // CLASS NAME : MediaHandler
36 ///////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////
41 // METHOD NAME : MediaHandler::MediaHandler
42 // METHOD TYPE : Constructor
46 MediaHandler::MediaHandler ( const Url & url_r,
47 const Pathname & attach_point_r,
48 const Pathname & urlpath_below_attachpoint_r,
49 const bool does_download_r )
50 : _attachPoint( new AttachPoint())
51 , _relativeRoot( urlpath_below_attachpoint_r)
52 , _does_download( does_download_r )
55 if ( !attach_point_r.empty() ) {
56 ///////////////////////////////////////////////////////////////////
57 // check if provided attachpoint is usable.
58 ///////////////////////////////////////////////////////////////////
60 PathInfo adir( attach_point_r );
61 // FIXME: verify if attach_point_r isn't a mountpoint of other device
62 if ( !adir.isDir() ) {
63 ERR << "Provided attach point is not a directory: " << adir << endl;
66 setAttachPoint( attach_point_r, false);
71 ///////////////////////////////////////////////////////////////////
74 // METHOD NAME : MediaHandler::~MediaHandler
75 // METHOD TYPE : Destructor
79 MediaHandler::~MediaHandler()
88 ///////////////////////////////////////////////////////////////////
91 // METHOD NAME : MediaHandler::removeAttachPoint
97 MediaHandler::removeAttachPoint()
100 INT << "MediaHandler deleted with media attached." << endl;
101 return; // no cleanup if media still mounted!
104 if ( _attachPoint.unique() &&
105 _attachPoint->temp &&
106 !_attachPoint->path.empty())
108 int res = recursive_rmdir( _attachPoint->path );
110 MIL << "Deleted default attach point " << _attachPoint->path << endl;
112 ERR << "Failed to Delete default attach point " << _attachPoint->path
113 << " errno(" << res << ")" << endl;
119 ///////////////////////////////////////////////////////////////////
122 // METHOD NAME : MediaHandler::attachPoint
123 // METHOD TYPE : Pathname
128 MediaHandler::attachPoint() const
130 return _attachPoint->path;
134 ///////////////////////////////////////////////////////////////////
137 // METHOD NAME : MediaHandler::attachPoint
143 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
145 _localRoot = Pathname();
147 _attachPoint.reset( new AttachPoint(path, temporary));
149 if( !_attachPoint->path.empty())
150 _localRoot = _attachPoint->path + _relativeRoot;
154 ///////////////////////////////////////////////////////////////////
157 // METHOD NAME : MediaHandler::attachPoint
163 MediaHandler::setAttachPoint(const AttachPointRef &ref)
165 _localRoot = Pathname();
168 AttachPointRef(ref).swap(_attachPoint);
170 _attachPoint.reset( new AttachPoint());
172 if( !_attachPoint->path.empty())
173 _localRoot = _attachPoint->path + _relativeRoot;
177 ///////////////////////////////////////////////////////////////////
180 // METHOD NAME : MediaHandler::findAttachedMedia
181 // METHOD TYPE : AttachedMedia
186 MediaHandler::findAttachedMedia(const MediaSourceRef &media) const
188 return MediaManager().findAttachedMedia(media);
192 ///////////////////////////////////////////////////////////////////
195 // METHOD NAME : MediaHandler::attach
196 // METHOD TYPE : Pathname
201 MediaHandler::createAttachPoint() const
203 /////////////////////////////////////////////////////////////////
204 // provide a default (temporary) attachpoint
205 /////////////////////////////////////////////////////////////////
206 const char * defmounts[] = {
207 "/var/adm/mount", "/var/tmp", /**/NULL/**/
212 for ( const char ** def = defmounts; *def; ++def ) {
214 if ( adir.isDir() && adir.userMayRWX() ) {
219 if ( aroot.empty() ) {
220 ERR << "Create attach point: Can't find a writable directory to create an attach point" << std::endl;
224 Pathname abase( aroot + "AP_" );
226 for ( unsigned i = 1; i < 1000; ++i ) {
227 adir( Pathname::extend( abase, str::hexstring( i ) ) );
228 if ( ! adir.isExist() && mkdir( adir.path() ) == 0 ) {
229 apoint = adir.path();
233 if ( apoint.empty() ) {
234 ERR << "Unable to create an attach point below " << aroot << std::endl;
236 MIL << "Created default attach point " << apoint << std::endl;
241 ///////////////////////////////////////////////////////////////////
244 // METHOD NAME : MediaHandler::setMediaSource
245 // METHOD TYPE : void
250 MediaHandler::setMediaSource(const MediaSourceRef &ref)
252 _mediaSource.reset();
253 if( ref && !ref->type.empty() && !ref->name.empty())
257 ///////////////////////////////////////////////////////////////////
260 // METHOD NAME : MediaHandler::attachedMedia
261 // METHOD TYPE : AttachedMedia
266 MediaHandler::attachedMedia() const
268 if ( _mediaSource && _attachPoint)
269 return AttachedMedia(_mediaSource, _attachPoint);
271 return AttachedMedia();
275 ///////////////////////////////////////////////////////////////////
278 // METHOD NAME : MediaHandler::attach
279 // METHOD TYPE : PMError
283 void MediaHandler::attach( bool next )
289 if ( _attachPoint->empty() ) {
290 ERR << "Bad Attachpoint" << endl;
291 ZYPP_THROW( MediaBadAttachPointException(url()));
295 attachTo( next ); // pass to concrete handler
296 MIL << "Attached: " << *this << endl;
302 ///////////////////////////////////////////////////////////////////
305 // METHOD NAME : MediaHandler::localPath
306 // METHOD TYPE : Pathname
308 Pathname MediaHandler::localPath( const Pathname & pathname ) const {
309 if ( _localRoot.empty() )
312 // we must check maximum file name length
313 // this is important for fetching the suseservers, the
314 // url with all parameters can get too long (bug #42021)
316 return _localRoot + pathname.absolutename();
323 ///////////////////////////////////////////////////////////////////
326 // METHOD NAME : MediaHandler::disconnect
327 // METHOD TYPE : PMError
329 void MediaHandler::disconnect()
334 disconnectFrom(); // pass to concrete handler
335 MIL << "Disconnected: " << *this << endl;
338 ///////////////////////////////////////////////////////////////////
341 // METHOD NAME : MediaHandler::release
342 // METHOD TYPE : PMError
346 void MediaHandler::release( bool eject )
348 if ( !isAttached() ) {
349 DBG << "Request to release media - not attached" << std::endl;
355 DBG << "Request to release attached media "
356 << _mediaSource->asString()
357 << (_mediaSource.unique() ? ", unique" : ", not unique")
360 if( _mediaSource.unique())
362 DBG << "Releasing media " << _mediaSource->asString() << std::endl;
363 releaseFrom( eject ); // pass to concrete handler
366 _mediaSource.reset();
367 MIL << "Released: " << *this << endl;
370 ///////////////////////////////////////////////////////////////////
373 // METHOD NAME : MediaHandler::provideFile
374 // METHOD TYPE : PMError
378 void MediaHandler::provideFileCopy( Pathname srcFilename,
379 Pathname targetFilename ) const
381 if ( !isAttached() ) {
382 INT << "Media not_attached on provideFileCopy(" << srcFilename
383 << "," << targetFilename << ")" << endl;
384 ZYPP_THROW(MediaNotAttachedException(url()));
387 getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
388 DBG << "provideFileCopy(" << srcFilename << "," << targetFilename << ")" << endl;
391 void MediaHandler::provideFile( Pathname filename ) const
393 if ( !isAttached() ) {
394 INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
395 ZYPP_THROW(MediaNotAttachedException(url()));
398 getFile( filename ); // pass to concrete handler
399 DBG << "provideFile(" << filename << ")" << endl;
403 ///////////////////////////////////////////////////////////////////
406 // METHOD NAME : MediaHandler::provideDir
407 // METHOD TYPE : PMError
411 void MediaHandler::provideDir( Pathname dirname ) const
413 if ( !isAttached() ) {
414 INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
415 ZYPP_THROW(MediaNotAttachedException(url()));
418 getDir( dirname, /*recursive*/false ); // pass to concrete handler
419 MIL << "provideDir(" << dirname << ")" << endl;
422 ///////////////////////////////////////////////////////////////////
425 // METHOD NAME : MediaHandler::provideDirTree
426 // METHOD TYPE : PMError
430 void MediaHandler::provideDirTree( Pathname dirname ) const
432 if ( !isAttached() ) {
433 INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
434 ZYPP_THROW(MediaNotAttachedException(url()));
437 getDir( dirname, /*recursive*/true ); // pass to concrete handler
438 MIL << "provideDirTree(" << dirname << ")" << endl;
441 ///////////////////////////////////////////////////////////////////
444 // METHOD NAME : MediaHandler::releasePath
445 // METHOD TYPE : PMError
449 void MediaHandler::releasePath( Pathname pathname ) const
451 if ( ! _does_download || _attachPoint->empty() )
454 PathInfo info( localPath( pathname ) );
456 if ( info.isFile() ) {
457 unlink( info.path() );
458 } else if ( info.isDir() ) {
459 if ( info.path() != _localRoot ) {
460 recursive_rmdir( info.path() );
462 clean_dir( info.path() );
467 ///////////////////////////////////////////////////////////////////
470 // METHOD NAME : MediaHandler::dirInfo
471 // METHOD TYPE : PMError
475 void MediaHandler::dirInfo( list<string> & retlist,
476 const Pathname & dirname, bool dots ) const
480 if ( !isAttached() ) {
481 INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
482 ZYPP_THROW(MediaNotAttachedException(url()));
485 getDirInfo( retlist, dirname, dots ); // pass to concrete handler
486 MIL << "dirInfo(" << dirname << ")" << endl;
489 ///////////////////////////////////////////////////////////////////
492 // METHOD NAME : MediaHandler::dirInfo
493 // METHOD TYPE : PMError
497 void MediaHandler::dirInfo( filesystem::DirContent & retlist,
498 const Pathname & dirname, bool dots ) const
502 if ( !isAttached() ) {
503 INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
504 ZYPP_THROW(MediaNotAttachedException(url()));
507 getDirInfo( retlist, dirname, dots ); // pass to concrete handler
508 MIL << "dirInfo(" << dirname << ")" << endl;
511 ///////////////////////////////////////////////////////////////////
514 // METHOD NAME : MediaHandler::getDirectoryYast
515 // METHOD TYPE : PMError
517 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
518 const Pathname & dirname, bool dots ) const
522 filesystem::DirContent content;
523 getDirectoryYast( content, dirname, dots );
525 // convert to std::list<std::string>
526 for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
527 retlist.push_back( it->name );
531 ///////////////////////////////////////////////////////////////////
534 // METHOD NAME : MediaHandler::getDirectoryYast
535 // METHOD TYPE : PMError
537 void MediaHandler::getDirectoryYast( filesystem::DirContent & retlist,
538 const Pathname & dirname, bool dots ) const
542 // look for directory.yast
543 Pathname dirFile = dirname + "directory.yast";
545 DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
547 // using directory.yast
548 ifstream dir( localPath( dirFile ).asString().c_str() );
550 ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
551 ZYPP_THROW(MediaSystemException(url(),
552 "Unable to load '" + localPath( dirFile ).asString() + "'"));
556 while( getline( dir, line ) ) {
557 if ( line.empty() ) continue;
558 if ( line == "directory.yast" ) continue;
560 // Newer directory.yast append '/' to directory names
561 // Remaining entries are unspecified, although most probabely files.
562 filesystem::FileType type = filesystem::FT_NOT_AVAIL;
563 if ( *line.rbegin() == '/' ) {
564 line.erase( line.end()-1 );
565 type = filesystem::FT_DIR;
569 if ( line == "." || line == ".." ) continue;
571 if ( *line.begin() == '.' ) continue;
574 retlist.push_back( filesystem::DirEntry( line, type ) );
578 /******************************************************************
581 ** FUNCTION NAME : operator<<
582 ** FUNCTION TYPE : ostream &
584 ostream & operator<<( ostream & str, const MediaHandler & obj )
586 str << obj.url() << ( obj.isAttached() ? "" : " not" )
587 << " attached; localRoot \"" << obj.localRoot() << "\"";
591 ///////////////////////////////////////////////////////////////////
594 // METHOD NAME : MediaHandler::getFile
595 // METHOD TYPE : PMError
597 // DESCRIPTION : Asserted that media is attached.
598 // Default implementation of pure virtual.
600 void MediaHandler::getFile( const Pathname & filename ) const
602 PathInfo info( localPath( filename ) );
603 if( info.isFile() ) {
608 ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
610 ZYPP_THROW(MediaFileNotFoundException(url(), filename));
614 void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
616 getFile(srcFilename);
618 if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
619 ZYPP_THROW(MediaWriteException(targetFilename));
625 ///////////////////////////////////////////////////////////////////
628 // METHOD NAME : MediaHandler::getDir
629 // METHOD TYPE : PMError
631 // DESCRIPTION : Asserted that media is attached.
632 // Default implementation of pure virtual.
634 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
636 PathInfo info( localPath( dirname ) );
642 ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
644 ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
647 ///////////////////////////////////////////////////////////////////
650 // METHOD NAME : MediaHandler::getDirInfo
651 // METHOD TYPE : PMError
653 // DESCRIPTION : Asserted that media is attached and retlist is empty.
654 // Default implementation of pure virtual.
656 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
657 const Pathname & dirname, bool dots ) const
659 PathInfo info( localPath( dirname ) );
660 if( ! info.isDir() ) {
661 ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
664 #if NONREMOTE_DIRECTORY_YAST
665 // use directory.yast if available
667 getDirectoryYast( retlist, dirname, dots );
669 catch (const MediaException & excpt_r)
674 int res = readdir( retlist, info.path(), dots );
676 ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
678 #if NONREMOTE_DIRECTORY_YAST
685 ///////////////////////////////////////////////////////////////////
688 // METHOD NAME : MediaHandler::getDirInfo
689 // METHOD TYPE : PMError
691 // DESCRIPTION : Asserted that media is attached and retlist is empty.
692 // Default implementation of pure virtual.
694 void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
695 const Pathname & dirname, bool dots ) const
697 PathInfo info( localPath( dirname ) );
698 if( ! info.isDir() ) {
699 ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
702 #if NONREMOTE_DIRECTORY_YAST
703 // use directory.yast if available
705 getDirectoryYast( retlist, dirname, dots );
707 catch (const MediaException & excpt_r)
712 int res = readdir( retlist, info.path(), dots );
714 ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
715 #if NONREMOTE_DIRECTORY_YAST