1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/RpmHeader.cc
16 ////////////////////////////////////////////////////////////////////
17 // unameToUid and gnameToGid are shamelessly stolen from rpm-4.4.
18 // (rpmio/ugid.c) Those functions were dropped in RPM_4_7
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 :-( */
31 int unameToUid(const char * thisUname, uid_t * uid)
33 /*@only@*/ static char * lastUname = NULL;
34 static size_t lastUnameLen = 0;
35 static size_t lastUnameAlloced;
37 struct passwd * pwent;
43 } else if (strcmp(thisUname, "root") == 0) {
50 thisUnameLen = strlen(thisUname);
51 if (lastUname == NULL || thisUnameLen != lastUnameLen ||
52 strcmp(thisUname, lastUname) != 0)
54 if (lastUnameAlloced < thisUnameLen + 1) {
55 lastUnameAlloced = thisUnameLen + 10;
56 lastUname = (char *)realloc(lastUname, lastUnameAlloced); /* XXX memory leak */
59 strcpy(lastUname, thisUname);
62 pwent = getpwnam(thisUname);
64 /*@-internalglobs@*/ /* FIX: shrug */
67 pwent = getpwnam(thisUname);
68 if (pwent == NULL) return -1;
71 lastUid = pwent->pw_uid;
81 int gnameToGid(const char * thisGname, gid_t * gid)
83 /*@only@*/ static char * lastGname = NULL;
84 static size_t lastGnameLen = 0;
85 static size_t lastGnameAlloced;
90 if (thisGname == NULL) {
93 } else if (strcmp(thisGname, "root") == 0) {
100 thisGnameLen = strlen(thisGname);
101 if (lastGname == NULL || thisGnameLen != lastGnameLen ||
102 strcmp(thisGname, lastGname) != 0)
104 if (lastGnameAlloced < thisGnameLen + 1) {
105 lastGnameAlloced = thisGnameLen + 10;
106 lastGname = (char *)realloc(lastGname, lastGnameAlloced); /* XXX memory leak */
109 strcpy(lastGname, thisGname);
112 grent = getgrnam(thisGname);
114 /*@-internalglobs@*/ /* FIX: shrug */
117 grent = getgrnam(thisGname);
119 /* XXX The filesystem package needs group/lock w/o getgrnam. */
120 if (strcmp(thisGname, "lock") == 0) {
126 if (strcmp(thisGname, "mail") == 0) {
135 lastGid = grent->gr_gid;
144 ////////////////////////////////////////////////////////////////////
152 #include "zypp/base/Easy.h"
153 #include "zypp/base/Logger.h"
154 #include "zypp/base/Exception.h"
156 #include "zypp/target/rpm/librpmDb.h"
157 #include "zypp/target/rpm/RpmHeader.h"
158 #include "zypp/Package.h"
159 #include "zypp/PathInfo.h"
170 ///////////////////////////////////////////////////////////////////
172 ///////////////////////////////////////////////////////////////////
175 // METHOD NAME : RpmHeader::RpmHeader
176 // METHOD TYPE : Constructor
180 RpmHeader::RpmHeader( Header h_r )
184 ///////////////////////////////////////////////////////////////////
187 // METHOD NAME : RpmHeader::RpmHeader
188 // METHOD TYPE : Constructor
190 RpmHeader::RpmHeader( BinHeader::Ptr & rhs )
194 ///////////////////////////////////////////////////////////////////
197 // METHOD NAME : RpmHeader::~RpmHeader
198 // METHOD TYPE : Destructor
202 RpmHeader::~RpmHeader()
205 ///////////////////////////////////////////////////////////////////
208 // METHOD NAME : RpmHeader::readPackage
209 // METHOD TYPE : constRpmHeaderPtr
211 RpmHeader::constPtr RpmHeader::readPackage( const Pathname & path_r,
212 VERIFICATION verification_r )
214 PathInfo file( path_r );
215 if ( ! file.isFile() )
217 ERR << "Not a file: " << file << endl;
218 return (RpmHeader*)0;
221 FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
222 if ( fd == 0 || ::Ferror(fd) )
224 ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
227 return (RpmHeader*)0;
230 librpmDb::globalInit();
231 rpmts ts = ::rpmtsCreate();
232 unsigned vsflag = RPMVSF_DEFAULT;
233 if ( verification_r & NODIGEST )
234 vsflag |= _RPMVSF_NODIGESTS;
235 if ( verification_r & NOSIGNATURE )
236 vsflag |= _RPMVSF_NOSIGNATURES;
237 ::rpmtsSetVSFlags( ts, rpmVSFlags(vsflag) );
240 int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), &nh );
248 WAR << "Error reading header from " << path_r << " error(" << res << ")" << endl;
249 return (RpmHeader*)0;
252 RpmHeader::constPtr h( new RpmHeader( nh ) );
253 headerFree( nh ); // clear the reference set in ReadPackageFile
255 MIL << h << " from " << path_r << endl;
259 ///////////////////////////////////////////////////////////////////
262 // METHOD NAME : RpmHeader::dumpOn
263 // METHOD TYPE : std::ostream &
267 std::ostream & RpmHeader::dumpOn( std::ostream & str ) const
269 return BinHeader::dumpOn( str ) << '{' << tag_name() << "-"
270 << (tag_epoch()==0?"":(tag_epoch()+":"))
272 << (tag_release().empty()?"":(std::string("-")+tag_release()))
273 << ( isSrc() ? ".src}" : "}");
277 ///////////////////////////////////////////////////////////////////
280 // METHOD NAME : RpmHeader::isSrc
281 // METHOD TYPE : bool
283 bool RpmHeader::isSrc() const
285 return has_tag( RPMTAG_SOURCEPACKAGE );
288 ///////////////////////////////////////////////////////////////////
291 // METHOD NAME : RpmHeader::tag_name
292 // METHOD TYPE : std::string
296 std::string RpmHeader::tag_name() const
298 return string_val( RPMTAG_NAME );
301 ///////////////////////////////////////////////////////////////////
304 // METHOD NAME : RpmHeader::tag_epoch
305 // METHOD TYPE : Edition::epoch_t
309 Edition::epoch_t RpmHeader::tag_epoch() const
311 return int_val ( RPMTAG_EPOCH );
314 ///////////////////////////////////////////////////////////////////
317 // METHOD NAME : RpmHeader::tag_version
318 // METHOD TYPE : std::string
322 std::string RpmHeader::tag_version() const
324 return string_val ( RPMTAG_VERSION );
327 ///////////////////////////////////////////////////////////////////
330 // METHOD NAME : RpmHeader::tag_release
331 // METHOD TYPE : std::string
335 std::string RpmHeader::tag_release() const
337 return string_val( RPMTAG_RELEASE );
340 ///////////////////////////////////////////////////////////////////
343 // METHOD NAME : RpmHeader::tag_edition
344 // METHOD TYPE : Edition
348 Edition RpmHeader::tag_edition () const
350 return Edition( tag_version(), tag_release(), tag_epoch() );
353 ///////////////////////////////////////////////////////////////////
356 // METHOD NAME : RpmHeader::tag_arch
357 // METHOD TYPE : Arch
361 Arch RpmHeader::tag_arch() const
363 return Arch( string_val( RPMTAG_ARCH ) );
366 ///////////////////////////////////////////////////////////////////
369 // METHOD NAME : RpmHeader::tag_installtime
370 // METHOD TYPE : Date
374 Date RpmHeader::tag_installtime() const
376 return int_val( RPMTAG_INSTALLTIME );
379 ///////////////////////////////////////////////////////////////////
382 // METHOD NAME : RpmHeader::tag_buildtime
383 // METHOD TYPE : Date
387 Date RpmHeader::tag_buildtime() const
389 return int_val( RPMTAG_BUILDTIME );
391 #warning CHECK IF FILE REQUIRES HANDLING IS OBSOLETE
392 ///////////////////////////////////////////////////////////////////
395 // METHOD NAME : RpmHeader::PkgRelList_val
396 // METHOD TYPE : CapabilitySet
400 CapabilitySet RpmHeader::PkgRelList_val( tag tag_r, bool pre, std::set<std::string> * freq_r ) const
404 rpmTag kindFlags = rpmTag(0);
405 rpmTag kindVersion = rpmTag(0);
409 case RPMTAG_REQUIRENAME:
410 kindFlags = RPMTAG_REQUIREFLAGS;
411 kindVersion = RPMTAG_REQUIREVERSION;
413 case RPMTAG_PROVIDENAME:
414 kindFlags = RPMTAG_PROVIDEFLAGS;
415 kindVersion = RPMTAG_PROVIDEVERSION;
417 case RPMTAG_OBSOLETENAME:
418 kindFlags = RPMTAG_OBSOLETEFLAGS;
419 kindVersion = RPMTAG_OBSOLETEVERSION;
421 case RPMTAG_CONFLICTNAME:
422 kindFlags = RPMTAG_CONFLICTFLAGS;
423 kindVersion = RPMTAG_CONFLICTVERSION;
425 case RPMTAG_ENHANCESNAME:
426 kindFlags = RPMTAG_ENHANCESFLAGS;
427 kindVersion = RPMTAG_ENHANCESVERSION;
429 case RPMTAG_SUGGESTSNAME:
430 kindFlags = RPMTAG_SUGGESTSFLAGS;
431 kindVersion = RPMTAG_SUGGESTSVERSION;
434 INT << "Illegal RPMTAG_dependencyNAME " << tag_r << endl;
440 unsigned count = string_list( tag_r, names );
445 int_list( kindFlags, flags );
448 string_list( kindVersion, versions );
450 for ( unsigned i = 0; i < count; ++i )
453 std::string n( names[i] );
456 int32_t f = flags[i];
457 std::string v = versions[i];
470 switch ( f & RPMSENSE_SENSEMASK )
475 case RPMSENSE_LESS|RPMSENSE_EQUAL:
478 case RPMSENSE_GREATER:
481 case RPMSENSE_GREATER|RPMSENSE_EQUAL:
490 if ((pre && (f & RPMSENSE_PREREQ))
491 || ((! pre) && !(f & RPMSENSE_PREREQ)))
495 ret.insert( Capability( n, op, Edition(v) ) );
497 catch (Exception & excpt_r)
499 ZYPP_CAUGHT(excpt_r);
500 WAR << "Invalid capability: " << n << " " << op << " "
509 ///////////////////////////////////////////////////////////////////
512 // METHOD NAME : RpmHeader::tag_provides
513 // METHOD TYPE : CapabilitySet
517 CapabilitySet RpmHeader::tag_provides( std::set<std::string> * freq_r ) const
519 return PkgRelList_val( RPMTAG_PROVIDENAME, false, freq_r );
522 ///////////////////////////////////////////////////////////////////
525 // METHOD NAME : RpmHeader::tag_requires
526 // METHOD TYPE : CapabilitySet
530 CapabilitySet RpmHeader::tag_requires( std::set<std::string> * freq_r ) const
532 return PkgRelList_val( RPMTAG_REQUIRENAME, false, freq_r );
535 ///////////////////////////////////////////////////////////////////
538 // METHOD NAME : RpmHeader::tag_requires
539 // METHOD TYPE : CapabilitySet
543 CapabilitySet RpmHeader::tag_prerequires( std::set<std::string> * freq_r ) const
545 return PkgRelList_val( RPMTAG_REQUIRENAME, true, freq_r );
548 ///////////////////////////////////////////////////////////////////
551 // METHOD NAME : RpmHeader::tag_conflicts
552 // METHOD TYPE : CapabilitySet
556 CapabilitySet RpmHeader::tag_conflicts( std::set<std::string> * freq_r ) const
558 return PkgRelList_val( RPMTAG_CONFLICTNAME, false, freq_r );
561 ///////////////////////////////////////////////////////////////////
564 // METHOD NAME : RpmHeader::tag_obsoletes
565 // METHOD TYPE : CapabilitySet
569 CapabilitySet RpmHeader::tag_obsoletes( std::set<std::string> * freq_r ) const
571 return PkgRelList_val( RPMTAG_OBSOLETENAME, false, freq_r );
574 ///////////////////////////////////////////////////////////////////
577 // METHOD NAME : RpmHeader::tag_enhances
578 // METHOD TYPE : CapabilitySet
582 CapabilitySet RpmHeader::tag_enhances( std::set<std::string> * freq_r ) const
584 return PkgRelList_val( RPMTAG_ENHANCESNAME, false, freq_r );
587 ///////////////////////////////////////////////////////////////////
590 // METHOD NAME : RpmHeader::tag_suggests
591 // METHOD TYPE : CapabilitySet
595 CapabilitySet RpmHeader::tag_suggests( std::set<std::string> * freq_r ) const
597 return PkgRelList_val( RPMTAG_SUGGESTSNAME, false, freq_r );
600 ///////////////////////////////////////////////////////////////////
603 // METHOD NAME : RpmHeader::tag_size
604 // METHOD TYPE : ByteCount
608 ByteCount RpmHeader::tag_size() const
610 return int_val( RPMTAG_SIZE );
613 ///////////////////////////////////////////////////////////////////
616 // METHOD NAME : RpmHeader::tag_archivesize
617 // METHOD TYPE : ByteCount
621 ByteCount RpmHeader::tag_archivesize() const
623 return int_val( RPMTAG_ARCHIVESIZE );
626 ///////////////////////////////////////////////////////////////////
629 // METHOD NAME : RpmHeader::tag_summary
630 // METHOD TYPE : std::string
634 std::string RpmHeader::tag_summary() const
636 return string_val( RPMTAG_SUMMARY );
639 ///////////////////////////////////////////////////////////////////
642 // METHOD NAME : RpmHeader::tag_description
643 // METHOD TYPE : std::string
647 std::string RpmHeader::tag_description() const
649 return string_val( RPMTAG_DESCRIPTION );
652 ///////////////////////////////////////////////////////////////////
655 // METHOD NAME : RpmHeader::tag_group
656 // METHOD TYPE : std::string
660 std::string RpmHeader::tag_group() const
662 return string_val( RPMTAG_GROUP );
665 ///////////////////////////////////////////////////////////////////
668 // METHOD NAME : RpmHeader::tag_vendor
669 // METHOD TYPE : std::string
673 std::string RpmHeader::tag_vendor() const
675 return string_val( RPMTAG_VENDOR );
678 ///////////////////////////////////////////////////////////////////
681 // METHOD NAME : RpmHeader::tag_distribution
682 // METHOD TYPE : std::string
686 std::string RpmHeader::tag_distribution() const
688 return string_val( RPMTAG_DISTRIBUTION );
691 ///////////////////////////////////////////////////////////////////
694 // METHOD NAME : RpmHeader::tag_license
695 // METHOD TYPE : std::string
699 std::string RpmHeader::tag_license() const
701 return string_val( RPMTAG_LICENSE );
704 ///////////////////////////////////////////////////////////////////
707 // METHOD NAME : RpmHeader::tag_buildhost
708 // METHOD TYPE : std::string
712 std::string RpmHeader::tag_buildhost() const
714 return string_val( RPMTAG_BUILDHOST );
717 ///////////////////////////////////////////////////////////////////
720 // METHOD NAME : RpmHeader::tag_packager
721 // METHOD TYPE : std::string
725 std::string RpmHeader::tag_packager() const
727 return string_val( RPMTAG_PACKAGER );
730 ///////////////////////////////////////////////////////////////////
733 // METHOD NAME : RpmHeader::tag_url
734 // METHOD TYPE : std::string
738 std::string RpmHeader::tag_url() const
740 return string_val( RPMTAG_URL );
743 ///////////////////////////////////////////////////////////////////
746 // METHOD NAME : RpmHeader::tag_os
747 // METHOD TYPE : std::string
751 std::string RpmHeader::tag_os() const
753 return string_val( RPMTAG_OS );
756 ///////////////////////////////////////////////////////////////////
759 // METHOD NAME : RpmHeader::tag_prein
760 // METHOD TYPE : std::string
764 std::string RpmHeader::tag_prein() const
766 return string_val( RPMTAG_PREIN );
769 ///////////////////////////////////////////////////////////////////
772 // METHOD NAME : RpmHeader::tag_postin
773 // METHOD TYPE : std::string
777 std::string RpmHeader::tag_postin() const
779 return string_val( RPMTAG_POSTIN );
782 ///////////////////////////////////////////////////////////////////
785 // METHOD NAME : RpmHeader::tag_preun
786 // METHOD TYPE : std::string
790 std::string RpmHeader::tag_preun() const
792 return string_val( RPMTAG_PREUN );
795 ///////////////////////////////////////////////////////////////////
798 // METHOD NAME : RpmHeader::tag_postun
799 // METHOD TYPE : std::string
803 std::string RpmHeader::tag_postun() const
805 return string_val( RPMTAG_POSTUN );
808 ///////////////////////////////////////////////////////////////////
811 // METHOD NAME : RpmHeader::tag_sourcerpm
812 // METHOD TYPE : std::string
816 std::string RpmHeader::tag_sourcerpm() const
818 return string_val( RPMTAG_SOURCERPM );
821 ///////////////////////////////////////////////////////////////////
824 // METHOD NAME : RpmHeader::tag_filenames
825 // METHOD TYPE : std::list<std::string>
829 std::list<std::string> RpmHeader::tag_filenames() const
831 std::list<std::string> ret;
833 stringList basenames;
834 if ( string_list( RPMTAG_BASENAMES, basenames ) )
837 string_list( RPMTAG_DIRNAMES, dirnames );
839 int_list( RPMTAG_DIRINDEXES, dirindexes );
840 for ( unsigned i = 0; i < basenames.size(); ++ i )
842 ret.push_back( dirnames[dirindexes[i]] + basenames[i] );
849 ///////////////////////////////////////////////////////////////////
852 // METHOD NAME : RpmHeader::tag_fileinfos
853 // METHOD TYPE : std::list<FileInfo>
857 std::list<FileInfo> RpmHeader::tag_fileinfos() const
859 std::list<FileInfo> ret;
861 stringList basenames;
862 if ( string_list( RPMTAG_BASENAMES, basenames ) )
865 string_list( RPMTAG_DIRNAMES, dirnames );
867 int_list( RPMTAG_DIRINDEXES, dirindexes );
869 int_list( RPMTAG_FILESIZES, filesizes );
871 string_list( RPMTAG_FILEMD5S, md5sums );
872 stringList usernames;
873 string_list( RPMTAG_FILEUSERNAME, usernames );
874 stringList groupnames;
875 string_list( RPMTAG_FILEGROUPNAME, groupnames );
877 int_list( RPMTAG_FILEUIDS, uids );
879 int_list( RPMTAG_FILEGIDS, gids );
881 int_list( RPMTAG_FILEMODES, filemodes );
883 int_list( RPMTAG_FILEMTIMES, filemtimes );
885 int_list( RPMTAG_FILEFLAGS, fileflags );
886 stringList filelinks;
887 string_list( RPMTAG_FILELINKTOS, filelinks );
889 for ( unsigned i = 0; i < basenames.size(); ++ i )
894 uid = unameToUid( usernames[i].c_str(), &uid );
904 gid = gnameToGid( groupnames[i].c_str(), &gid );
912 dirnames[dirindexes[i]] + basenames[i],
917 mode_t(filemodes[i]),
919 bool(fileflags[i] & RPMFILE_GHOST),
923 ret.push_back( info );
930 ///////////////////////////////////////////////////////////////////
933 // METHOD NAME : RpmHeader::tag_changelog
934 // METHOD TYPE : Changelog
938 Changelog RpmHeader::tag_changelog() const
943 if ( int_list( RPMTAG_CHANGELOGTIME, times ) )
946 string_list( RPMTAG_CHANGELOGNAME, names );
948 string_list( RPMTAG_CHANGELOGTEXT, texts );
949 for ( unsigned i = 0; i < times.size(); ++ i )
951 ret.push_back( ChangelogEntry( times[i], names[i], texts[i] ) );
958 ///////////////////////////////////////////////////////////////////
961 // METHOD NAME : RpmHeader::tag_du
962 // METHOD TYPE : PkgDu &
966 DiskUsage & RpmHeader::tag_du( DiskUsage & dudata_r ) const
969 stringList basenames;
970 if ( string_list( RPMTAG_BASENAMES, basenames ) )
973 string_list( RPMTAG_DIRNAMES, dirnames );
975 int_list( RPMTAG_DIRINDEXES, dirindexes );
978 int_list( RPMTAG_FILEDEVICES, filedevices );
980 int_list( RPMTAG_FILEINODES, fileinodes );
982 int_list( RPMTAG_FILESIZES, filesizes );
984 int_list( RPMTAG_FILEMODES, filemodes );
986 ///////////////////////////////////////////////////////////////////
987 // Create and collect Entries by index. devino_cache is used to
988 // filter out hardliks ( different name but same device and inode ).
989 ///////////////////////////////////////////////////////////////////
990 filesystem::DevInoCache trace;
991 std::vector<DiskUsage::Entry> entries;
992 entries.resize( dirnames.size() );
993 for ( unsigned i = 0; i < dirnames.size(); ++i )
995 entries[i] = DiskUsage::Entry( dirnames[i] );
997 // cut off deeper directory levels in DiskUsage::Entry
998 unsigned level = 3; // number of '/' incl. a trailing one
999 std::string::size_type pos = 0; // we know rpm stores absolute pathnames
1000 while ( --level && pos != std::string::npos )
1002 pos = entries[i].path.find( "/", pos+1 );
1004 if ( pos != std::string::npos )
1006 entries[i].path.erase( pos+1 );
1010 for ( unsigned i = 0; i < basenames.size(); ++ i )
1012 filesystem::StatMode mode( filemodes[i] );
1013 if ( mode.isFile() )
1015 if ( trace.insert( filedevices[i], fileinodes[i] ) )
1017 // Count full 1K blocks
1018 entries[dirindexes[i]]._size += ByteCount( filesizes[i] ).blocks( ByteCount::K );
1019 ++(entries[dirindexes[i]]._files);
1021 // else: hardlink; already counted this device/inode
1025 ///////////////////////////////////////////////////////////////////
1026 // Collect all enties. We first unify the duplicate entries that
1027 // were created by cutting off deeper levels. Then the size of each
1028 // directory must also be added to each of it's parent directories.
1029 ///////////////////////////////////////////////////////////////////
1031 for ( unsigned i = 0; i < entries.size(); ++i )
1033 if ( entries[i]._size )
1034 tmpdata.add( entries[i] );
1037 for_( it, tmpdata.begin(), tmpdata.end() )
1039 DiskUsage::Entry ent( *it );
1042 dudata_r.add( ent );
1043 if ( ent.path.size() <= 1 ) // "" or "/"
1046 // set path to parent dir. Note that DiskUsage::Entry
1047 // has leading and trailing '/' on pathnmes.
1048 std::string::size_type rstart = ent.path.size() - 2; // trailing '/' !
1049 std::string::size_type lpos = ent.path.rfind( '/', rstart ); // one but last '/'
1050 if ( lpos == std::string::npos )
1053 ent.path.erase( lpos + 1 );
1061 } // namespace target