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