Detect and compile with rpm 4.7 (bnc #444211)
[platform/upstream/libzypp.git] / zypp / target / rpm / RpmHeader.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/RpmHeader.cc
10  *
11 */
12 #include "librpm.h"
13 #ifndef _RPM_4_4_COMPAT
14 #include <rpm/ugid.h>
15 inline uid_t getUidS(const char * uname) { uid_t tmp; return ::unameToUid( uname, &tmp ); }
16 inline gid_t getGidS(const char * gname) { gid_t tmp; return ::gnameToGid( gname, &tmp ); }
17 #else
18 #include <rpm/rpmbuild.h>
19 #endif
20
21 #include <iostream>
22 #include <map>
23 #include <set>
24 #include <vector>
25
26 #include "zypp/base/Easy.h"
27 #include "zypp/base/Logger.h"
28 #include "zypp/base/Exception.h"
29
30 #include "zypp/target/rpm/RpmHeader.h"
31 #include "zypp/Package.h"
32 #include "zypp/PathInfo.h"
33
34 using std::endl;
35
36 namespace zypp
37 {
38 namespace target
39 {
40 namespace rpm
41 {
42
43 ///////////////////////////////////////////////////////////////////
44
45 ///////////////////////////////////////////////////////////////////
46 //
47 //
48 //        METHOD NAME : RpmHeader::RpmHeader
49 //        METHOD TYPE : Constructor
50 //
51 //        DESCRIPTION :
52 //
53 RpmHeader::RpmHeader( Header h_r )
54     : BinHeader( h_r )
55 {}
56
57 ///////////////////////////////////////////////////////////////////
58 //
59 //
60 //        METHOD NAME : RpmHeader::RpmHeader
61 //        METHOD TYPE : Constructor
62 //
63 RpmHeader::RpmHeader( BinHeader::Ptr & rhs )
64     : BinHeader( rhs )
65 {}
66
67 ///////////////////////////////////////////////////////////////////
68 //
69 //
70 //        METHOD NAME : RpmHeader::~RpmHeader
71 //        METHOD TYPE : Destructor
72 //
73 //        DESCRIPTION :
74 //
75 RpmHeader::~RpmHeader()
76 {}
77
78 ///////////////////////////////////////////////////////////////////
79 //
80 //
81 //        METHOD NAME : RpmHeader::readPackage
82 //        METHOD TYPE : constRpmHeaderPtr
83 //
84 RpmHeader::constPtr RpmHeader::readPackage( const Pathname & path_r,
85                                             VERIFICATION verification_r )
86 {
87   PathInfo file( path_r );
88   if ( ! file.isFile() )
89   {
90     ERR << "Not a file: " << file << endl;
91     return (RpmHeader*)0;
92   }
93
94   FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
95   if ( fd == 0 || ::Ferror(fd) )
96   {
97     ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
98     if ( fd )
99       ::Fclose( fd );
100     return (RpmHeader*)0;
101   }
102
103   rpmts ts = ::rpmtsCreate();
104   unsigned vsflag = RPMVSF_DEFAULT;
105   if ( verification_r & NODIGEST )
106     vsflag |= _RPMVSF_NODIGESTS;
107   if ( verification_r & NOSIGNATURE )
108     vsflag |= _RPMVSF_NOSIGNATURES;
109   ::rpmtsSetVSFlags( ts, rpmVSFlags(vsflag) );
110
111   Header nh = 0;
112   int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), &nh );
113
114   ts = ::rpmtsFree(ts);
115
116   ::Fclose( fd );
117
118   if ( ! nh )
119   {
120     WAR << "Error reading header from " << path_r << " error(" << res << ")" << endl;
121     return (RpmHeader*)0;
122   }
123
124   RpmHeader::constPtr h( new RpmHeader( nh ) );
125   headerFree( nh ); // clear the reference set in ReadPackageFile
126
127   MIL << h << " from " << path_r << endl;
128   return h;
129 }
130
131 ///////////////////////////////////////////////////////////////////
132 //
133 //
134 //        METHOD NAME : RpmHeader::dumpOn
135 //        METHOD TYPE : std::ostream &
136 //
137 //        DESCRIPTION :
138 //
139 std::ostream & RpmHeader::dumpOn( std::ostream & str ) const
140 {
141   return BinHeader::dumpOn( str ) << '{' << tag_name() << "-"
142          << (tag_epoch()==0?"":(tag_epoch()+":"))
143          << tag_version()
144          << (tag_release().empty()?"":(std::string("-")+tag_release()))
145          << ( isSrc() ? ".src}" : "}");
146 }
147
148
149 ///////////////////////////////////////////////////////////////////
150 //
151 //
152 //        METHOD NAME : RpmHeader::isSrc
153 //        METHOD TYPE : bool
154 //
155 bool RpmHeader::isSrc() const
156 {
157   return has_tag( RPMTAG_SOURCEPACKAGE );
158 }
159
160 ///////////////////////////////////////////////////////////////////
161 //
162 //
163 //        METHOD NAME : RpmHeader::tag_name
164 //        METHOD TYPE : std::string
165 //
166 //        DESCRIPTION :
167 //
168 std::string RpmHeader::tag_name() const
169 {
170   return string_val( RPMTAG_NAME );
171 }
172
173 ///////////////////////////////////////////////////////////////////
174 //
175 //
176 //        METHOD NAME : RpmHeader::tag_epoch
177 //        METHOD TYPE : Edition::epoch_t
178 //
179 //        DESCRIPTION :
180 //
181 Edition::epoch_t RpmHeader::tag_epoch() const
182 {
183   return int_val ( RPMTAG_EPOCH );
184 }
185
186 ///////////////////////////////////////////////////////////////////
187 //
188 //
189 //        METHOD NAME : RpmHeader::tag_version
190 //        METHOD TYPE : std::string
191 //
192 //        DESCRIPTION :
193 //
194 std::string RpmHeader::tag_version() const
195 {
196   return string_val ( RPMTAG_VERSION );
197 }
198
199 ///////////////////////////////////////////////////////////////////
200 //
201 //
202 //        METHOD NAME : RpmHeader::tag_release
203 //        METHOD TYPE : std::string
204 //
205 //        DESCRIPTION :
206 //
207 std::string RpmHeader::tag_release() const
208 {
209   return string_val( RPMTAG_RELEASE );
210 }
211
212 ///////////////////////////////////////////////////////////////////
213 //
214 //
215 //        METHOD NAME : RpmHeader::tag_edition
216 //        METHOD TYPE : Edition
217 //
218 //        DESCRIPTION :
219 //
220 Edition RpmHeader::tag_edition () const
221 {
222   return Edition( tag_version(), tag_release(), tag_epoch() );
223 }
224
225 ///////////////////////////////////////////////////////////////////
226 //
227 //
228 //        METHOD NAME : RpmHeader::tag_arch
229 //        METHOD TYPE : Arch
230 //
231 //        DESCRIPTION :
232 //
233 Arch RpmHeader::tag_arch() const
234 {
235   return Arch( string_val( RPMTAG_ARCH ) );
236 }
237
238 ///////////////////////////////////////////////////////////////////
239 //
240 //
241 //        METHOD NAME : RpmHeader::tag_installtime
242 //        METHOD TYPE : Date
243 //
244 //        DESCRIPTION :
245 //
246 Date RpmHeader::tag_installtime() const
247 {
248   return int_val( RPMTAG_INSTALLTIME );
249 }
250
251 ///////////////////////////////////////////////////////////////////
252 //
253 //
254 //        METHOD NAME : RpmHeader::tag_buildtime
255 //        METHOD TYPE : Date
256 //
257 //        DESCRIPTION :
258 //
259 Date RpmHeader::tag_buildtime() const
260 {
261   return int_val( RPMTAG_BUILDTIME );
262 }
263 #warning CHECK IF FILE REQUIRES HANDLING IS OBSOLETE
264 ///////////////////////////////////////////////////////////////////
265 //
266 //
267 //        METHOD NAME : RpmHeader::PkgRelList_val
268 //        METHOD TYPE : CapabilitySet
269 //
270 //        DESCRIPTION :
271 //
272 CapabilitySet RpmHeader::PkgRelList_val( tag tag_r, bool pre, std::set<std::string> * freq_r ) const
273   {
274     CapabilitySet ret;
275
276     rpmTag  kindFlags   = rpmTag(0);
277     rpmTag  kindVersion = rpmTag(0);
278
279     switch ( tag_r )
280     {
281     case RPMTAG_REQUIRENAME:
282       kindFlags   = RPMTAG_REQUIREFLAGS;
283       kindVersion = RPMTAG_REQUIREVERSION;
284       break;
285     case RPMTAG_PROVIDENAME:
286       kindFlags   = RPMTAG_PROVIDEFLAGS;
287       kindVersion = RPMTAG_PROVIDEVERSION;
288       break;
289     case RPMTAG_OBSOLETENAME:
290       kindFlags   = RPMTAG_OBSOLETEFLAGS;
291       kindVersion = RPMTAG_OBSOLETEVERSION;
292       break;
293     case RPMTAG_CONFLICTNAME:
294       kindFlags   = RPMTAG_CONFLICTFLAGS;
295       kindVersion = RPMTAG_CONFLICTVERSION;
296       break;
297     case RPMTAG_ENHANCESNAME:
298       kindFlags   = RPMTAG_ENHANCESFLAGS;
299       kindVersion = RPMTAG_ENHANCESVERSION;
300       break;
301     case RPMTAG_SUGGESTSNAME:
302       kindFlags   = RPMTAG_SUGGESTSFLAGS;
303       kindVersion = RPMTAG_SUGGESTSVERSION;
304       break;
305     default:
306       INT << "Illegal RPMTAG_dependencyNAME " << tag_r << endl;
307       return ret;
308       break;
309     }
310
311     stringList names;
312     unsigned count = string_list( tag_r, names );
313     if ( !count )
314       return ret;
315
316     intList  flags;
317     int_list( kindFlags, flags );
318
319     stringList versions;
320     string_list( kindVersion, versions );
321
322     for ( unsigned i = 0; i < count; ++i )
323     {
324
325       std::string n( names[i] );
326
327       Rel op = Rel::ANY;
328       int32_t f = flags[i];
329       std::string v = versions[i];
330
331       if ( n[0] == '/' )
332       {
333         if ( freq_r )
334         {
335           freq_r->insert( n );
336         }
337       }
338       else
339       {
340         if ( v.size() )
341         {
342           switch ( f & RPMSENSE_SENSEMASK )
343           {
344           case RPMSENSE_LESS:
345             op = Rel::LT;
346             break;
347           case RPMSENSE_LESS|RPMSENSE_EQUAL:
348             op = Rel::LE;
349             break;
350           case RPMSENSE_GREATER:
351             op = Rel::GT;
352             break;
353           case RPMSENSE_GREATER|RPMSENSE_EQUAL:
354             op = Rel::GE;
355             break;
356           case RPMSENSE_EQUAL:
357             op = Rel::EQ;
358             break;
359           }
360         }
361       }
362       if ((pre && (f & RPMSENSE_PREREQ))
363           || ((! pre) && !(f & RPMSENSE_PREREQ)))
364       {
365         try
366         {
367           ret.insert( Capability( n, op, Edition(v) ) );
368         }
369         catch (Exception & excpt_r)
370         {
371           ZYPP_CAUGHT(excpt_r);
372           WAR << "Invalid capability: " << n << " " << op << " "
373           << v << endl;
374         }
375       }
376     }
377
378     return ret;
379   }
380
381 ///////////////////////////////////////////////////////////////////
382 //
383 //
384 //        METHOD NAME : RpmHeader::tag_provides
385 //        METHOD TYPE : CapabilitySet
386 //
387 //        DESCRIPTION :
388 //
389 CapabilitySet RpmHeader::tag_provides( std::set<std::string> * freq_r ) const
390   {
391     return PkgRelList_val( RPMTAG_PROVIDENAME, false, freq_r );
392   }
393
394 ///////////////////////////////////////////////////////////////////
395 //
396 //
397 //        METHOD NAME : RpmHeader::tag_requires
398 //        METHOD TYPE : CapabilitySet
399 //
400 //        DESCRIPTION :
401 //
402 CapabilitySet RpmHeader::tag_requires( std::set<std::string> * freq_r ) const
403   {
404     return PkgRelList_val( RPMTAG_REQUIRENAME, false, freq_r );
405   }
406
407 ///////////////////////////////////////////////////////////////////
408 //
409 //
410 //        METHOD NAME : RpmHeader::tag_requires
411 //        METHOD TYPE : CapabilitySet
412 //
413 //        DESCRIPTION :
414 //
415 CapabilitySet RpmHeader::tag_prerequires( std::set<std::string> * freq_r ) const
416   {
417     return PkgRelList_val( RPMTAG_REQUIRENAME, true, freq_r );
418   }
419
420 ///////////////////////////////////////////////////////////////////
421 //
422 //
423 //        METHOD NAME : RpmHeader::tag_conflicts
424 //        METHOD TYPE : CapabilitySet
425 //
426 //        DESCRIPTION :
427 //
428 CapabilitySet RpmHeader::tag_conflicts( std::set<std::string> * freq_r ) const
429   {
430     return PkgRelList_val( RPMTAG_CONFLICTNAME, false, freq_r );
431   }
432
433 ///////////////////////////////////////////////////////////////////
434 //
435 //
436 //        METHOD NAME : RpmHeader::tag_obsoletes
437 //        METHOD TYPE : CapabilitySet
438 //
439 //        DESCRIPTION :
440 //
441 CapabilitySet RpmHeader::tag_obsoletes( std::set<std::string> * freq_r ) const
442   {
443     return PkgRelList_val( RPMTAG_OBSOLETENAME, false, freq_r );
444   }
445
446 ///////////////////////////////////////////////////////////////////
447 //
448 //
449 //        METHOD NAME : RpmHeader::tag_enhances
450 //        METHOD TYPE : CapabilitySet
451 //
452 //        DESCRIPTION :
453 //
454 CapabilitySet RpmHeader::tag_enhances( std::set<std::string> * freq_r ) const
455   {
456     return PkgRelList_val( RPMTAG_ENHANCESNAME, false, freq_r );
457   }
458
459 ///////////////////////////////////////////////////////////////////
460 //
461 //
462 //        METHOD NAME : RpmHeader::tag_suggests
463 //        METHOD TYPE : CapabilitySet
464 //
465 //        DESCRIPTION :
466 //
467 CapabilitySet RpmHeader::tag_suggests( std::set<std::string> * freq_r ) const
468   {
469     return PkgRelList_val( RPMTAG_SUGGESTSNAME, false, freq_r );
470   }
471
472 ///////////////////////////////////////////////////////////////////
473 //
474 //
475 //        METHOD NAME : RpmHeader::tag_size
476 //        METHOD TYPE : ByteCount
477 //
478 //        DESCRIPTION :
479 //
480 ByteCount RpmHeader::tag_size() const
481 {
482   return int_val( RPMTAG_SIZE );
483 }
484
485 ///////////////////////////////////////////////////////////////////
486 //
487 //
488 //        METHOD NAME : RpmHeader::tag_archivesize
489 //        METHOD TYPE : ByteCount
490 //
491 //        DESCRIPTION :
492 //
493 ByteCount RpmHeader::tag_archivesize() const
494 {
495   return int_val( RPMTAG_ARCHIVESIZE );
496 }
497
498 ///////////////////////////////////////////////////////////////////
499 //
500 //
501 //        METHOD NAME : RpmHeader::tag_summary
502 //        METHOD TYPE : std::string
503 //
504 //        DESCRIPTION :
505 //
506 std::string RpmHeader::tag_summary() const
507 {
508   return string_val( RPMTAG_SUMMARY );
509 }
510
511 ///////////////////////////////////////////////////////////////////
512 //
513 //
514 //        METHOD NAME : RpmHeader::tag_description
515 //        METHOD TYPE : std::string
516 //
517 //        DESCRIPTION :
518 //
519 std::string RpmHeader::tag_description() const
520 {
521   return string_val( RPMTAG_DESCRIPTION );
522 }
523
524 ///////////////////////////////////////////////////////////////////
525 //
526 //
527 //        METHOD NAME : RpmHeader::tag_group
528 //        METHOD TYPE : std::string
529 //
530 //        DESCRIPTION :
531 //
532 std::string RpmHeader::tag_group() const
533 {
534   return string_val( RPMTAG_GROUP );
535 }
536
537 ///////////////////////////////////////////////////////////////////
538 //
539 //
540 //        METHOD NAME : RpmHeader::tag_vendor
541 //        METHOD TYPE : std::string
542 //
543 //        DESCRIPTION :
544 //
545 std::string RpmHeader::tag_vendor() const
546 {
547   return string_val( RPMTAG_VENDOR );
548 }
549
550 ///////////////////////////////////////////////////////////////////
551 //
552 //
553 //        METHOD NAME : RpmHeader::tag_distribution
554 //        METHOD TYPE : std::string
555 //
556 //        DESCRIPTION :
557 //
558 std::string RpmHeader::tag_distribution() const
559 {
560   return string_val( RPMTAG_DISTRIBUTION );
561 }
562
563 ///////////////////////////////////////////////////////////////////
564 //
565 //
566 //        METHOD NAME : RpmHeader::tag_license
567 //        METHOD TYPE : std::string
568 //
569 //        DESCRIPTION :
570 //
571 std::string RpmHeader::tag_license() const
572 {
573   return string_val( RPMTAG_LICENSE );
574 }
575
576 ///////////////////////////////////////////////////////////////////
577 //
578 //
579 //        METHOD NAME : RpmHeader::tag_buildhost
580 //        METHOD TYPE : std::string
581 //
582 //        DESCRIPTION :
583 //
584 std::string RpmHeader::tag_buildhost() const
585 {
586   return string_val( RPMTAG_BUILDHOST );
587 }
588
589 ///////////////////////////////////////////////////////////////////
590 //
591 //
592 //        METHOD NAME : RpmHeader::tag_packager
593 //        METHOD TYPE : std::string
594 //
595 //        DESCRIPTION :
596 //
597 std::string RpmHeader::tag_packager() const
598 {
599   return string_val( RPMTAG_PACKAGER );
600 }
601
602 ///////////////////////////////////////////////////////////////////
603 //
604 //
605 //        METHOD NAME : RpmHeader::tag_url
606 //        METHOD TYPE : std::string
607 //
608 //        DESCRIPTION :
609 //
610 std::string RpmHeader::tag_url() const
611 {
612   return string_val( RPMTAG_URL );
613 }
614
615 ///////////////////////////////////////////////////////////////////
616 //
617 //
618 //        METHOD NAME : RpmHeader::tag_os
619 //        METHOD TYPE : std::string
620 //
621 //        DESCRIPTION :
622 //
623 std::string RpmHeader::tag_os() const
624 {
625   return string_val( RPMTAG_OS );
626 }
627
628 ///////////////////////////////////////////////////////////////////
629 //
630 //
631 //        METHOD NAME : RpmHeader::tag_prein
632 //        METHOD TYPE : std::string
633 //
634 //        DESCRIPTION :
635 //
636 std::string RpmHeader::tag_prein() const
637 {
638   return string_val( RPMTAG_PREIN );
639 }
640
641 ///////////////////////////////////////////////////////////////////
642 //
643 //
644 //        METHOD NAME : RpmHeader::tag_postin
645 //        METHOD TYPE : std::string
646 //
647 //        DESCRIPTION :
648 //
649 std::string RpmHeader::tag_postin() const
650 {
651   return string_val( RPMTAG_POSTIN );
652 }
653
654 ///////////////////////////////////////////////////////////////////
655 //
656 //
657 //        METHOD NAME : RpmHeader::tag_preun
658 //        METHOD TYPE : std::string
659 //
660 //        DESCRIPTION :
661 //
662 std::string RpmHeader::tag_preun() const
663 {
664   return string_val( RPMTAG_PREUN );
665 }
666
667 ///////////////////////////////////////////////////////////////////
668 //
669 //
670 //        METHOD NAME : RpmHeader::tag_postun
671 //        METHOD TYPE : std::string
672 //
673 //        DESCRIPTION :
674 //
675 std::string RpmHeader::tag_postun() const
676 {
677   return string_val( RPMTAG_POSTUN );
678 }
679
680 ///////////////////////////////////////////////////////////////////
681 //
682 //
683 //        METHOD NAME : RpmHeader::tag_sourcerpm
684 //        METHOD TYPE : std::string
685 //
686 //        DESCRIPTION :
687 //
688 std::string RpmHeader::tag_sourcerpm() const
689 {
690   return string_val( RPMTAG_SOURCERPM );
691 }
692
693 ///////////////////////////////////////////////////////////////////
694 //
695 //
696 //        METHOD NAME : RpmHeader::tag_filenames
697 //        METHOD TYPE : std::list<std::string>
698 //
699 //        DESCRIPTION :
700 //
701 std::list<std::string> RpmHeader::tag_filenames() const
702 {
703   std::list<std::string> ret;
704
705   stringList basenames;
706   if ( string_list( RPMTAG_BASENAMES, basenames ) )
707   {
708     stringList dirnames;
709     string_list( RPMTAG_DIRNAMES, dirnames );
710     intList  dirindexes;
711     int_list( RPMTAG_DIRINDEXES, dirindexes );
712     for ( unsigned i = 0; i < basenames.size(); ++ i )
713     {
714       ret.push_back( dirnames[dirindexes[i]] + basenames[i] );
715     }
716   }
717
718   return ret;
719 }
720
721 ///////////////////////////////////////////////////////////////////
722 //
723 //
724 //        METHOD NAME : RpmHeader::tag_fileinfos
725 //        METHOD TYPE : std::list<FileInfo>
726 //
727 //        DESCRIPTION :
728 //
729 std::list<FileInfo> RpmHeader::tag_fileinfos() const
730 {
731   std::list<FileInfo> ret;
732
733   stringList basenames;
734   if ( string_list( RPMTAG_BASENAMES, basenames ) )
735   {
736     stringList dirnames;
737     string_list( RPMTAG_DIRNAMES, dirnames );
738     intList  dirindexes;
739     int_list( RPMTAG_DIRINDEXES, dirindexes );
740     intList filesizes;
741     int_list( RPMTAG_FILESIZES, filesizes );
742     stringList md5sums;
743     string_list( RPMTAG_FILEMD5S, md5sums );
744     stringList usernames;
745     string_list( RPMTAG_FILEUSERNAME, usernames );
746     stringList groupnames;
747     string_list( RPMTAG_FILEGROUPNAME, groupnames );
748     intList uids;
749     int_list( RPMTAG_FILEUIDS, uids );
750     intList gids;
751     int_list( RPMTAG_FILEGIDS, gids );
752     intList filemodes;
753     int_list( RPMTAG_FILEMODES, filemodes );
754     intList filemtimes;
755     int_list( RPMTAG_FILEMTIMES, filemtimes );
756     intList fileflags;
757     int_list( RPMTAG_FILEFLAGS, fileflags );
758     stringList filelinks;
759     string_list( RPMTAG_FILELINKTOS, filelinks );
760
761     for ( unsigned i = 0; i < basenames.size(); ++ i )
762     {
763       uid_t uid;
764       if (uids.empty())
765       {
766         uid = getUidS( usernames[i].c_str() );
767       }
768       else
769       {
770         uid =uids[i];
771       }
772
773       gid_t gid;
774       if (gids.empty())
775       {
776         gid = getGidS( groupnames[i].c_str() );
777       }
778       else
779       {
780         gid = gids[i];
781       }
782
783       FileInfo info = {
784                         dirnames[dirindexes[i]] + basenames[i],
785                         filesizes[i],
786                         md5sums[i],
787                         uid,
788                         gid,
789                         filemodes[i],
790                         filemtimes[i],
791                         fileflags[i] & RPMFILE_GHOST,
792                         filelinks[i]
793                       };
794
795       ret.push_back( info );
796     }
797   }
798
799   return ret;
800 }
801
802 ///////////////////////////////////////////////////////////////////
803 //
804 //
805 //        METHOD NAME : RpmHeader::tag_changelog
806 //        METHOD TYPE : Changelog
807 //
808 //        DESCRIPTION :
809 //
810 Changelog RpmHeader::tag_changelog() const
811 {
812   Changelog ret;
813
814   intList times;
815   if ( int_list( RPMTAG_CHANGELOGTIME, times ) )
816   {
817     stringList names;
818     string_list( RPMTAG_CHANGELOGNAME, names );
819     stringList texts;
820     string_list( RPMTAG_CHANGELOGTEXT, texts );
821     for ( unsigned i = 0; i < times.size(); ++ i )
822     {
823       ret.push_back( ChangelogEntry( times[i], names[i], texts[i] ) );
824     }
825   }
826
827   return ret;
828 }
829
830 ///////////////////////////////////////////////////////////////////
831 //
832 //
833 //        METHOD NAME : RpmHeader::tag_du
834 //        METHOD TYPE : PkgDu &
835 //
836 //        DESCRIPTION :
837 //
838 DiskUsage & RpmHeader::tag_du( DiskUsage & dudata_r ) const
839 {
840   dudata_r.clear();
841   stringList basenames;
842   if ( string_list( RPMTAG_BASENAMES, basenames ) )
843   {
844     stringList dirnames;
845     string_list( RPMTAG_DIRNAMES, dirnames );
846     intList dirindexes;
847     int_list( RPMTAG_DIRINDEXES, dirindexes );
848
849     intList filedevices;
850     int_list( RPMTAG_FILEDEVICES, filedevices );
851     intList fileinodes;
852     int_list( RPMTAG_FILEINODES, fileinodes );
853     intList filesizes;
854     int_list( RPMTAG_FILESIZES, filesizes );
855     intList filemodes;
856     int_list( RPMTAG_FILEMODES, filemodes );
857
858     ///////////////////////////////////////////////////////////////////
859     // Create and collect Entries by index. devino_cache is used to
860     // filter out hardliks ( different name but same device and inode ).
861     ///////////////////////////////////////////////////////////////////
862     filesystem::DevInoCache trace;
863     std::vector<DiskUsage::Entry> entries;
864     entries.resize( dirnames.size() );
865     for ( unsigned i = 0; i < dirnames.size(); ++i )
866     {
867       entries[i] = DiskUsage::Entry( dirnames[i] );
868
869       // cut off deeper directory levels in DiskUsage::Entry
870       unsigned level             = 3; // number of '/' incl. a trailing one
871       std::string::size_type pos = 0; // we know rpm stores absolute pathnames
872       while ( --level && pos != std::string::npos )
873       {
874         pos = entries[i].path.find( "/", pos+1 );
875       }
876       if ( pos != std::string::npos )
877       {
878         entries[i].path.erase( pos+1 );
879       }
880     }
881
882     for ( unsigned i = 0; i < basenames.size(); ++ i )
883     {
884       filesystem::StatMode mode( filemodes[i] );
885       if ( mode.isFile() )
886       {
887         if ( trace.insert( filedevices[i], fileinodes[i] ) )
888         {
889           // Count full 1K blocks
890           entries[dirindexes[i]]._size += ByteCount( filesizes[i] ).blocks( ByteCount::K );
891           ++(entries[dirindexes[i]]._files);
892         }
893         // else: hardlink; already counted this device/inode
894       }
895     }
896
897     ///////////////////////////////////////////////////////////////////
898     // Collect all enties. We first unify the duplicate entries that
899     // were created by cutting off deeper levels. Then the size of each
900     // directory must also be added to each of it's parent directories.
901     ///////////////////////////////////////////////////////////////////
902     DiskUsage tmpdata;
903     for ( unsigned i = 0; i < entries.size(); ++i )
904     {
905       if ( entries[i]._size )
906         tmpdata.add( entries[i] );
907     }
908
909     for_( it, tmpdata.begin(), tmpdata.end() )
910     {
911       DiskUsage::Entry ent( *it );
912
913       do {
914         dudata_r.add( ent );
915         if ( ent.path.size() <= 1 ) // "" or "/"
916           break;
917
918         // set path to parent dir. Note that DiskUsage::Entry
919         // has leading and trailing '/' on pathnmes.
920         std::string::size_type rstart = ent.path.size() - 2;           // trailing '/' !
921         std::string::size_type lpos   = ent.path.rfind( '/', rstart ); // one but last '/'
922         if ( lpos == std::string::npos )
923           break;
924
925         ent.path.erase( lpos + 1 );
926       } while( true );
927     }
928   }
929   return dudata_r;
930 }
931
932 } // namespace rpm
933 } // namespace target
934 } // namespace zypp