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 )
53 , _isAttached( false )
56 if ( !attach_point_r.empty() ) {
57 ///////////////////////////////////////////////////////////////////
58 // check if provided attachpoint is usable.
59 ///////////////////////////////////////////////////////////////////
61 PathInfo adir( attach_point_r );
62 // FIXME: verify if attach_point_r isn't a mountpoint of other device
63 if ( !adir.isDir() ) {
64 ERR << "Provided attach point is not a directory: " << adir << endl;
67 setAttachPoint( attach_point_r, false);
72 ///////////////////////////////////////////////////////////////////
75 // METHOD NAME : MediaHandler::~MediaHandler
76 // METHOD TYPE : Destructor
80 MediaHandler::~MediaHandler()
85 ///////////////////////////////////////////////////////////////////
88 // METHOD NAME : MediaHandler::removeAttachPoint
94 MediaHandler::removeAttachPoint()
97 INT << "MediaHandler deleted with media attached." << endl;
98 return; // no cleanup if media still mounted!
101 if ( _attachPoint.unique() &&
102 _attachPoint->temp &&
103 !_attachPoint->path.empty())
105 int res = recursive_rmdir( _attachPoint->path );
107 MIL << "Deleted default attach point " << _attachPoint->path << endl;
109 ERR << "Failed to Delete default attach point " << _attachPoint->path
110 << " errno(" << res << ")" << endl;
116 ///////////////////////////////////////////////////////////////////
119 // METHOD NAME : MediaHandler::attachPoint
120 // METHOD TYPE : Pathname
125 MediaHandler::attachPoint() const
127 return _attachPoint->path;
131 ///////////////////////////////////////////////////////////////////
134 // METHOD NAME : MediaHandler::attachPoint
140 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
142 _localRoot = Pathname();
144 _attachPoint.reset( new AttachPoint(path, temporary));
146 if( !_attachPoint->path.empty())
147 _localRoot = _attachPoint->path + _relativeRoot;
151 ///////////////////////////////////////////////////////////////////
154 // METHOD NAME : MediaHandler::attachPoint
160 MediaHandler::setAttachPoint(const AttachPointRef &ref)
162 _localRoot = Pathname();
165 AttachPointRef(ref).swap(_attachPoint);
167 _attachPoint.reset( new AttachPoint());
169 if( !_attachPoint->path.empty())
170 _localRoot = _attachPoint->path + _relativeRoot;
174 ///////////////////////////////////////////////////////////////////
177 // METHOD NAME : MediaHandler::findAttachedMedia
178 // METHOD TYPE : AttachedMedia
183 MediaHandler::findAttachedMedia(const MediaSourceRef &media) const
185 return MediaManager().findAttachedMedia(media);
189 ///////////////////////////////////////////////////////////////////
192 // METHOD NAME : MediaHandler::attach
193 // METHOD TYPE : Pathname
198 MediaHandler::createAttachPoint() const
200 /////////////////////////////////////////////////////////////////
201 // provide a default (temporary) attachpoint
202 /////////////////////////////////////////////////////////////////
203 const char * defmounts[] = {
204 "/var/adm/mount", "/var/tmp", /**/NULL/**/
209 for ( const char ** def = defmounts; *def; ++def ) {
211 if ( adir.isDir() && adir.userMayRWX() ) {
216 if ( aroot.empty() ) {
217 ERR << "Create attach point: Can't find a writable directory to create an attach point" << std::endl;
221 Pathname abase( aroot + "AP_" );
223 for ( unsigned i = 1; i < 1000; ++i ) {
224 adir( Pathname::extend( abase, str::hexstring( i ) ) );
225 if ( ! adir.isExist() && mkdir( adir.path() ) == 0 ) {
226 apoint = adir.path();
230 if ( apoint.empty() ) {
231 ERR << "Unable to create an attach point below " << aroot << std::endl;
233 MIL << "Created default attach point " << apoint << std::endl;
238 ///////////////////////////////////////////////////////////////////
241 // METHOD NAME : MediaHandler::attachedMedia
242 // METHOD TYPE : AttachedMedia
247 MediaHandler::attachedMedia() const
249 if ( _isAttached && _mediaSource && _attachPoint)
250 return AttachedMedia(_mediaSource, _attachPoint);
252 return AttachedMedia();
256 ///////////////////////////////////////////////////////////////////
259 // METHOD NAME : MediaHandler::attach
260 // METHOD TYPE : PMError
264 void MediaHandler::attach( bool next )
270 if ( _attachPoint->empty() ) {
271 ERR << "Bad Attachpoint" << endl;
272 ZYPP_THROW( MediaBadAttachPointException(url()));
276 attachTo( next ); // pass to concrete handler
278 MIL << "Attached: " << *this << endl;
284 ///////////////////////////////////////////////////////////////////
287 // METHOD NAME : MediaHandler::localPath
288 // METHOD TYPE : Pathname
290 Pathname MediaHandler::localPath( const Pathname & pathname ) const {
291 if ( _localRoot.empty() )
294 // we must check maximum file name length
295 // this is important for fetching the suseservers, the
296 // url with all parameters can get too long (bug #42021)
298 return _localRoot + pathname.absolutename();
305 ///////////////////////////////////////////////////////////////////
308 // METHOD NAME : MediaHandler::disconnect
309 // METHOD TYPE : PMError
311 void MediaHandler::disconnect()
316 disconnectFrom(); // pass to concrete handler
317 MIL << "Disconnected: " << *this << endl;
320 ///////////////////////////////////////////////////////////////////
323 // METHOD NAME : MediaHandler::release
324 // METHOD TYPE : PMError
328 void MediaHandler::release( bool eject )
330 if ( !_isAttached ) {
336 releaseFrom( eject ); // pass to concrete handler
338 MIL << "Released: " << *this << endl;
341 ///////////////////////////////////////////////////////////////////
344 // METHOD NAME : MediaHandler::provideFile
345 // METHOD TYPE : PMError
349 void MediaHandler::provideFileCopy( Pathname srcFilename,
350 Pathname targetFilename ) const
352 if ( !_isAttached ) {
353 INT << "Media not_attached on provideFileCopy(" << srcFilename
354 << "," << targetFilename << ")" << endl;
355 ZYPP_THROW(MediaNotAttachedException(url()));
358 getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
359 DBG << "provideFileCopy(" << srcFilename << "," << targetFilename << ")" << endl;
362 void MediaHandler::provideFile( Pathname filename ) const
364 if ( !_isAttached ) {
365 INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
366 ZYPP_THROW(MediaNotAttachedException(url()));
369 getFile( filename ); // pass to concrete handler
370 DBG << "provideFile(" << filename << ")" << endl;
374 ///////////////////////////////////////////////////////////////////
377 // METHOD NAME : MediaHandler::provideDir
378 // METHOD TYPE : PMError
382 void MediaHandler::provideDir( Pathname dirname ) const
384 if ( !_isAttached ) {
385 INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
386 ZYPP_THROW(MediaNotAttachedException(url()));
389 getDir( dirname, /*recursive*/false ); // pass to concrete handler
390 MIL << "provideDir(" << dirname << ")" << endl;
393 ///////////////////////////////////////////////////////////////////
396 // METHOD NAME : MediaHandler::provideDirTree
397 // METHOD TYPE : PMError
401 void MediaHandler::provideDirTree( Pathname dirname ) const
403 if ( !_isAttached ) {
404 INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
405 ZYPP_THROW(MediaNotAttachedException(url()));
408 getDir( dirname, /*recursive*/true ); // pass to concrete handler
409 MIL << "provideDirTree(" << dirname << ")" << endl;
412 ///////////////////////////////////////////////////////////////////
415 // METHOD NAME : MediaHandler::releasePath
416 // METHOD TYPE : PMError
420 void MediaHandler::releasePath( Pathname pathname ) const
422 if ( ! _does_download || _attachPoint->empty() )
425 PathInfo info( localPath( pathname ) );
427 if ( info.isFile() ) {
428 unlink( info.path() );
429 } else if ( info.isDir() ) {
430 if ( info.path() != _localRoot ) {
431 recursive_rmdir( info.path() );
433 clean_dir( info.path() );
438 ///////////////////////////////////////////////////////////////////
441 // METHOD NAME : MediaHandler::dirInfo
442 // METHOD TYPE : PMError
446 void MediaHandler::dirInfo( list<string> & retlist,
447 const Pathname & dirname, bool dots ) const
451 if ( !_isAttached ) {
452 INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
453 ZYPP_THROW(MediaNotAttachedException(url()));
456 getDirInfo( retlist, dirname, dots ); // pass to concrete handler
457 MIL << "dirInfo(" << dirname << ")" << endl;
460 ///////////////////////////////////////////////////////////////////
463 // METHOD NAME : MediaHandler::dirInfo
464 // METHOD TYPE : PMError
468 void MediaHandler::dirInfo( filesystem::DirContent & retlist,
469 const Pathname & dirname, bool dots ) const
473 if ( !_isAttached ) {
474 INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
475 ZYPP_THROW(MediaNotAttachedException(url()));
478 getDirInfo( retlist, dirname, dots ); // pass to concrete handler
479 MIL << "dirInfo(" << dirname << ")" << endl;
482 ///////////////////////////////////////////////////////////////////
485 // METHOD NAME : MediaHandler::getDirectoryYast
486 // METHOD TYPE : PMError
488 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
489 const Pathname & dirname, bool dots ) const
493 filesystem::DirContent content;
494 getDirectoryYast( content, dirname, dots );
496 // convert to std::list<std::string>
497 for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
498 retlist.push_back( it->name );
502 ///////////////////////////////////////////////////////////////////
505 // METHOD NAME : MediaHandler::getDirectoryYast
506 // METHOD TYPE : PMError
508 void MediaHandler::getDirectoryYast( filesystem::DirContent & retlist,
509 const Pathname & dirname, bool dots ) const
513 // look for directory.yast
514 Pathname dirFile = dirname + "directory.yast";
516 DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
518 // using directory.yast
519 ifstream dir( localPath( dirFile ).asString().c_str() );
521 ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
522 ZYPP_THROW(MediaSystemException(url(),
523 "Unable to load '" + localPath( dirFile ).asString() + "'"));
527 while( getline( dir, line ) ) {
528 if ( line.empty() ) continue;
529 if ( line == "directory.yast" ) continue;
531 // Newer directory.yast append '/' to directory names
532 // Remaining entries are unspecified, although most probabely files.
533 filesystem::FileType type = filesystem::FT_NOT_AVAIL;
534 if ( *line.rbegin() == '/' ) {
535 line.erase( line.end()-1 );
536 type = filesystem::FT_DIR;
540 if ( line == "." || line == ".." ) continue;
542 if ( *line.begin() == '.' ) continue;
545 retlist.push_back( filesystem::DirEntry( line, type ) );
549 /******************************************************************
552 ** FUNCTION NAME : operator<<
553 ** FUNCTION TYPE : ostream &
555 ostream & operator<<( ostream & str, const MediaHandler & obj )
557 str << obj.url() << ( obj.isAttached() ? "" : " not" )
558 << " attached; localRoot \"" << obj.localRoot() << "\"";
562 ///////////////////////////////////////////////////////////////////
565 // METHOD NAME : MediaHandler::getFile
566 // METHOD TYPE : PMError
568 // DESCRIPTION : Asserted that media is attached.
569 // Default implementation of pure virtual.
571 void MediaHandler::getFile( const Pathname & filename ) const
573 PathInfo info( localPath( filename ) );
574 if( info.isFile() ) {
579 ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
581 ZYPP_THROW(MediaFileNotFoundException(url(), filename));
585 void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
587 getFile(srcFilename);
589 if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
590 ZYPP_THROW(MediaWriteException(targetFilename));
596 ///////////////////////////////////////////////////////////////////
599 // METHOD NAME : MediaHandler::getDir
600 // METHOD TYPE : PMError
602 // DESCRIPTION : Asserted that media is attached.
603 // Default implementation of pure virtual.
605 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
607 PathInfo info( localPath( dirname ) );
613 ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
615 ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
618 ///////////////////////////////////////////////////////////////////
621 // METHOD NAME : MediaHandler::getDirInfo
622 // METHOD TYPE : PMError
624 // DESCRIPTION : Asserted that media is attached and retlist is empty.
625 // Default implementation of pure virtual.
627 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
628 const Pathname & dirname, bool dots ) const
630 PathInfo info( localPath( dirname ) );
631 if( ! info.isDir() ) {
632 ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
635 #if NONREMOTE_DIRECTORY_YAST
636 // use directory.yast if available
638 getDirectoryYast( retlist, dirname, dots );
640 catch (const MediaException & excpt_r)
645 int res = readdir( retlist, info.path(), dots );
647 ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
649 #if NONREMOTE_DIRECTORY_YAST
656 ///////////////////////////////////////////////////////////////////
659 // METHOD NAME : MediaHandler::getDirInfo
660 // METHOD TYPE : PMError
662 // DESCRIPTION : Asserted that media is attached and retlist is empty.
663 // Default implementation of pure virtual.
665 void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
666 const Pathname & dirname, bool dots ) const
668 PathInfo info( localPath( dirname ) );
669 if( ! info.isDir() ) {
670 ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
673 #if NONREMOTE_DIRECTORY_YAST
674 // use directory.yast if available
676 getDirectoryYast( retlist, dirname, dots );
678 catch (const MediaException & excpt_r)
683 int res = readdir( retlist, info.path(), dots );
685 ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
686 #if NONREMOTE_DIRECTORY_YAST