2009-10-02 11:47:28 +04:00
# include "system.h"
# include "rpmlib.h"
2009-10-03 12:34:15 +04:00
# include "debug.h"
2009-10-02 11:47:28 +04:00
# include "depends.h"
# include "al.h"
2009-10-03 12:34:15 +04:00
struct alEntry {
const char * name ;
2010-03-12 11:02:08 +03:00
unsigned int fasthash ;
2009-10-03 12:34:15 +04:00
/* entry-specific members */
} ;
struct alIndex {
int sorted ;
int size ;
/* flexible array of entries */
} ;
2010-03-12 11:02:08 +03:00
static inline
unsigned int fasthash ( const char * name )
{
/* The "fast hash" is used below to avoid extra strcmp calls. Initially it
* was just a string length . To improve the performance without resorting
* to full - fledged hashing , we now combine string length with its middle
* character . */
unsigned int len = strlen ( name ) ;
unsigned char c = name [ len > > 1 ] ;
return ( len < < 8 ) | c ;
}
2009-10-03 12:34:15 +04:00
/**
* Compare two available index entries by name ( qsort / bsearch ) .
* @ param one 1 st available prov entry
* @ param two 2 nd available prov entry
* @ return result of comparison
*/
static inline
int nameCmp ( const void * one , const void * two ) /*@*/
{
const struct alEntry * a = one , * b = two ;
2010-03-12 11:02:08 +03:00
if ( a - > fasthash > b - > fasthash )
return 1 ;
if ( a - > fasthash < b - > fasthash )
return - 1 ;
2009-10-03 12:34:15 +04:00
return strcmp ( a - > name , b - > name ) ;
}
static
void * axSearch ( void * index , int esize , const char * name , int * nfound )
{
if ( nfound )
* nfound = 0 ;
struct alIndex * ax = index ;
if ( ax = = NULL )
return NULL ;
assert ( ax - > size > 0 ) ;
char * entries = ( char * ) ( ax + 1 ) ;
2010-03-12 11:02:08 +03:00
struct alEntry needle = { name , fasthash ( name ) } ;
2009-10-03 12:34:15 +04:00
if ( ax - > size = = 1 ) {
if ( nameCmp ( entries , & needle ) )
return NULL ;
if ( nfound )
* nfound = 1 ;
return entries ;
}
if ( ! ax - > sorted ) {
qsort ( entries , ax - > size , esize , nameCmp ) ;
ax - > sorted = 1 ;
}
char * first , * last ;
first = last = bsearch ( & needle , entries , ax - > size , esize , nameCmp ) ;
if ( first = = NULL )
return NULL ;
if ( nfound ) {
* nfound = 1 ;
/* rewind to the first match */
while ( first > entries ) {
if ( nameCmp ( first - esize , & needle ) )
break ;
first - = esize ;
( * nfound ) + + ;
}
/* rewind to the last match */
while ( last + esize < entries + esize * ax - > size ) {
if ( nameCmp ( last + esize , & needle ) )
break ;
last + = esize ;
( * nfound ) + + ;
}
}
return first ;
}
static
void * axGrow ( void * index , int esize , int more )
{
struct alIndex * ax = index ;
if ( ax ) {
assert ( ax - > size > 0 ) ;
ax = xrealloc ( ax , sizeof ( * ax ) + esize * ( ax - > size + more ) ) ;
}
else {
ax = xmalloc ( sizeof ( * ax ) + esize * more ) ;
ax - > size = 0 ;
}
return ax ;
}
2009-10-02 11:47:28 +04:00
/** \ingroup rpmdep
* A single available item ( e . g . a Provides : dependency ) .
*/
2009-10-04 06:58:58 +04:00
struct alProvEntry {
/*@dependent@*/ const char * name ; /*!< Provides name. */
2010-03-12 11:02:08 +03:00
unsigned int fasthash ;
2009-10-04 06:58:58 +04:00
int pkgIx ; /*!< Containing package index. */
int provIx ; /*!< Provides index in package. */
2009-10-02 11:47:28 +04:00
} ;
/** \ingroup rpmdep
* Index of all available items .
*/
2009-10-04 06:58:58 +04:00
struct alProvIndex {
int sorted ;
2009-10-02 11:47:28 +04:00
int size ; /*!< No. of available items. */
2009-10-04 06:58:58 +04:00
struct alProvEntry prov [ 1 ] ; /*!< Array of available items. */
2009-10-02 11:47:28 +04:00
} ;
2009-10-04 06:58:58 +04:00
static
void alIndexPkgProvides ( availableList al , int pkgIx )
2009-10-02 11:47:28 +04:00
{
2009-10-04 06:58:58 +04:00
const struct availablePackage * alp = & al - > list [ pkgIx ] ;
if ( alp - > providesCount = = 0 )
2009-10-02 11:47:28 +04:00
return ;
2009-10-04 06:58:58 +04:00
struct alProvIndex * px = al - > provIndex =
axGrow ( al - > provIndex , sizeof ( * px - > prov ) , alp - > providesCount ) ;
2009-10-02 11:47:28 +04:00
2009-10-04 06:58:58 +04:00
int provIx ;
for ( provIx = 0 ; provIx < alp - > providesCount ; provIx + + ) {
struct alProvEntry * pe = & px - > prov [ px - > size + + ] ;
pe - > name = alp - > provides [ provIx ] ;
2010-03-12 11:02:08 +03:00
pe - > fasthash = fasthash ( pe - > name ) ;
2009-10-04 06:58:58 +04:00
pe - > pkgIx = pkgIx ;
pe - > provIx = provIx ;
2009-10-02 11:47:28 +04:00
}
2009-10-04 06:58:58 +04:00
px - > sorted = 0 ;
2009-10-02 11:47:28 +04:00
}
2009-10-04 06:58:58 +04:00
static
struct alProvEntry * alSearchProv ( availableList al , const char * name , int * n )
2009-10-02 11:47:28 +04:00
{
2010-07-12 11:03:50 +04:00
/* first time lookup, create provIndex */
if ( al - > provIndex = = NULL ) {
int i ;
for ( i = 0 ; i < al - > size ; i + + )
alIndexPkgProvides ( al , i ) ;
}
2009-10-04 06:58:58 +04:00
return axSearch ( al - > provIndex , sizeof ( * al - > provIndex - > prov ) , name , n ) ;
}
static
void alFreeProvIndex ( availableList al )
{
al - > provIndex = _free ( al - > provIndex ) ;
2009-10-02 11:47:28 +04:00
}
2009-10-04 10:14:34 +04:00
/** \ingroup rpmdep
* A file to be installed / removed .
2009-10-02 11:47:28 +04:00
*/
2009-10-04 10:14:34 +04:00
struct alFileEntry {
const char * basename ; /*!< File basename. */
2010-03-12 11:02:08 +03:00
unsigned int fasthash ;
2009-10-04 10:14:34 +04:00
int pkgIx ; /*!< Containing package number. */
} ;
struct alFileIndex {
int sorted ;
int size ;
struct alFileEntry files [ 1 ] ;
} ;
/** \ingroup rpmdep
* A directory which contains some files .
*/
struct alDirEntry {
const char * dirname ; /*!< Directory path (+ trailing '/'). */
2010-03-12 11:02:08 +03:00
unsigned int fasthash ;
2009-10-04 10:14:34 +04:00
struct alFileIndex * fx ; /*!< Files index this directory. */
} ;
struct alDirIndex {
int sorted ;
int size ;
struct alDirEntry dirs [ 1 ] ;
} ;
static
void alIndexPkgFiles ( availableList al , int pkgIx )
2009-10-02 11:47:28 +04:00
{
2009-10-04 10:14:34 +04:00
const struct availablePackage * alp = & al - > list [ pkgIx ] ;
if ( alp - > filesCount = = 0 )
return ;
const HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
const HFD_t hfd = headerFreeData ;
const char * * bn = NULL , * * dn = NULL ;
const int * di = NULL ;
rpmTagType bnt = 0 , dnt = 0 , dit = 0 ;
int bnc = 0 , dnc = 0 , dic = 0 ;
if ( ! hge ( alp - > h , RPMTAG_BASENAMES , & bnt , ( void * * ) & bn , & bnc ) )
goto exit ;
if ( ! hge ( alp - > h , RPMTAG_DIRNAMES , & dnt , ( void * * ) & dn , & dnc ) )
goto exit ;
if ( ! hge ( alp - > h , RPMTAG_DIRINDEXES , & dit , ( void * * ) & di , & dic ) )
goto exit ;
if ( bnc ! = dic )
goto exit ;
/* XXX FIXME: We ought to relocate the directory list here */
struct alDirIndex * dx = al - > dirIndex =
axGrow ( al - > dirIndex , sizeof ( * dx - > dirs ) , dnc ) ;
int i = 0 ;
while ( i < bnc ) {
/* maybe a few files under the same dir */
int j = i ;
while ( j + 1 < bnc ) {
if ( di [ i ] ! = di [ j + 1 ] )
break ;
j + + ;
}
/* find or create dir entry */
const char * d = dn [ di [ i ] ] ;
struct alDirEntry * de = ( dx - > size = = 0 ) ? NULL :
axSearch ( dx , sizeof ( * dx - > dirs ) , d , NULL ) ;
if ( de = = NULL ) {
de = & dx - > dirs [ dx - > size + + ] ;
de - > dirname = d ;
2010-03-12 11:02:08 +03:00
de - > fasthash = fasthash ( d ) ;
2009-10-04 10:14:34 +04:00
de - > fx = NULL ;
dx - > sorted = 0 ;
}
struct alFileIndex * fx = de - > fx =
axGrow ( de - > fx , sizeof ( * fx - > files ) , j - i + 1 ) ;
while ( i < = j ) {
/* add file entries */
const char * b = bn [ i + + ] ;
struct alFileEntry * fe = & fx - > files [ fx - > size + + ] ;
fe - > basename = b ;
2010-03-12 11:02:08 +03:00
fe - > fasthash = fasthash ( b ) ;
2009-10-04 10:14:34 +04:00
fe - > pkgIx = pkgIx ;
}
fx - > sorted = 0 ;
}
exit :
/* XXX strings point to header memory */
bn = hfd ( bn , bnt ) ;
dn = hfd ( dn , dnt ) ;
di = hfd ( di , dit ) ;
}
2009-10-02 11:47:28 +04:00
2009-10-04 10:14:34 +04:00
static
struct alFileEntry * alSearchFile ( availableList al , const char * fname , int * n )
{
2010-07-12 11:03:50 +04:00
/* first time lookup, create dirIndex */
if ( al - > dirIndex = = NULL ) {
int i ;
for ( i = 0 ; i < al - > size ; i + + )
alIndexPkgFiles ( al , i ) ;
}
2009-10-04 10:14:34 +04:00
/* need to preserve trailing slahs in d */
const char * b = strrchr ( fname , ' / ' ) + 1 ;
int dlen = b - fname ;
char * d = alloca ( dlen + 1 ) ;
memcpy ( d , fname , dlen ) ;
d [ dlen ] = ' \0 ' ;
struct alDirEntry * de = axSearch ( al - > dirIndex , sizeof ( * de ) , d , NULL ) ;
if ( de = = NULL ) {
* n = 0 ;
return NULL ;
}
assert ( de - > fx ) ;
return axSearch ( de - > fx , sizeof ( * de - > fx - > files ) , b , n ) ;
}
2009-10-02 11:47:28 +04:00
2009-10-04 10:14:34 +04:00
static
void alFreeDirIndex ( availableList al )
{
struct alDirIndex * dx = al - > dirIndex ;
if ( dx ) {
int i ;
for ( i = 0 ; i < dx - > size ; i + + ) {
struct alDirEntry * de = & dx - > dirs [ i ] ;
de - > fx = _free ( de - > fx ) ;
}
al - > dirIndex = _free ( al - > dirIndex ) ;
}
2009-10-02 11:47:28 +04:00
}
struct availablePackage * *
alAllSatisfiesDepend ( const availableList al ,
const char * keyName , const char * keyEVR , int keyFlags )
{
2009-10-04 06:58:58 +04:00
struct availablePackage * * ret = NULL ;
2009-10-04 10:35:49 +04:00
int found = 0 ;
2009-10-04 06:58:58 +04:00
int i , n ;
2009-10-02 11:47:28 +04:00
2009-10-04 10:35:49 +04:00
if ( * keyName = = ' / ' & & ( keyFlags & RPMSENSE_SENSEMASK ) = = 0 ) {
const struct alFileEntry * fe = alSearchFile ( al , keyName , & n ) ;
for ( i = 0 ; fe & & i < n ; i + + , fe + + ) {
struct availablePackage * alp = & al - > list [ fe - > pkgIx ] ;
int j , already = 0 ;
for ( j = 0 ; j < found ; j + + )
if ( ret [ j ] = = alp ) {
already = 1 ;
break ;
}
if ( already )
continue ;
ret = xrealloc ( ret , ( found + 2 ) * sizeof ( * ret ) ) ;
ret [ found + + ] = alp ;
}
2009-10-02 11:47:28 +04:00
}
2009-10-04 06:58:58 +04:00
const struct alProvEntry * pe = alSearchProv ( al , keyName , & n ) ;
2009-10-04 10:35:49 +04:00
for ( i = 0 ; pe & & i < n ; i + + , pe + + ) {
2009-10-04 06:58:58 +04:00
struct availablePackage * alp = & al - > list [ pe - > pkgIx ] ;
2009-10-04 10:35:49 +04:00
int j , already = 0 ;
for ( j = 0 ; j < found ; j + + )
if ( ret [ j ] = = alp ) {
already = 1 ;
break ;
}
if ( already )
continue ;
2009-10-04 12:19:04 +04:00
if ( ( keyFlags & RPMSENSE_SENSEMASK ) ) {
const char * provName = pe - > name ;
const char * provEVR = alp - > providesEVR ?
alp - > providesEVR [ pe - > provIx ] : NULL ;
int provFlags = alp - > provideFlags ?
alp - > provideFlags [ pe - > provIx ] : 0 ;
if ( ! ( provFlags & RPMSENSE_SENSEMASK ) )
provFlags | = RPMSENSE_EQUAL ; /* ALT21-139-g6cb9a9a */
int rc = rpmRangesOverlap ( provName , provEVR , provFlags ,
keyName , keyEVR , keyFlags ) ;
if ( rc = = 0 )
continue ;
}
2009-10-04 06:58:58 +04:00
ret = xrealloc ( ret , ( found + 2 ) * sizeof ( * ret ) ) ;
ret [ found + + ] = alp ;
2009-10-02 11:47:28 +04:00
}
if ( ret )
ret [ found ] = NULL ;
return ret ;
}
struct availablePackage *
alAddPackage ( availableList al ,
Header h , /*@null@*/ /*@dependent@*/ const void * key ,
/*@null@*/ FD_t fd , /*@null@*/ rpmRelocation * relocs )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
struct availablePackage * p ;
rpmRelocation * r ;
int i ;
int pkgNum ;
AUTO_REALLOC ( al - > list , al - > size ) ;
pkgNum = al - > size + + ;
p = al - > list + pkgNum ;
p - > h = headerLink ( h ) ; /* XXX reference held by transaction set */
p - > depth = p - > npreds = 0 ;
memset ( & p - > tsi , 0 , sizeof ( p - > tsi ) ) ;
( void ) headerNVR ( p - > h , & p - > name , & p - > version , & p - > release ) ;
if ( ! hge ( h , RPMTAG_EPOCH , NULL , ( void * * ) & p - > epoch , NULL ) )
p - > epoch = NULL ;
if ( ! hge ( h , RPMTAG_BUILDTIME , NULL , ( void * * ) & p - > buildtime , NULL ) )
p - > buildtime = NULL ;
if ( ! hge ( h , RPMTAG_PROVIDENAME , NULL , ( void * * ) & p - > provides ,
& p - > providesCount ) ) {
p - > providesCount = 0 ;
p - > provides = NULL ;
p - > providesEVR = NULL ;
p - > provideFlags = NULL ;
} else {
if ( ! hge ( h , RPMTAG_PROVIDEVERSION ,
NULL , ( void * * ) & p - > providesEVR , NULL ) )
p - > providesEVR = NULL ;
if ( ! hge ( h , RPMTAG_PROVIDEFLAGS ,
NULL , ( void * * ) & p - > provideFlags , NULL ) )
p - > provideFlags = NULL ;
}
if ( ! hge ( h , RPMTAG_REQUIRENAME , NULL , ( void * * ) & p - > requires ,
& p - > requiresCount ) ) {
p - > requiresCount = 0 ;
p - > requires = NULL ;
p - > requiresEVR = NULL ;
p - > requireFlags = NULL ;
} else {
if ( ! hge ( h , RPMTAG_REQUIREVERSION ,
NULL , ( void * * ) & p - > requiresEVR , NULL ) )
p - > requiresEVR = NULL ;
if ( ! hge ( h , RPMTAG_REQUIREFLAGS ,
NULL , ( void * * ) & p - > requireFlags , NULL ) )
p - > requireFlags = NULL ;
}
2009-10-04 10:14:34 +04:00
if ( ! hge ( h , RPMTAG_BASENAMES , NULL , NULL , & p - > filesCount ) )
2009-10-02 11:47:28 +04:00
p - > filesCount = 0 ;
p - > key = key ;
p - > fd = ( fd ! = NULL ? fdLink ( fd , " alAddPackage " ) : NULL ) ;
if ( relocs ) {
for ( i = 0 , r = relocs ; r - > oldPath | | r - > newPath ; i + + , r + + )
{ } ;
p - > relocs = xmalloc ( ( i + 1 ) * sizeof ( * p - > relocs ) ) ;
for ( i = 0 , r = relocs ; r - > oldPath | | r - > newPath ; i + + , r + + ) {
p - > relocs [ i ] . oldPath = r - > oldPath ? xstrdup ( r - > oldPath ) : NULL ;
p - > relocs [ i ] . newPath = r - > newPath ? xstrdup ( r - > newPath ) : NULL ;
}
p - > relocs [ i ] . oldPath = NULL ;
p - > relocs [ i ] . newPath = NULL ;
} else {
p - > relocs = NULL ;
}
2010-07-12 11:03:50 +04:00
/* Only update the index if it is already created.
* Otherwise , the index will be constructed upon the first time lookup . */
if ( al - > provIndex )
alIndexPkgProvides ( al , pkgNum ) ;
if ( al - > dirIndex )
alIndexPkgFiles ( al , pkgNum ) ;
2009-10-02 11:47:28 +04:00
return p ;
}
void alFree ( availableList al )
{
HFD_t hfd = headerFreeData ;
struct availablePackage * p ;
rpmRelocation * r ;
int i ;
if ( ( p = al - > list ) ! = NULL )
for ( i = 0 ; i < al - > size ; i + + , p + + ) {
{ tsortInfo tsi ;
while ( ( tsi = p - > tsi . tsi_next ) ! = NULL ) {
p - > tsi . tsi_next = tsi - > tsi_next ;
tsi - > tsi_next = NULL ;
tsi = _free ( tsi ) ;
}
}
p - > provides = hfd ( p - > provides , - 1 ) ;
p - > providesEVR = hfd ( p - > providesEVR , - 1 ) ;
p - > requires = hfd ( p - > requires , - 1 ) ;
p - > requiresEVR = hfd ( p - > requiresEVR , - 1 ) ;
p - > h = headerFree ( p - > h ) ;
if ( p - > relocs ) {
for ( r = p - > relocs ; ( r - > oldPath | | r - > newPath ) ; r + + ) {
r - > oldPath = _free ( r - > oldPath ) ;
r - > newPath = _free ( r - > newPath ) ;
}
p - > relocs = _free ( p - > relocs ) ;
}
if ( p - > fd ! = NULL )
p - > fd = fdFree ( p - > fd , " alAddPackage (alFree) " ) ;
}
al - > list = _free ( al - > list ) ;
2009-10-04 06:58:58 +04:00
alFreeProvIndex ( al ) ;
2009-10-04 10:14:34 +04:00
alFreeDirIndex ( al ) ;
2009-10-02 11:47:28 +04:00
}