- Speedup computation of number of rpm database entries.
[platform/upstream/libzypp.git] / zypp / target / rpm / librpmDb.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/librpmDb.cc
10  *
11 */
12 #include "librpm.h"
13
14 #include <iostream>
15
16 #include "zypp/base/Logger.h"
17 #include "zypp/target/rpm/librpmDb.h"
18 #include "zypp/target/rpm/RpmHeader.h"
19 #include "zypp/target/rpm/RpmException.h"
20
21 using namespace std;
22
23 namespace zypp {
24   namespace target {
25     namespace rpm {
26 ///////////////////////////////////////////////////////////////////
27 //
28 //      CLASS NAME : librpmDb::D
29 /**
30  * @short librpmDb internal database handle
31  **/
32 class librpmDb::D {
33   D & operator=( const D & ); // NO ASSIGNMENT!
34   D ( const D & );            // NO COPY!
35   public:
36
37     const Pathname _root;   // root directory for all operations
38     const Pathname _dbPath; // directory (below root) that contains the rpmdb
39     rpmdb          _db;     // database handle
40     shared_ptr<RpmException> _error;  // database error
41
42     friend ostream & operator<<( ostream & str, const D & obj ) {
43       str << "{" << obj._error  << "(" << obj._root << ")" << obj._dbPath << "}";
44       return str;
45     }
46
47     D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
48       : _root  ( root_r )
49       , _dbPath( dbPath_r )
50       , _db    ( 0 )
51     {
52       _error.reset();
53       // set %_dbpath macro
54       ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
55       const char * root = ( _root == "/" ? NULL : _root.asString().c_str() );
56       int          perms = 0644;
57
58       // check whether to create a new db
59       PathInfo master( _root + _dbPath + "Packages" );
60       if ( ! master.isFile() ) {
61         // init database
62         int res = ::rpmdbInit( root, perms );
63         if ( res ) {
64           ERR << "rpmdbInit error(" << res << "): " << *this << endl;
65           _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
66           ZYPP_THROW(*_error);
67         }
68       }
69
70       // open database
71       int res = ::rpmdbOpen( root, &_db, (readonly_r ? O_RDONLY : O_RDWR ), perms );
72       if ( res || !_db ) {
73         if ( _db ) {
74           ::rpmdbClose( _db );
75           _db = 0;
76         }
77         ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
78         _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
79         ZYPP_THROW(*_error);
80         return;
81       }
82
83       DBG << "DBACCESS " << *this << endl;
84     }
85
86     ~D() {
87       if ( _db ) {
88       ::rpmdbClose( _db );
89       }
90     }
91 };
92
93 ///////////////////////////////////////////////////////////////////
94
95 ///////////////////////////////////////////////////////////////////
96 //
97 //      CLASS NAME : librpmDb (ststic interface)
98 //
99 ///////////////////////////////////////////////////////////////////
100
101 Pathname         librpmDb::_defaultRoot  ( "/" );
102 Pathname         librpmDb::_defaultDbPath( "/var/lib/rpm" );
103 librpmDb::constPtr librpmDb::_defaultDb;
104 bool             librpmDb::_dbBlocked    ( true );
105
106 ///////////////////////////////////////////////////////////////////
107 //
108 //
109 //      METHOD NAME : librpmDb::globalInit
110 //      METHOD TYPE : bool
111 //
112 bool librpmDb::globalInit()
113 {
114   static bool initialized = false;
115
116   if ( initialized )
117     return true;
118
119   int rc = ::rpmReadConfigFiles( NULL, NULL );
120   if ( rc ) {
121     ERR << "rpmReadConfigFiles returned " << rc << endl;
122     return false;
123   }
124
125   // should speed up convertdb and rebuilddb.
126   ::addMacro( NULL, "_rpmdb_rebuild", NULL, "%{nil}", RMIL_CMDLINE );
127
128   initialized = true; // Necessary to be able to use exand().
129
130 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
131   MIL << "librpm init done:"
132     OUTVAL(_target)
133     OUTVAL(_dbpath)
134       << endl;
135 #undef OUTVAL
136   return initialized;
137 }
138
139 ///////////////////////////////////////////////////////////////////
140 //
141 //
142 //      METHOD NAME : librpmDb::expand
143 //      METHOD TYPE : std::string
144 //
145 std::string librpmDb::expand( const std::string & macro_r )
146 {
147   if ( ! globalInit() )
148     return macro_r;  // unexpanded
149
150   char * val = ::rpmExpand( macro_r.c_str(), NULL );
151   if ( !val )
152     return "";
153
154   string ret( val );
155   free( val );
156   return ret;
157 }
158
159 ///////////////////////////////////////////////////////////////////
160 //
161 //
162 //      METHOD NAME : librpmDb::newLibrpmDb
163 //      METHOD TYPE : librpmDb *
164 //
165 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
166 {
167   // check arguments
168   if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
169     ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
170   }
171
172   // initialize librpm
173   if ( ! globalInit() ) {
174     ZYPP_THROW(GlobalRpmInitException());
175   }
176
177   // open rpmdb
178   librpmDb * ret = 0;
179   try {
180     ret = new librpmDb( root_r, dbPath_r, readonly_r );
181   }
182   catch (const RpmException & excpt_r)
183   {
184     ZYPP_CAUGHT(excpt_r);
185     delete ret;
186     ret = 0;
187     ZYPP_RETHROW(excpt_r);
188   }
189   return ret;
190 }
191
192 ///////////////////////////////////////////////////////////////////
193 //
194 //
195 //      METHOD NAME : librpmDb::dbAccess
196 //      METHOD TYPE : PMError
197 //
198 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
199 {
200   // check arguments
201   if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
202     ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
203   }
204
205   if ( _defaultDb ) {
206     // already accessing a database: switching is not allowed.
207     if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
208       return;
209     else {
210       ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
211     }
212   }
213
214   // got no database: we could switch to a new one (even if blocked!)
215   _defaultRoot = root_r;
216   _defaultDbPath = dbPath_r;
217   MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
218
219   return dbAccess();
220 }
221
222 ///////////////////////////////////////////////////////////////////
223 //
224 //
225 //      METHOD NAME : librpmDb::dbAccess
226 //      METHOD TYPE : PMError
227 //
228 void librpmDb::dbAccess()
229 {
230   if ( _dbBlocked ) {
231     ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
232   }
233
234   if ( !_defaultDb ) {
235     // get access
236     _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
237   }
238 }
239
240 ///////////////////////////////////////////////////////////////////
241 //
242 //
243 //      METHOD NAME : librpmDb::dbAccess
244 //      METHOD TYPE : PMError
245 //
246 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
247 {
248   try {
249     dbAccess();
250   }
251   catch (const RpmException & excpt_r)
252   {
253     ZYPP_CAUGHT(excpt_r);
254     ptr_r = 0;
255     ZYPP_RETHROW(excpt_r);
256   }
257   ptr_r = _defaultDb;
258 }
259
260 ///////////////////////////////////////////////////////////////////
261 //
262 //
263 //      METHOD NAME : librpmDb::dbRelease
264 //      METHOD TYPE : unsigned
265 //
266 unsigned librpmDb::dbRelease( bool force_r )
267 {
268   if ( !_defaultDb ) {
269     return 0;
270   }
271
272   unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
273
274   switch ( outstanding ) {
275   default:
276     if ( !force_r ) {
277       DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
278       break;
279     }
280     // else fall through:
281   case 0:
282     DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
283       << ", outstanding " << outstanding << endl;
284
285     _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
286     // tag handle invalid
287     _defaultDb = 0;
288     break;
289   }
290
291   return outstanding;
292 }
293
294 ///////////////////////////////////////////////////////////////////
295 //
296 //
297 //      METHOD NAME : librpmDb::blockAccess
298 //      METHOD TYPE : unsigned
299 //
300 unsigned librpmDb::blockAccess()
301 {
302   MIL << "Block access" << endl;
303   _dbBlocked = true;
304   return dbRelease( /*force*/true );
305 }
306
307 ///////////////////////////////////////////////////////////////////
308 //
309 //
310 //      METHOD NAME : librpmDb::unblockAccess
311 //      METHOD TYPE : void
312 //
313 void librpmDb::unblockAccess()
314 {
315   MIL << "Unblock access" << endl;
316   _dbBlocked = false;
317 }
318
319 ///////////////////////////////////////////////////////////////////
320 //
321 //
322 //      METHOD NAME : librpmDb::dumpState
323 //      METHOD TYPE : ostream &
324 //
325 ostream & librpmDb::dumpState( ostream & str )
326 {
327   if ( !_defaultDb ) {
328     return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
329   }
330   return str << "[" << _defaultDb << "]";
331 }
332
333 ///////////////////////////////////////////////////////////////////
334 //
335 //      CLASS NAME : librpmDb (internal database handle interface (nonstatic))
336 //
337 ///////////////////////////////////////////////////////////////////
338
339 ///////////////////////////////////////////////////////////////////
340 //
341 //
342 //      METHOD NAME : librpmDb::librpmDb
343 //      METHOD TYPE : Constructor
344 //
345 //      DESCRIPTION :
346 //
347 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
348     : _d( * new D( root_r, dbPath_r, readonly_r ) )
349 {
350 }
351
352 ///////////////////////////////////////////////////////////////////
353 //
354 //
355 //      METHOD NAME : librpmDb::~librpmDb
356 //      METHOD TYPE : Destructor
357 //
358 //      DESCRIPTION :
359 //
360 librpmDb::~librpmDb()
361 {
362   delete &_d;
363 }
364
365 ///////////////////////////////////////////////////////////////////
366 //
367 //
368 //      METHOD NAME : librpmDb::unref_to
369 //      METHOD TYPE : void
370 //
371 void librpmDb::unref_to( unsigned refCount_r ) const
372 {
373   if ( refCount_r == 1 ) {
374     dbRelease();
375   }
376 }
377
378 ///////////////////////////////////////////////////////////////////
379 //
380 //
381 //      METHOD NAME : librpmDb::root
382 //      METHOD TYPE : const Pathname &
383 //
384 const Pathname & librpmDb::root() const
385 {
386   return _d._root;
387 }
388
389 ///////////////////////////////////////////////////////////////////
390 //
391 //
392 //      METHOD NAME : librpmDb::dbPath
393 //      METHOD TYPE : const Pathname &
394 //
395 const Pathname & librpmDb::dbPath() const
396 {
397   return _d._dbPath;
398 }
399
400 ///////////////////////////////////////////////////////////////////
401 //
402 //
403 //      METHOD NAME : librpmDb::error
404 //      METHOD TYPE : PMError
405 //
406 shared_ptr<RpmException> librpmDb::error() const
407 {
408   return _d._error;
409 }
410
411 ///////////////////////////////////////////////////////////////////
412 //
413 //
414 //      METHOD NAME : librpmDb::empty
415 //      METHOD TYPE : bool
416 //
417 bool librpmDb::empty() const
418 {
419   return( valid() && ! *db_const_iterator( this ) );
420 }
421
422 ///////////////////////////////////////////////////////////////////
423 //
424 //
425 //      METHOD NAME : librpmDb::size
426 //      METHOD TYPE : unsigned
427 //
428 unsigned librpmDb::size() const
429 {
430   unsigned count = 0;
431   if ( valid() )
432     {
433       dbiIndex dbi = dbiOpen( _d._db, RPMTAG_NAME, 0 );
434       if ( dbi )
435         {
436           DBC * dbcursor = 0;
437           dbiCopen( dbi, dbi->dbi_txnid, &dbcursor, 0 );
438
439           DBT key, data;
440           memset( &key, 0, sizeof(key) );
441           memset( &data, 0, sizeof(data) );
442           while ( dbiGet( dbi, dbcursor, &key, &data, DB_NEXT ) == 0 )
443             count += data.size / dbi->dbi_jlen;
444
445           dbiCclose( dbi, dbcursor, 0 );
446           /* no need to close dbi */
447         }
448     }
449   return count;
450 }
451
452 ///////////////////////////////////////////////////////////////////
453 //
454 //
455 //      METHOD NAME : librpmDb::dont_call_it
456 //      METHOD TYPE : void *
457 //
458 void * librpmDb::dont_call_it() const
459 {
460   return _d._db;
461 }
462
463 ///////////////////////////////////////////////////////////////////
464 //
465 //
466 //      METHOD NAME : librpmDb::dumpOn
467 //      METHOD TYPE : ostream &
468 //
469 //      DESCRIPTION :
470 //
471 ostream & librpmDb::dumpOn( ostream & str ) const
472 {
473   ReferenceCounted::dumpOn( str ) << _d;
474   return str;
475 }
476
477 ///////////////////////////////////////////////////////////////////
478 //
479 //      CLASS NAME : librpmDb::DbDirInfo
480 //
481 ///////////////////////////////////////////////////////////////////
482
483 ///////////////////////////////////////////////////////////////////
484 //
485 //
486 //      METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
487 //      METHOD TYPE : Constructor
488 //
489 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
490     : _root( root_r )
491     , _dbPath( dbPath_r )
492 {
493   // check and adjust arguments
494   if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
495     ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
496   } else {
497     _dbDir   ( _root + _dbPath );
498     _dbV4    ( _dbDir.path() + "Packages" );
499     _dbV3    ( _dbDir.path() + "packages.rpm" );
500     _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
501     DBG << *this << endl;
502   }
503 }
504
505 ///////////////////////////////////////////////////////////////////
506 //
507 //
508 //      METHOD NAME : librpmDb::DbDirInfo::update
509 //      METHOD TYPE : void
510 //
511 void librpmDb::DbDirInfo::restat()
512 {
513   _dbDir();
514   _dbV4();
515   _dbV3();
516   _dbV3ToV4();
517   DBG << *this << endl;
518 }
519
520 /******************************************************************
521 **
522 **
523 **      FUNCTION NAME : operator<<
524 **      FUNCTION TYPE : std::ostream &
525 */
526 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
527 {
528   if ( obj.illegalArgs() ) {
529     str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
530   } else {
531     str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
532     str << "  Dir:    " << obj._dbDir << endl;
533     str << "  V4:     " << obj._dbV4 << endl;
534     str << "  V3:     " << obj._dbV3 << endl;
535     str << "  V3ToV4: " << obj._dbV3ToV4;
536   }
537   return str;
538 }
539
540 ///////////////////////////////////////////////////////////////////
541 //
542 //      CLASS NAME : librpmDb::db_const_iterator::D
543 /**
544  *
545  **/
546 class librpmDb::db_const_iterator::D {
547   D & operator=( const D & ); // NO ASSIGNMENT!
548   D ( const D & );            // NO COPY!
549   public:
550
551     librpmDb::constPtr     _dbptr;
552     shared_ptr<RpmException> _dberr;
553
554     RpmHeader::constPtr _hptr;
555     rpmdbMatchIterator   _mi;
556
557     D( librpmDb::constPtr dbptr_r )
558       : _dbptr( dbptr_r )
559       , _mi( 0 )
560     {
561       if ( !_dbptr ) {
562         try {
563           librpmDb::dbAccess( _dbptr );
564         }
565         catch (const RpmException & excpt_r)
566         {
567           ZYPP_CAUGHT(excpt_r);
568         }
569         if ( !_dbptr ) {
570           WAR << "No database access: " << _dberr << endl;
571         }
572       } else {
573         destroy(); // Checks whether _dbptr still valid
574       }
575     }
576
577     ~D() {
578       if ( _mi ) {
579         ::rpmdbFreeIterator( _mi );
580       }
581     }
582
583     /**
584      * Let iterator access a dbindex file. Call @ref advance to access the
585      * 1st element (if present).
586      **/
587     bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
588       destroy();
589       if ( ! _dbptr )
590         return false;
591       _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
592       return _mi;
593     }
594
595     /**
596      * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
597      * Always returns false.
598      **/
599     bool destroy() {
600       if ( _mi ) {
601         _mi = ::rpmdbFreeIterator( _mi );
602         _hptr = 0;
603       }
604       if ( _dbptr && _dbptr->error() ) {
605         _dberr = _dbptr->error();
606         WAR << "Lost database access: " << _dberr << endl;
607         _dbptr = 0;
608       }
609       return false;
610     }
611
612     /**
613      * Advance to the first/next header in iterator. Destroys iterator if
614      * no more headers available.
615      **/
616     bool advance() {
617       if ( !_mi )
618         return false;
619       Header h = ::rpmdbNextIterator( _mi );
620       if ( ! h ) {
621         destroy();
622         return false;
623       }
624       _hptr = new RpmHeader( h );
625       return true;
626     }
627
628     /**
629      * Access a dbindex file and advance to the 1st header.
630      **/
631     bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
632       if ( ! create( rpmtag, keyp, keylen ) )
633         return false;
634       return advance();
635     }
636
637     /**
638      * Create an itertator that contains the database entry located at
639      * off_r, and advance to the 1st header.
640      **/
641     bool set( int off_r ) {
642       if ( ! create( RPMDBI_PACKAGES ) )
643         return false;
644 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
645       ::rpmdbAppendIterator( _mi, &off_r, 1 );
646       return advance();
647     }
648
649     unsigned offset() {
650       return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
651     }
652
653     int size() {
654       if ( !_mi )
655         return 0;
656       int ret = ::rpmdbGetIteratorCount( _mi );
657 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
658       return( ret ? ret : -1 ); // -1: sequential access
659     }
660 };
661
662 ///////////////////////////////////////////////////////////////////
663
664 ///////////////////////////////////////////////////////////////////
665 //
666 //      CLASS NAME : librpmDb::Ptr::db_const_iterator
667 //
668 ///////////////////////////////////////////////////////////////////
669
670 ///////////////////////////////////////////////////////////////////
671 //
672 //
673 //      METHOD NAME : librpmDb::db_const_iterator::db_iterator
674 //      METHOD TYPE : Constructor
675 //
676 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
677     : _d( * new D( dbptr_r ) )
678 {
679   findAll();
680 }
681
682 ///////////////////////////////////////////////////////////////////
683 //
684 //
685 //      METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
686 //      METHOD TYPE : Destructor
687 //
688 librpmDb::db_const_iterator::~db_const_iterator()
689 {
690   delete &_d;
691 }
692
693 ///////////////////////////////////////////////////////////////////
694 //
695 //
696 //      METHOD NAME : librpmDb::db_const_iterator::operator++
697 //      METHOD TYPE : void
698 //
699 void librpmDb::db_const_iterator::operator++()
700 {
701   _d.advance();
702 }
703
704 ///////////////////////////////////////////////////////////////////
705 //
706 //
707 //      METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
708 //      METHOD TYPE : unsigned
709 //
710 unsigned librpmDb::db_const_iterator::dbHdrNum() const
711 {
712   return _d.offset();
713 }
714
715 ///////////////////////////////////////////////////////////////////
716 //
717 //
718 //      METHOD NAME : librpmDb::db_const_iterator::operator*
719 //      METHOD TYPE : const RpmHeader::constPtr &
720 //
721 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
722 {
723   return _d._hptr;
724 }
725
726 ///////////////////////////////////////////////////////////////////
727 //
728 //
729 //      METHOD NAME : librpmDb::db_const_iterator::dbError
730 //      METHOD TYPE : PMError
731 //
732 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
733 {
734   if ( _d._dbptr )
735     return _d._dbptr->error();
736
737   return _d._dberr;
738 }
739
740 /******************************************************************
741 **
742 **
743 **      FUNCTION NAME : operator<<
744 **      FUNCTION TYPE : ostream &
745 */
746 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
747 {
748   str << "db_const_iterator(" << obj._d._dbptr
749     << " Size:" << obj._d.size()
750       << " HdrNum:" << obj._d.offset()
751         << ")";
752   return str;
753 }
754
755 ///////////////////////////////////////////////////////////////////
756 //
757 //
758 //      METHOD NAME : librpmDb::db_const_iterator::findAll
759 //      METHOD TYPE : bool
760 //
761 bool librpmDb::db_const_iterator::findAll()
762 {
763   return _d.init( RPMDBI_PACKAGES );
764 }
765
766 ///////////////////////////////////////////////////////////////////
767 //
768 //
769 //      METHOD NAME : librpmDb::db_const_iterator::findByFile
770 //      METHOD TYPE : bool
771 //
772 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
773 {
774   return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
775 }
776
777 ///////////////////////////////////////////////////////////////////
778 //
779 //
780 //      METHOD NAME : librpmDb::db_const_iterator::findByProvides
781 //      METHOD TYPE : bool
782 //
783 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
784 {
785   return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
786 }
787
788 ///////////////////////////////////////////////////////////////////
789 //
790 //
791 //      METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
792 //      METHOD TYPE : bool
793 //
794 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
795 {
796   return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
797 }
798
799 ///////////////////////////////////////////////////////////////////
800 //
801 //
802 //      METHOD NAME : librpmDb::db_const_iterator::findByConflicts
803 //      METHOD TYPE : bool
804 //
805 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
806 {
807   return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
808 }
809
810 ///////////////////////////////////////////////////////////////////
811 //
812 //
813 //      METHOD NAME : librpmDb::findByName
814 //      METHOD TYPE : bool
815 //
816 bool librpmDb::db_const_iterator::findByName( const string & name_r )
817 {
818   return _d.init( RPMTAG_NAME, name_r.c_str() );
819 }
820
821 ///////////////////////////////////////////////////////////////////
822 //
823 //
824 //      METHOD NAME : librpmDb::db_const_iterator::findPackage
825 //      METHOD TYPE : bool
826 //
827 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
828 {
829   if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
830     return false;
831
832   if ( _d.size() == 1 )
833     return true;
834
835   // check installtime on multiple entries
836   int match    = 0;
837   time_t itime = 0;
838   for ( ; operator*(); operator++() ) {
839     if ( operator*()->tag_installtime() > itime ) {
840       match = _d.offset();
841       itime = operator*()->tag_installtime();
842     }
843   }
844
845   return _d.set( match );
846 }
847
848 ///////////////////////////////////////////////////////////////////
849 //
850 //
851 //      METHOD NAME : librpmDb::db_const_iterator::findPackage
852 //      METHOD TYPE : bool
853 //
854 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
855 {
856   if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
857     return false;
858
859   for ( ; operator*(); operator++() ) {
860     if ( ed_r == operator*()->tag_edition() ) {
861       int match = _d.offset();
862       return _d.set( match );
863     }
864   }
865
866   return _d.destroy();
867 }
868
869 ///////////////////////////////////////////////////////////////////
870 //
871 //
872 //      METHOD NAME : librpmDb::db_const_iterator::findPackage
873 //      METHOD TYPE : bool
874 //
875 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
876 {
877   if ( ! which_r )
878     return _d.destroy();
879
880   return findPackage( which_r->name(), which_r->edition() );
881 }
882
883     } // namespace rpm
884   } // namespace target
885 } // namespace zypp