1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/librpmDb.cc
16 #include "zypp/base/Logger.h"
17 #include "zypp/PathInfo.h"
18 #include "zypp/target/rpm/librpmDb.h"
19 #include "zypp/target/rpm/RpmHeader.h"
20 #include "zypp/target/rpm/RpmException.h"
22 #undef ZYPP_BASE_LOGGER_LOGGROUP
23 #define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
33 ///////////////////////////////////////////////////////////////////
35 // CLASS NAME : librpmDb::D
37 * @short librpmDb internal database handle
41 D & operator=( const D & ); // NO ASSIGNMENT!
42 D ( const D & ); // NO COPY!
45 const Pathname _root; // root directory for all operations
46 const Pathname _dbPath; // directory (below root) that contains the rpmdb
47 rpmts _ts; // transaction handle, includes database
48 shared_ptr<RpmException> _error; // database error
50 friend ostream & operator<<( ostream & str, const D & obj )
52 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
56 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
63 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
65 _ts = ::rpmtsCreate();
66 ::rpmtsSetRootDir( _ts, _root.c_str() );
68 // check whether to create a new db
69 PathInfo master( _root + _dbPath + "Packages" );
70 if ( ! master.isFile() )
73 if ( filesystem::assert_dir(_root + _dbPath) != 0 )
75 ERR << "Could not create dbpath " << (_root + _dbPath).asString() << endl;
76 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
79 int res = ::rpmtsInitDB( _ts, 0644 );
82 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
83 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
90 int res = ::rpmtsOpenDB( _ts, (readonly_r ? O_RDONLY : O_RDWR ));
93 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
94 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
100 DBG << "DBACCESS " << *this << endl;
112 ///////////////////////////////////////////////////////////////////
114 ///////////////////////////////////////////////////////////////////
116 // CLASS NAME : librpmDb (ststic interface)
118 ///////////////////////////////////////////////////////////////////
120 Pathname librpmDb::_defaultRoot; // Remembered arg to last dbAccess call
121 Pathname librpmDb::_defaultDbPath; // Remembered arg to last dbAccess call
122 librpmDb::constPtr librpmDb::_defaultDb;
123 bool librpmDb::_dbBlocked ( true );
125 ///////////////////////////////////////////////////////////////////
128 // METHOD NAME : librpmDb::globalInit
129 // METHOD TYPE : bool
131 bool librpmDb::globalInit()
133 static bool initialized = false;
138 int rc = ::rpmReadConfigFiles( NULL, NULL );
141 ERR << "rpmReadConfigFiles returned " << rc << endl;
145 initialized = true; // Necessary to be able to use exand().
147 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
148 MIL << "librpm init done:"
156 ///////////////////////////////////////////////////////////////////
159 // METHOD NAME : librpmDb::expand
160 // METHOD TYPE : std::string
162 std::string librpmDb::expand( const std::string & macro_r )
164 if ( ! globalInit() )
165 return macro_r; // unexpanded
167 char * val = ::rpmExpand( macro_r.c_str(), NULL );
176 ///////////////////////////////////////////////////////////////////
179 // METHOD NAME : librpmDb::newLibrpmDb
180 // METHOD TYPE : librpmDb *
182 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
185 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
187 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
191 if ( ! globalInit() )
193 ZYPP_THROW(GlobalRpmInitException());
200 ret = new librpmDb( root_r, dbPath_r, readonly_r );
202 catch (const RpmException & excpt_r)
204 ZYPP_CAUGHT(excpt_r);
207 ZYPP_RETHROW(excpt_r);
212 ///////////////////////////////////////////////////////////////////
215 // METHOD NAME : librpmDb::dbAccess
216 // METHOD TYPE : PMError
218 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
221 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
223 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
228 // already accessing a database: switching is not allowed.
229 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
233 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
237 // got no database: we could switch to a new one (even if blocked!)
238 _defaultRoot = root_r;
239 _defaultDbPath = dbPath_r;
240 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
245 ///////////////////////////////////////////////////////////////////
248 // METHOD NAME : librpmDb::dbAccess
249 // METHOD TYPE : PMError
251 void librpmDb::dbAccess()
255 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
261 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
265 ///////////////////////////////////////////////////////////////////
268 // METHOD NAME : librpmDb::dbAccess
269 // METHOD TYPE : PMError
271 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
277 catch (const RpmException & excpt_r)
279 ZYPP_CAUGHT(excpt_r);
281 ZYPP_RETHROW(excpt_r);
286 ///////////////////////////////////////////////////////////////////
289 // METHOD NAME : librpmDb::dbRelease
290 // METHOD TYPE : unsigned
292 unsigned librpmDb::dbRelease( bool force_r )
299 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
301 switch ( outstanding )
306 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
309 // else fall through:
311 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
312 << ", outstanding " << outstanding << endl;
314 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
315 // tag handle invalid
323 ///////////////////////////////////////////////////////////////////
326 // METHOD NAME : librpmDb::blockAccess
327 // METHOD TYPE : unsigned
329 unsigned librpmDb::blockAccess()
331 MIL << "Block access" << endl;
333 return dbRelease( /*force*/true );
336 ///////////////////////////////////////////////////////////////////
339 // METHOD NAME : librpmDb::unblockAccess
340 // METHOD TYPE : void
342 void librpmDb::unblockAccess()
344 MIL << "Unblock access" << endl;
348 ///////////////////////////////////////////////////////////////////
351 // METHOD NAME : librpmDb::dumpState
352 // METHOD TYPE : ostream &
354 ostream & librpmDb::dumpState( ostream & str )
358 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
360 return str << "[" << _defaultDb << "]";
363 ///////////////////////////////////////////////////////////////////
365 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
367 ///////////////////////////////////////////////////////////////////
369 ///////////////////////////////////////////////////////////////////
372 // METHOD NAME : librpmDb::librpmDb
373 // METHOD TYPE : Constructor
377 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
378 : _d( * new D( root_r, dbPath_r, readonly_r ) )
381 ///////////////////////////////////////////////////////////////////
384 // METHOD NAME : librpmDb::~librpmDb
385 // METHOD TYPE : Destructor
389 librpmDb::~librpmDb()
394 ///////////////////////////////////////////////////////////////////
397 // METHOD NAME : librpmDb::unref_to
398 // METHOD TYPE : void
400 void librpmDb::unref_to( unsigned refCount_r ) const
402 if ( refCount_r == 1 )
408 ///////////////////////////////////////////////////////////////////
411 // METHOD NAME : librpmDb::root
412 // METHOD TYPE : const Pathname &
414 const Pathname & librpmDb::root() const
419 ///////////////////////////////////////////////////////////////////
422 // METHOD NAME : librpmDb::dbPath
423 // METHOD TYPE : const Pathname &
425 const Pathname & librpmDb::dbPath() const
430 ///////////////////////////////////////////////////////////////////
433 // METHOD NAME : librpmDb::error
434 // METHOD TYPE : PMError
436 shared_ptr<RpmException> librpmDb::error() const
441 ///////////////////////////////////////////////////////////////////
444 // METHOD NAME : librpmDb::empty
445 // METHOD TYPE : bool
447 bool librpmDb::empty() const
449 return( valid() && ! *db_const_iterator( this ) );
452 ///////////////////////////////////////////////////////////////////
455 // METHOD NAME : librpmDb::size
456 // METHOD TYPE : unsigned
458 unsigned librpmDb::size() const
463 db_const_iterator it( this );
464 for ( db_const_iterator it( this ); *it; ++it )
470 ///////////////////////////////////////////////////////////////////
473 // METHOD NAME : librpmDb::dont_call_it
474 // METHOD TYPE : void *
476 void * librpmDb::dont_call_it() const
478 return rpmtsGetRdb(_d._ts);
481 ///////////////////////////////////////////////////////////////////
484 // METHOD NAME : librpmDb::dumpOn
485 // METHOD TYPE : ostream &
489 ostream & librpmDb::dumpOn( ostream & str ) const
491 ReferenceCounted::dumpOn( str ) << _d;
495 ///////////////////////////////////////////////////////////////////
497 // CLASS NAME : librpmDb::DbDirInfo
499 ///////////////////////////////////////////////////////////////////
501 ///////////////////////////////////////////////////////////////////
504 // METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
505 // METHOD TYPE : Constructor
507 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
509 , _dbPath( dbPath_r )
511 // check and adjust arguments
512 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
514 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
518 _dbDir ( _root + _dbPath );
519 _dbV4 ( _dbDir.path() + "Packages" );
520 _dbV3 ( _dbDir.path() + "packages.rpm" );
521 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
522 DBG << *this << endl;
526 ///////////////////////////////////////////////////////////////////
529 // METHOD NAME : librpmDb::DbDirInfo::update
530 // METHOD TYPE : void
532 void librpmDb::DbDirInfo::restat()
538 DBG << *this << endl;
541 /******************************************************************
544 ** FUNCTION NAME : operator<<
545 ** FUNCTION TYPE : std::ostream &
547 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
549 if ( obj.illegalArgs() )
551 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
555 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
556 str << " Dir: " << obj._dbDir << endl;
557 str << " V4: " << obj._dbV4 << endl;
558 str << " V3: " << obj._dbV3 << endl;
559 str << " V3ToV4: " << obj._dbV3ToV4;
564 ///////////////////////////////////////////////////////////////////
566 // CLASS NAME : librpmDb::db_const_iterator::D
570 class librpmDb::db_const_iterator::D
572 D & operator=( const D & ); // NO ASSIGNMENT!
573 D ( const D & ); // NO COPY!
576 librpmDb::constPtr _dbptr;
577 shared_ptr<RpmException> _dberr;
579 RpmHeader::constPtr _hptr;
580 rpmdbMatchIterator _mi;
582 D( librpmDb::constPtr dbptr_r )
590 librpmDb::dbAccess( _dbptr );
592 catch (const RpmException & excpt_r)
594 ZYPP_CAUGHT(excpt_r);
598 WAR << "No database access: " << _dberr << endl;
603 destroy(); // Checks whether _dbptr still valid
611 ::rpmdbFreeIterator( _mi );
616 * Let iterator access a dbindex file. Call @ref advance to access the
617 * 1st element (if present).
619 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
624 _mi = ::rpmtsInitIterator( _dbptr->_d._ts, rpmTag(rpmtag), keyp, keylen );
629 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
630 * Always returns false.
636 _mi = ::rpmdbFreeIterator( _mi );
639 if ( _dbptr && _dbptr->error() )
641 _dberr = _dbptr->error();
642 WAR << "Lost database access: " << _dberr << endl;
649 * Advance to the first/next header in iterator. Destroys iterator if
650 * no more headers available.
656 Header h = ::rpmdbNextIterator( _mi );
662 _hptr = new RpmHeader( h );
667 * Access a dbindex file and advance to the 1st header.
669 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
671 if ( ! create( rpmtag, keyp, keylen ) )
677 * Create an itertator that contains the database entry located at
678 * off_r, and advance to the 1st header.
680 bool set( int off_r )
682 if ( ! create( RPMDBI_PACKAGES ) )
684 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
685 #ifdef RPMFILEITERMAX // since rpm.4.12
686 ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
688 ::rpmdbAppendIterator( _mi, &off_r, 1 );
695 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
702 int ret = ::rpmdbGetIteratorCount( _mi );
703 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
704 return( ret ? ret : -1 ); // -1: sequential access
708 ///////////////////////////////////////////////////////////////////
710 ///////////////////////////////////////////////////////////////////
712 // CLASS NAME : librpmDb::Ptr::db_const_iterator
714 ///////////////////////////////////////////////////////////////////
716 ///////////////////////////////////////////////////////////////////
719 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
720 // METHOD TYPE : Constructor
722 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
723 : _d( * new D( dbptr_r ) )
728 ///////////////////////////////////////////////////////////////////
731 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
732 // METHOD TYPE : Destructor
734 librpmDb::db_const_iterator::~db_const_iterator()
739 ///////////////////////////////////////////////////////////////////
742 // METHOD NAME : librpmDb::db_const_iterator::operator++
743 // METHOD TYPE : void
745 void librpmDb::db_const_iterator::operator++()
750 ///////////////////////////////////////////////////////////////////
753 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
754 // METHOD TYPE : unsigned
756 unsigned librpmDb::db_const_iterator::dbHdrNum() const
761 ///////////////////////////////////////////////////////////////////
764 // METHOD NAME : librpmDb::db_const_iterator::operator*
765 // METHOD TYPE : const RpmHeader::constPtr &
767 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
772 ///////////////////////////////////////////////////////////////////
775 // METHOD NAME : librpmDb::db_const_iterator::dbError
776 // METHOD TYPE : PMError
778 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
781 return _d._dbptr->error();
786 /******************************************************************
789 ** FUNCTION NAME : operator<<
790 ** FUNCTION TYPE : ostream &
792 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
794 str << "db_const_iterator(" << obj._d._dbptr
795 << " Size:" << obj._d.size()
796 << " HdrNum:" << obj._d.offset()
801 ///////////////////////////////////////////////////////////////////
804 // METHOD NAME : librpmDb::db_const_iterator::findAll
805 // METHOD TYPE : bool
807 bool librpmDb::db_const_iterator::findAll()
809 return _d.init( RPMDBI_PACKAGES );
812 ///////////////////////////////////////////////////////////////////
815 // METHOD NAME : librpmDb::db_const_iterator::findByFile
816 // METHOD TYPE : bool
818 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
820 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
823 ///////////////////////////////////////////////////////////////////
826 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
827 // METHOD TYPE : bool
829 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
831 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
834 ///////////////////////////////////////////////////////////////////
837 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
838 // METHOD TYPE : bool
840 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
842 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
845 ///////////////////////////////////////////////////////////////////
848 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
849 // METHOD TYPE : bool
851 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
853 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
856 ///////////////////////////////////////////////////////////////////
859 // METHOD NAME : librpmDb::findByName
860 // METHOD TYPE : bool
862 bool librpmDb::db_const_iterator::findByName( const string & name_r )
864 return _d.init( RPMTAG_NAME, name_r.c_str() );
867 ///////////////////////////////////////////////////////////////////
870 // METHOD NAME : librpmDb::db_const_iterator::findPackage
871 // METHOD TYPE : bool
873 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
875 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
878 if ( _d.size() == 1 )
881 // check installtime on multiple entries
884 for ( ; operator*(); operator++() )
886 if ( operator*()->tag_installtime() > itime )
889 itime = operator*()->tag_installtime();
893 return _d.set( match );
896 ///////////////////////////////////////////////////////////////////
899 // METHOD NAME : librpmDb::db_const_iterator::findPackage
900 // METHOD TYPE : bool
902 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
904 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
907 for ( ; operator*(); operator++() )
909 if ( ed_r == operator*()->tag_edition() )
911 int match = _d.offset();
912 return _d.set( match );
919 ///////////////////////////////////////////////////////////////////
922 // METHOD NAME : librpmDb::db_const_iterator::findPackage
923 // METHOD TYPE : bool
925 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
930 return findPackage( which_r->name(), which_r->edition() );
934 } // namespace target