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