1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/RpmHeader.cc
13 #if !defined(_RPM_4_4_COMPAT) && !defined(_RPM_5)
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/RpmHeader.h"
157 #include "zypp/Package.h"
158 #include "zypp/PathInfo.h"
169 ///////////////////////////////////////////////////////////////////
171 ///////////////////////////////////////////////////////////////////
174 // METHOD NAME : RpmHeader::RpmHeader
175 // METHOD TYPE : Constructor
179 RpmHeader::RpmHeader( Header h_r )
183 ///////////////////////////////////////////////////////////////////
186 // METHOD NAME : RpmHeader::RpmHeader
187 // METHOD TYPE : Constructor
189 RpmHeader::RpmHeader( BinHeader::Ptr & rhs )
193 ///////////////////////////////////////////////////////////////////
196 // METHOD NAME : RpmHeader::~RpmHeader
197 // METHOD TYPE : Destructor
201 RpmHeader::~RpmHeader()
204 ///////////////////////////////////////////////////////////////////
207 // METHOD NAME : RpmHeader::readPackage
208 // METHOD TYPE : constRpmHeaderPtr
210 RpmHeader::constPtr RpmHeader::readPackage( const Pathname & path_r,
211 VERIFICATION verification_r )
213 PathInfo file( path_r );
214 if ( ! file.isFile() )
216 ERR << "Not a file: " << file << endl;
217 return (RpmHeader*)0;
220 FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
221 if ( fd == 0 || ::Ferror(fd) )
223 ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
226 return (RpmHeader*)0;
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) );
238 int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), &nh );
246 WAR << "Error reading header from " << path_r << " error(" << res << ")" << endl;
247 return (RpmHeader*)0;
250 RpmHeader::constPtr h( new RpmHeader( nh ) );
251 headerFree( nh ); // clear the reference set in ReadPackageFile
253 MIL << h << " from " << path_r << endl;
257 ///////////////////////////////////////////////////////////////////
260 // METHOD NAME : RpmHeader::dumpOn
261 // METHOD TYPE : std::ostream &
265 std::ostream & RpmHeader::dumpOn( std::ostream & str ) const
267 return BinHeader::dumpOn( str ) << '{' << tag_name() << "-"
268 << (tag_epoch()==0?"":(tag_epoch()+":"))
270 << (tag_release().empty()?"":(std::string("-")+tag_release()))
271 << ( isSrc() ? ".src}" : "}");
275 ///////////////////////////////////////////////////////////////////
278 // METHOD NAME : RpmHeader::isSrc
279 // METHOD TYPE : bool
281 bool RpmHeader::isSrc() const
283 return has_tag( RPMTAG_SOURCEPACKAGE );
286 ///////////////////////////////////////////////////////////////////
289 // METHOD NAME : RpmHeader::tag_name
290 // METHOD TYPE : std::string
294 std::string RpmHeader::tag_name() const
296 return string_val( RPMTAG_NAME );
299 ///////////////////////////////////////////////////////////////////
302 // METHOD NAME : RpmHeader::tag_epoch
303 // METHOD TYPE : Edition::epoch_t
307 Edition::epoch_t RpmHeader::tag_epoch() const
309 return int_val ( RPMTAG_EPOCH );
312 ///////////////////////////////////////////////////////////////////
315 // METHOD NAME : RpmHeader::tag_version
316 // METHOD TYPE : std::string
320 std::string RpmHeader::tag_version() const
322 return string_val ( RPMTAG_VERSION );
325 ///////////////////////////////////////////////////////////////////
328 // METHOD NAME : RpmHeader::tag_release
329 // METHOD TYPE : std::string
333 std::string RpmHeader::tag_release() const
335 return string_val( RPMTAG_RELEASE );
338 ///////////////////////////////////////////////////////////////////
341 // METHOD NAME : RpmHeader::tag_edition
342 // METHOD TYPE : Edition
346 Edition RpmHeader::tag_edition () const
348 return Edition( tag_version(), tag_release(), tag_epoch() );
351 ///////////////////////////////////////////////////////////////////
354 // METHOD NAME : RpmHeader::tag_arch
355 // METHOD TYPE : Arch
359 Arch RpmHeader::tag_arch() const
361 return Arch( string_val( RPMTAG_ARCH ) );
364 ///////////////////////////////////////////////////////////////////
367 // METHOD NAME : RpmHeader::tag_installtime
368 // METHOD TYPE : Date
372 Date RpmHeader::tag_installtime() const
374 return int_val( RPMTAG_INSTALLTIME );
377 ///////////////////////////////////////////////////////////////////
380 // METHOD NAME : RpmHeader::tag_buildtime
381 // METHOD TYPE : Date
385 Date RpmHeader::tag_buildtime() const
387 return int_val( RPMTAG_BUILDTIME );
389 #warning CHECK IF FILE REQUIRES HANDLING IS OBSOLETE
390 ///////////////////////////////////////////////////////////////////
393 // METHOD NAME : RpmHeader::PkgRelList_val
394 // METHOD TYPE : CapabilitySet
398 CapabilitySet RpmHeader::PkgRelList_val( tag tag_r, bool pre, std::set<std::string> * freq_r ) const
402 rpmTag kindFlags = rpmTag(0);
403 rpmTag kindVersion = rpmTag(0);
407 case RPMTAG_REQUIRENAME:
408 kindFlags = RPMTAG_REQUIREFLAGS;
409 kindVersion = RPMTAG_REQUIREVERSION;
411 case RPMTAG_PROVIDENAME:
412 kindFlags = RPMTAG_PROVIDEFLAGS;
413 kindVersion = RPMTAG_PROVIDEVERSION;
415 case RPMTAG_OBSOLETENAME:
416 kindFlags = RPMTAG_OBSOLETEFLAGS;
417 kindVersion = RPMTAG_OBSOLETEVERSION;
419 case RPMTAG_CONFLICTNAME:
420 kindFlags = RPMTAG_CONFLICTFLAGS;
421 kindVersion = RPMTAG_CONFLICTVERSION;
423 case RPMTAG_ENHANCESNAME:
424 kindFlags = RPMTAG_ENHANCESFLAGS;
425 kindVersion = RPMTAG_ENHANCESVERSION;
427 case RPMTAG_SUGGESTSNAME:
428 kindFlags = RPMTAG_SUGGESTSFLAGS;
429 kindVersion = RPMTAG_SUGGESTSVERSION;
432 INT << "Illegal RPMTAG_dependencyNAME " << tag_r << endl;
438 unsigned count = string_list( tag_r, names );
443 int_list( kindFlags, flags );
446 string_list( kindVersion, versions );
448 for ( unsigned i = 0; i < count; ++i )
451 std::string n( names[i] );
454 int32_t f = flags[i];
455 std::string v = versions[i];
468 switch ( f & RPMSENSE_SENSEMASK )
473 case RPMSENSE_LESS|RPMSENSE_EQUAL:
476 case RPMSENSE_GREATER:
479 case RPMSENSE_GREATER|RPMSENSE_EQUAL:
488 if ((pre && (f & RPMSENSE_PREREQ))
489 || ((! pre) && !(f & RPMSENSE_PREREQ)))
493 ret.insert( Capability( n, op, Edition(v) ) );
495 catch (Exception & excpt_r)
497 ZYPP_CAUGHT(excpt_r);
498 WAR << "Invalid capability: " << n << " " << op << " "
507 ///////////////////////////////////////////////////////////////////
510 // METHOD NAME : RpmHeader::tag_provides
511 // METHOD TYPE : CapabilitySet
515 CapabilitySet RpmHeader::tag_provides( std::set<std::string> * freq_r ) const
517 return PkgRelList_val( RPMTAG_PROVIDENAME, false, freq_r );
520 ///////////////////////////////////////////////////////////////////
523 // METHOD NAME : RpmHeader::tag_requires
524 // METHOD TYPE : CapabilitySet
528 CapabilitySet RpmHeader::tag_requires( std::set<std::string> * freq_r ) const
530 return PkgRelList_val( RPMTAG_REQUIRENAME, false, freq_r );
533 ///////////////////////////////////////////////////////////////////
536 // METHOD NAME : RpmHeader::tag_requires
537 // METHOD TYPE : CapabilitySet
541 CapabilitySet RpmHeader::tag_prerequires( std::set<std::string> * freq_r ) const
543 return PkgRelList_val( RPMTAG_REQUIRENAME, true, freq_r );
546 ///////////////////////////////////////////////////////////////////
549 // METHOD NAME : RpmHeader::tag_conflicts
550 // METHOD TYPE : CapabilitySet
554 CapabilitySet RpmHeader::tag_conflicts( std::set<std::string> * freq_r ) const
556 return PkgRelList_val( RPMTAG_CONFLICTNAME, false, freq_r );
559 ///////////////////////////////////////////////////////////////////
562 // METHOD NAME : RpmHeader::tag_obsoletes
563 // METHOD TYPE : CapabilitySet
567 CapabilitySet RpmHeader::tag_obsoletes( std::set<std::string> * freq_r ) const
569 return PkgRelList_val( RPMTAG_OBSOLETENAME, false, freq_r );
572 ///////////////////////////////////////////////////////////////////
575 // METHOD NAME : RpmHeader::tag_enhances
576 // METHOD TYPE : CapabilitySet
580 CapabilitySet RpmHeader::tag_enhances( std::set<std::string> * freq_r ) const
582 return PkgRelList_val( RPMTAG_ENHANCESNAME, false, freq_r );
585 ///////////////////////////////////////////////////////////////////
588 // METHOD NAME : RpmHeader::tag_suggests
589 // METHOD TYPE : CapabilitySet
593 CapabilitySet RpmHeader::tag_suggests( std::set<std::string> * freq_r ) const
595 return PkgRelList_val( RPMTAG_SUGGESTSNAME, false, freq_r );
598 ///////////////////////////////////////////////////////////////////
601 // METHOD NAME : RpmHeader::tag_size
602 // METHOD TYPE : ByteCount
606 ByteCount RpmHeader::tag_size() const
608 return int_val( RPMTAG_SIZE );
611 ///////////////////////////////////////////////////////////////////
614 // METHOD NAME : RpmHeader::tag_archivesize
615 // METHOD TYPE : ByteCount
619 ByteCount RpmHeader::tag_archivesize() const
621 return int_val( RPMTAG_ARCHIVESIZE );
624 ///////////////////////////////////////////////////////////////////
627 // METHOD NAME : RpmHeader::tag_summary
628 // METHOD TYPE : std::string
632 std::string RpmHeader::tag_summary() const
634 return string_val( RPMTAG_SUMMARY );
637 ///////////////////////////////////////////////////////////////////
640 // METHOD NAME : RpmHeader::tag_description
641 // METHOD TYPE : std::string
645 std::string RpmHeader::tag_description() const
647 return string_val( RPMTAG_DESCRIPTION );
650 ///////////////////////////////////////////////////////////////////
653 // METHOD NAME : RpmHeader::tag_group
654 // METHOD TYPE : std::string
658 std::string RpmHeader::tag_group() const
660 return string_val( RPMTAG_GROUP );
663 ///////////////////////////////////////////////////////////////////
666 // METHOD NAME : RpmHeader::tag_vendor
667 // METHOD TYPE : std::string
671 std::string RpmHeader::tag_vendor() const
673 return string_val( RPMTAG_VENDOR );
676 ///////////////////////////////////////////////////////////////////
679 // METHOD NAME : RpmHeader::tag_distribution
680 // METHOD TYPE : std::string
684 std::string RpmHeader::tag_distribution() const
686 return string_val( RPMTAG_DISTRIBUTION );
689 ///////////////////////////////////////////////////////////////////
692 // METHOD NAME : RpmHeader::tag_license
693 // METHOD TYPE : std::string
697 std::string RpmHeader::tag_license() const
699 return string_val( RPMTAG_LICENSE );
702 ///////////////////////////////////////////////////////////////////
705 // METHOD NAME : RpmHeader::tag_buildhost
706 // METHOD TYPE : std::string
710 std::string RpmHeader::tag_buildhost() const
712 return string_val( RPMTAG_BUILDHOST );
715 ///////////////////////////////////////////////////////////////////
718 // METHOD NAME : RpmHeader::tag_packager
719 // METHOD TYPE : std::string
723 std::string RpmHeader::tag_packager() const
725 return string_val( RPMTAG_PACKAGER );
728 ///////////////////////////////////////////////////////////////////
731 // METHOD NAME : RpmHeader::tag_url
732 // METHOD TYPE : std::string
736 std::string RpmHeader::tag_url() const
738 return string_val( RPMTAG_URL );
741 ///////////////////////////////////////////////////////////////////
744 // METHOD NAME : RpmHeader::tag_os
745 // METHOD TYPE : std::string
749 std::string RpmHeader::tag_os() const
751 return string_val( RPMTAG_OS );
754 ///////////////////////////////////////////////////////////////////
757 // METHOD NAME : RpmHeader::tag_prein
758 // METHOD TYPE : std::string
762 std::string RpmHeader::tag_prein() const
764 return string_val( RPMTAG_PREIN );
767 ///////////////////////////////////////////////////////////////////
770 // METHOD NAME : RpmHeader::tag_postin
771 // METHOD TYPE : std::string
775 std::string RpmHeader::tag_postin() const
777 return string_val( RPMTAG_POSTIN );
780 ///////////////////////////////////////////////////////////////////
783 // METHOD NAME : RpmHeader::tag_preun
784 // METHOD TYPE : std::string
788 std::string RpmHeader::tag_preun() const
790 return string_val( RPMTAG_PREUN );
793 ///////////////////////////////////////////////////////////////////
796 // METHOD NAME : RpmHeader::tag_postun
797 // METHOD TYPE : std::string
801 std::string RpmHeader::tag_postun() const
803 return string_val( RPMTAG_POSTUN );
806 ///////////////////////////////////////////////////////////////////
809 // METHOD NAME : RpmHeader::tag_sourcerpm
810 // METHOD TYPE : std::string
814 std::string RpmHeader::tag_sourcerpm() const
816 return string_val( RPMTAG_SOURCERPM );
819 ///////////////////////////////////////////////////////////////////
822 // METHOD NAME : RpmHeader::tag_filenames
823 // METHOD TYPE : std::list<std::string>
827 std::list<std::string> RpmHeader::tag_filenames() const
829 std::list<std::string> ret;
831 stringList basenames;
832 if ( string_list( RPMTAG_BASENAMES, basenames ) )
835 string_list( RPMTAG_DIRNAMES, dirnames );
837 int_list( RPMTAG_DIRINDEXES, dirindexes );
838 for ( unsigned i = 0; i < basenames.size(); ++ i )
840 ret.push_back( dirnames[dirindexes[i]] + basenames[i] );
847 ///////////////////////////////////////////////////////////////////
850 // METHOD NAME : RpmHeader::tag_fileinfos
851 // METHOD TYPE : std::list<FileInfo>
855 std::list<FileInfo> RpmHeader::tag_fileinfos() const
857 std::list<FileInfo> ret;
859 stringList basenames;
860 if ( string_list( RPMTAG_BASENAMES, basenames ) )
863 string_list( RPMTAG_DIRNAMES, dirnames );
865 int_list( RPMTAG_DIRINDEXES, dirindexes );
867 int_list( RPMTAG_FILESIZES, filesizes );
869 string_list( RPMTAG_FILEMD5S, md5sums );
870 stringList usernames;
871 string_list( RPMTAG_FILEUSERNAME, usernames );
872 stringList groupnames;
873 string_list( RPMTAG_FILEGROUPNAME, groupnames );
875 int_list( RPMTAG_FILEUIDS, uids );
877 int_list( RPMTAG_FILEGIDS, gids );
879 int_list( RPMTAG_FILEMODES, filemodes );
881 int_list( RPMTAG_FILEMTIMES, filemtimes );
883 int_list( RPMTAG_FILEFLAGS, fileflags );
884 stringList filelinks;
885 string_list( RPMTAG_FILELINKTOS, filelinks );
887 for ( unsigned i = 0; i < basenames.size(); ++ i )
892 uid = unameToUid( usernames[i].c_str(), &uid );
902 gid = gnameToGid( groupnames[i].c_str(), &gid );
910 dirnames[dirindexes[i]] + basenames[i],
917 fileflags[i] & RPMFILE_GHOST,
921 ret.push_back( info );
928 ///////////////////////////////////////////////////////////////////
931 // METHOD NAME : RpmHeader::tag_changelog
932 // METHOD TYPE : Changelog
936 Changelog RpmHeader::tag_changelog() const
941 if ( int_list( RPMTAG_CHANGELOGTIME, times ) )
944 string_list( RPMTAG_CHANGELOGNAME, names );
946 string_list( RPMTAG_CHANGELOGTEXT, texts );
947 for ( unsigned i = 0; i < times.size(); ++ i )
949 ret.push_back( ChangelogEntry( times[i], names[i], texts[i] ) );
956 ///////////////////////////////////////////////////////////////////
959 // METHOD NAME : RpmHeader::tag_du
960 // METHOD TYPE : PkgDu &
964 DiskUsage & RpmHeader::tag_du( DiskUsage & dudata_r ) const
967 stringList basenames;
968 if ( string_list( RPMTAG_BASENAMES, basenames ) )
971 string_list( RPMTAG_DIRNAMES, dirnames );
973 int_list( RPMTAG_DIRINDEXES, dirindexes );
976 int_list( RPMTAG_FILEDEVICES, filedevices );
978 int_list( RPMTAG_FILEINODES, fileinodes );
980 int_list( RPMTAG_FILESIZES, filesizes );
982 int_list( RPMTAG_FILEMODES, filemodes );
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 )
993 entries[i] = DiskUsage::Entry( dirnames[i] );
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 )
1000 pos = entries[i].path.find( "/", pos+1 );
1002 if ( pos != std::string::npos )
1004 entries[i].path.erase( pos+1 );
1008 for ( unsigned i = 0; i < basenames.size(); ++ i )
1010 filesystem::StatMode mode( filemodes[i] );
1011 if ( mode.isFile() )
1013 if ( trace.insert( filedevices[i], fileinodes[i] ) )
1015 // Count full 1K blocks
1016 entries[dirindexes[i]]._size += ByteCount( filesizes[i] ).blocks( ByteCount::K );
1017 ++(entries[dirindexes[i]]._files);
1019 // else: hardlink; already counted this device/inode
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 ///////////////////////////////////////////////////////////////////
1029 for ( unsigned i = 0; i < entries.size(); ++i )
1031 if ( entries[i]._size )
1032 tmpdata.add( entries[i] );
1035 for_( it, tmpdata.begin(), tmpdata.end() )
1037 DiskUsage::Entry ent( *it );
1040 dudata_r.add( ent );
1041 if ( ent.path.size() <= 1 ) // "" or "/"
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 )
1051 ent.path.erase( lpos + 1 );
1059 } // namespace target