tdnf/solv/tdnfpackage.c

2660 lines
57 KiB
C

/*
* Copyright (C) 2015-2023 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
* of the License are located in the COPYING file of this distribution.
*/
#include "includes.h"
uint32_t
SolvCreatePackageList(
PSolvPackageList* ppSolvPackageList
)
{
uint32_t dwError = 0;
PSolvPackageList pPkgList = NULL;
if(!ppSolvPackageList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateMemory(
1,
sizeof(SolvPackageList),
(void **)&pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
queue_init(&pPkgList->queuePackages);
*ppSolvPackageList = pPkgList;
cleanup:
return dwError;
error:
if(ppSolvPackageList)
{
*ppSolvPackageList = NULL;
}
SolvFreePackageList(pPkgList);
goto cleanup;
}
void
SolvEmptyPackageList(
PSolvPackageList pPkgList
)
{
if(pPkgList)
{
queue_free(&pPkgList->queuePackages);
}
}
void
SolvFreePackageList(
PSolvPackageList pPkgList
)
{
if(pPkgList)
{
queue_free(&pPkgList->queuePackages);
TDNF_SAFE_FREE_MEMORY(pPkgList);
}
}
uint32_t
SolvQueueToPackageList(
Queue* pQueue,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
PSolvPackageList pPkgList = NULL;
if(!ppPkgList || !pQueue)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
if(pQueue->count == 0)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreatePackageList(&pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
queue_insertn(&pPkgList->queuePackages,
pPkgList->queuePackages.count,
pQueue->count,
pQueue->elements);
*ppPkgList = pPkgList;
cleanup:
return dwError;
error:
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;
}
uint32_t
SolvGetQueryResult(
PSolvQuery pQuery,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
PSolvPackageList pPkgList = NULL;
if(!ppPkgList || !pQuery)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
if(pQuery->queueResult.count == 0)
{
dwError = ERROR_TDNF_NO_MATCH;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvQueueToPackageList(&pQuery->queueResult, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
return dwError;
error:
if(pPkgList)
{
SolvFreePackageList(pPkgList);
}
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;
}
uint32_t
SolvGetPackageListSize(
PSolvPackageList pPkgList,
uint32_t* pdwSize
)
{
uint32_t dwError = 0;
uint32_t dwCount = 0;
if(!pPkgList || !pdwSize)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwCount = pPkgList->queuePackages.count;
*pdwSize = dwCount;
cleanup:
return dwError;
error:
if(pdwSize)
{
*pdwSize = 0;
}
goto cleanup;
}
uint32_t
SolvGetPkgInfoFromId(
PSolvSack pSack,
uint32_t dwPkgId,
uint32_t dwWhichInfo,
char** ppszInfo)
{
uint32_t dwError = 0;
const char* pszTemp = NULL;
char* pszInfo = NULL;
Solvable *pSolv = NULL;
if(!pSack || !pSack->pPool || !ppszInfo)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTemp = solvable_lookup_str(pSolv, dwWhichInfo);
if(!pszTemp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTemp, &pszInfo);
BAIL_ON_TDNF_ERROR(dwError);
*ppszInfo = pszInfo;
cleanup:
return dwError;
error:
if(ppszInfo)
{
*ppszInfo = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszInfo);
goto cleanup;
}
uint32_t
SolvGetPkgNameFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszName)
{
uint32_t dwError = 0;
const char* pszTemp = NULL;
char* pszName = NULL;
Solvable *pSolv = NULL;
if(!pSack || !ppszName)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTemp = pool_id2str(pSack->pPool, pSolv->name);
if(!pszTemp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTemp, &pszName);
BAIL_ON_TDNF_ERROR(dwError);
*ppszName = pszName;
cleanup:
return dwError;
error:
if(ppszName)
{
*ppszName = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszName);
goto cleanup;
}
uint32_t
SolvGetPkgArchFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszArch)
{
uint32_t dwError = 0;
char* pszArch = NULL;
if(!pSack || !ppszArch)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPkgInfoFromId(
pSack,
dwPkgId,
SOLVABLE_ARCH,
&pszArch);
BAIL_ON_TDNF_ERROR(dwError);
*ppszArch = pszArch;
cleanup:
return dwError;
error:
if(ppszArch)
{
*ppszArch = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszArch);
goto cleanup;
}
uint32_t
SolvGetPkgVersionFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszVersion)
{
uint32_t dwError = 0;
char* pszVersion = NULL;
char* pszEpoch = NULL;
char* pszRelease = NULL;
const char* pszEvr = NULL;
Solvable *pSolv = NULL;
if(!pSack || !pSack->pPool || !ppszVersion)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszEvr = solvable_lookup_str(pSolv, SOLVABLE_EVR);
if(!pszEvr)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvSplitEvr(pSack,
pszEvr,
&pszEpoch,
&pszVersion,
&pszRelease);
BAIL_ON_TDNF_ERROR(dwError);
*ppszVersion = pszVersion;
cleanup:
TDNF_SAFE_FREE_MEMORY(pszEpoch);
TDNF_SAFE_FREE_MEMORY(pszRelease);
return dwError;
error:
if(ppszVersion)
{
*ppszVersion = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszVersion);
goto cleanup;
}
uint32_t
SolvGetPkgReleaseFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszRelease)
{
uint32_t dwError = 0;
char* pszVersion = NULL;
char* pszEpoch = NULL;
char* pszRelease = NULL;
const char* pszEvr = NULL;
Solvable *pSolv = NULL;
if(!pSack || !ppszRelease)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszEvr = solvable_lookup_str(pSolv, SOLVABLE_EVR);
if(!pszEvr)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvSplitEvr(pSack,
pszEvr,
&pszEpoch,
&pszVersion,
&pszRelease);
BAIL_ON_TDNF_ERROR(dwError);
*ppszRelease = pszRelease;
cleanup:
TDNF_SAFE_FREE_MEMORY(pszEpoch);
TDNF_SAFE_FREE_MEMORY(pszVersion);
return dwError;
error:
if(ppszRelease)
{
*ppszRelease = NULL;
}
goto cleanup;
}
uint32_t
SolvGetPkgRepoNameFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszRepoName)
{
uint32_t dwError = 0;
char* pszRepoName = NULL;
const Solvable *pSolv = NULL;
if(!pSack || !ppszRepoName)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if(!pSolv->repo->name)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pSolv->repo->name, &pszRepoName);
BAIL_ON_TDNF_ERROR(dwError);
*ppszRepoName = pszRepoName;
cleanup:
return dwError;
error:
if(ppszRepoName)
{
*ppszRepoName = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszRepoName);
goto cleanup;
}
uint32_t
SolvGetPkgInstallSizeFromId(
PSolvSack pSack,
uint32_t dwPkgId,
uint32_t* pdwSize)
{
uint32_t dwError = 0;
uint32_t dwInstallSize = 0;
Solvable *pSolv = NULL;
if(!pSack || !pdwSize)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwInstallSize = solvable_lookup_num(pSolv, SOLVABLE_INSTALLSIZE, 0);
*pdwSize = dwInstallSize;
cleanup:
return dwError;
error:
if(pdwSize)
{
*pdwSize = 0;
}
goto cleanup;;
}
uint32_t
SolvGetPkgDownloadSizeFromId(
PSolvSack pSack,
uint32_t dwPkgId,
uint32_t* pdwSize)
{
uint32_t dwError = 0;
uint32_t dwDownloadSize = 0;
Solvable *pSolv = NULL;
if(!pSack || !pdwSize)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwDownloadSize = solvable_lookup_num(pSolv, SOLVABLE_DOWNLOADSIZE, 0);
*pdwSize = dwDownloadSize;
cleanup:
return dwError;
error:
if(pdwSize)
{
*pdwSize = 0;
}
goto cleanup;;
}
uint32_t
SolvGetPkgSummaryFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszSummary)
{
uint32_t dwError = 0;
char* pszSummary = NULL;
if(!pSack || !ppszSummary)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPkgInfoFromId(
pSack,
dwPkgId,
SOLVABLE_SUMMARY,
&pszSummary);
BAIL_ON_TDNF_ERROR(dwError);
*ppszSummary = pszSummary;
cleanup:
return dwError;
error:
if(ppszSummary)
{
*ppszSummary = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszSummary);
goto cleanup;
}
uint32_t
SolvGetPkgLicenseFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszLicense)
{
uint32_t dwError = 0;
char* pszLicense = NULL;
if(!pSack || !ppszLicense)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPkgInfoFromId(
pSack,
dwPkgId,
SOLVABLE_LICENSE,
&pszLicense);
BAIL_ON_TDNF_ERROR(dwError);
*ppszLicense = pszLicense;
cleanup:
return dwError;
error:
if(ppszLicense)
{
*ppszLicense = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszLicense);
goto cleanup;
}
uint32_t
SolvGetPkgDescriptionFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszDescription
)
{
uint32_t dwError = 0;
char* pszDescription = NULL;
if(!pSack || !ppszDescription)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPkgInfoFromId(
pSack,
dwPkgId,
SOLVABLE_DESCRIPTION,
&pszDescription);
BAIL_ON_TDNF_ERROR(dwError);
*ppszDescription = pszDescription;
cleanup:
return dwError;
error:
if(ppszDescription)
{
*ppszDescription = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszDescription);
// Some packages don't have description.
// No description is not an error.
if(dwError == ERROR_TDNF_NO_DATA)
{
dwError = 0;
}
goto cleanup;
}
uint32_t
SolvGetPkgUrlFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszUrl)
{
uint32_t dwError = 0;
char* pszUrl = NULL;
if(!pSack || !ppszUrl)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPkgInfoFromId(
pSack,
dwPkgId,
SOLVABLE_URL,
&pszUrl);
BAIL_ON_TDNF_ERROR(dwError);
*ppszUrl = pszUrl;
cleanup:
return dwError;
error:
if(ppszUrl)
{
*ppszUrl = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszUrl);
// Some packages don't have URL information.
// No url is not an error.
if(dwError == ERROR_TDNF_NO_DATA)
{
dwError = 0;
}
goto cleanup;
}
uint32_t
SolvGetPkgNevrFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszNevr)
{
uint32_t dwError = 0;
const char* pszTemp = NULL;
char* pszNevr = NULL;
Solvable *pSolv = NULL;
if(!pSack || !pSack->pPool || !ppszNevr)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTemp = pool_solvable2str(pSack->pPool, pSolv);
if(!pszTemp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTemp, &pszNevr);
BAIL_ON_TDNF_ERROR(dwError);
*ppszNevr = pszNevr;
cleanup:
return dwError;
error:
if(ppszNevr)
{
*ppszNevr = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszNevr);
goto cleanup;
}
uint32_t
SolvGetPkgLocationFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char** ppszLocation)
{
uint32_t dwError = 0;
const char* pszTemp = NULL;
char* pszLocation = NULL;
Solvable *pSolv = NULL;
if(!pSack || !ppszLocation)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTemp = solvable_get_location(pSolv, NULL);
if(!pszTemp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTemp, &pszLocation);
BAIL_ON_TDNF_ERROR(dwError);
*ppszLocation = pszLocation;
cleanup:
return dwError;
error:
// Installed packages do not have location.
if(dwError == ERROR_TDNF_NO_DATA)
{
dwError = 0;
}
if(ppszLocation)
{
ppszLocation = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszLocation);
goto cleanup;
}
uint32_t
SolvGetPackageId(
PSolvPackageList pPkgList,
uint32_t dwPkgIndex,
Id* dwPkgId
)
{
uint32_t dwError = 0;
if(!pPkgList || dwPkgIndex >= (uint32_t)pPkgList->queuePackages.count)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
*dwPkgId = pPkgList->queuePackages.elements[dwPkgIndex];
cleanup:
return dwError;
error:
goto cleanup;
}
uint32_t
SolvGetPkgChecksumFromId(
PSolvSack pSack,
uint32_t dwPkgId,
int *checksumType,
unsigned char** ppbChecksum)
{
uint32_t dwError = 0;
const unsigned char* pbTemp = NULL;
unsigned char* pbChecksum = NULL;
Solvable *pSolv = NULL;
int checksumLen = 0;
if(!pSack || !pSack->pPool || !ppbChecksum)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pbTemp = solvable_lookup_bin_checksum(pSolv, SOLVABLE_CHECKSUM, checksumType);
if(!pbTemp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
checksumLen = solv_chksum_len(*checksumType);
dwError = TDNFAllocateMemory(checksumLen, sizeof(unsigned char), (void **)&pbChecksum);
BAIL_ON_TDNF_ERROR(dwError);
memcpy(pbChecksum, pbTemp, checksumLen);
*ppbChecksum = pbChecksum;
cleanup:
return dwError;
error:
if(ppbChecksum)
{
*ppbChecksum = NULL;
}
TDNF_SAFE_FREE_MEMORY(pbChecksum);
goto cleanup;
}
uint32_t
SolvCmpEvr(
PSolvSack pSack,
Id dwPkg1,
Id dwPkg2,
int* pdwResult)
{
uint32_t dwError = 0;
Solvable *pSolv1 = NULL;
Solvable *pSolv2 = NULL;
const char *pszEvr1 = NULL;
const char *pszEvr2 = NULL;
if(!pSack)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv1 = pool_id2solvable(pSack->pPool, dwPkg1);
pSolv2 = pool_id2solvable(pSack->pPool, dwPkg2);
if(!pSolv1 || !pSolv2)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pszEvr1 = solvable_lookup_str(pSolv1, SOLVABLE_EVR);
pszEvr2 = solvable_lookup_str(pSolv2, SOLVABLE_EVR);
*pdwResult = pool_evrcmp_str(
pSack->pPool,
pszEvr1,
pszEvr2,
EVRCMP_COMPARE);
cleanup:
return dwError;
error:
goto cleanup;
}
uint32_t
SolvGetLatest(
PSolvSack pSack,
Queue* pPkgList,
Id dwPkg,
Id* pdwResult)
{
uint32_t dwError = 0;
Solvable *pSolv1 = NULL;
Solvable *pSolv2 = NULL;
const char *pszEvr1 = NULL;
const char *pszEvr2 = NULL;
const char *pszName1 = NULL;
const char *pszName2 = NULL;
uint32_t dwPkgIter = 0;
int compareResult = 0;
if(!pSack || dwPkg <= 0 || !pPkgList || !pdwResult)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv1 = pool_id2solvable(pSack->pPool, dwPkg);
if(!pSolv1)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pszName1 = pool_id2str(pSack->pPool, pSolv1->name);
pszEvr1 = solvable_lookup_str(pSolv1, SOLVABLE_EVR);
for( ; dwPkgIter < (uint32_t)pPkgList->count; dwPkgIter++)
{
pSolv2 = pool_id2solvable(pSack->pPool, pPkgList->elements[dwPkgIter]);
if(!pSolv2)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pszName2 = pool_id2str(pSack->pPool, pSolv2->name);
if(!strcmp(pszName1, pszName2))
{
pszEvr2 = solvable_lookup_str(pSolv2, SOLVABLE_EVR);
compareResult = pool_evrcmp_str(
pSack->pPool,
pszEvr2, pszEvr1,
EVRCMP_COMPARE);
if(compareResult == 1)
{
*pdwResult = pPkgList->elements[dwPkgIter];
pSolv1 = pSolv2;
pszEvr1 = pszEvr2;
}
}
}
cleanup:
return dwError;
error:
if(pdwResult)
{
*pdwResult = 0;
}
goto cleanup;
}
uint32_t
SolvFindAllInstalled(
PSolvSack pSack,
PSolvPackageList* ppPkgList)
{
uint32_t dwError = 0;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
if(!pSack || !ppPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreateQuery(pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvAddSystemRepoFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
if(pQuery)
{
SolvFreeQuery(pQuery);
}
return dwError;
error:
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;
}
uint32_t
SolvCountPkgByName(
PSolvSack pSack,
const char* pszName,
int nSource,
uint32_t* pdwCount
)
{
uint32_t dwError = 0;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
uint32_t dwCount = 0;
if(!pSack || IsNullOrEmptyString(pszName) ||
!pdwCount)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreateQuery(pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
if (nSource) {
pQuery->nScope = SCOPE_SOURCE;
}
dwError = SolvApplySinglePackageFilter(pQuery, pszName);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetPackageListSize(pPkgList, &dwCount);
BAIL_ON_TDNF_ERROR(dwError);
*pdwCount = dwCount;
cleanup:
if(pPkgList)
{
SolvFreePackageList(pPkgList);
}
if(pQuery)
{
SolvFreeQuery(pQuery);
}
return dwError;
error:
if(pdwCount)
{
*pdwCount = 0;
}
goto cleanup;
}
uint32_t
SolvFindInstalledPkgByName(
PSolvSack pSack,
const char* pszName,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
if(!pSack || IsNullOrEmptyString(pszName) ||
!ppPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreateQuery(pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvAddSystemRepoFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplySinglePackageFilter(pQuery, pszName);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
if(pQuery)
{
SolvFreeQuery(pQuery);
}
return dwError;
error:
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;
}
uint32_t
SolvFindInstalledPkgByMultipleNames(
PSolvSack pSack,
char** ppszPackageNameSpecs,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
if(!pSack || !ppszPackageNameSpecs ||
!ppPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreateQuery(pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvAddSystemRepoFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyPackageFilter(pQuery, ppszPackageNameSpecs);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
if(pQuery)
{
SolvFreeQuery(pQuery);
}
return dwError;
error:
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;
}
uint32_t
SolvFindAvailablePkgByName(
PSolvSack pSack,
const char* pszName,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
if(!pSack || IsNullOrEmptyString(pszName) || !ppPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreateQuery(pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvAddAvailableRepoFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplySinglePackageFilter(pQuery, pszName);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
if(pQuery)
{
SolvFreeQuery(pQuery);
}
return dwError;
error:
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;;
}
uint32_t
SolvFindAvailableSrcPkgByName(
PSolvSack pSack,
const char* pszName,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
if(!pSack || IsNullOrEmptyString(pszName) || !ppPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvCreateQuery(pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
pQuery->nScope = SCOPE_SOURCE;
dwError = SolvAddAvailableRepoFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplySinglePackageFilter(pQuery, pszName);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
if(pQuery)
{
SolvFreeQuery(pQuery);
}
return dwError;
error:
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;;
}
uint32_t
SolvGetTransResultsWithType(
Transaction *pTrans,
Id dwType,
PSolvPackageList* ppPkgList
)
{
uint32_t dwError = 0;
Id dwPkgType = 0;
PSolvPackageList pPkgList = NULL;
Queue queueSolvedPackages = {0};
if(!ppPkgList || !pTrans )
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
queue_init(&queueSolvedPackages);
for (int i = 0; i < pTrans->steps.count; ++i)
{
Id dwPkg = pTrans->steps.elements[i];
switch (dwType)
{
case SOLVER_TRANSACTION_OBSOLETED:
dwPkgType = transaction_type(
pTrans,
dwPkg,
SOLVER_TRANSACTION_SHOW_OBSOLETES);
break;
default:
dwPkgType = transaction_type(
pTrans,
dwPkg,
SOLVER_TRANSACTION_SHOW_ACTIVE|
SOLVER_TRANSACTION_SHOW_ALL);
break;
}
/* Solver uses SOLVER_TRANSACTION_CHANGE if a pkg has
the same nevra, but has differences. If the pkg is
completly identical it uses SOLVER_TRANSACTION_REINSTALL.
For our purposes we don't care. */
if ((dwType == dwPkgType) ||
(dwType == SOLVER_TRANSACTION_REINSTALL &&
dwPkgType == SOLVER_TRANSACTION_CHANGE))
queue_push(&queueSolvedPackages, dwPkg);
}
dwError = SolvQueueToPackageList(&queueSolvedPackages, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
*ppPkgList = pPkgList;
cleanup:
queue_free(&queueSolvedPackages);
return dwError;
error:
if(pPkgList)
{
SolvFreePackageList(pPkgList);
}
if(ppPkgList)
{
*ppPkgList = NULL;
}
goto cleanup;
}
/* code based on mlschroe's suggestion in PR 378 */
/* check if package s obsoletes is */
static int
is_obsoleting(Pool *pool, Solvable *s, const Solvable *is)
{
Id obs;
const Id *obsp;
Id n = is - pool->solvables;
if (!s->obsoletes)
return 0;
obsp = s->repo->idarraydata + s->obsoletes;
while ((obs = *obsp++) != 0) { /* for all obsoletes */
if (pool_match_nevr(pool, pool->solvables + n, obs)) {
return 1;
}
}
return 0;
}
uint32_t
SolvFindBestAvailable(
PSolvSack pSack,
const char* pszPkgName,
Id* pdwId
)
{
uint32_t dwError = 0;
Pool *pool; /* FOR_PROVIDES needs this name */
Id idName;
Id p, pp;
Queue q = {0};
if(!pSack || IsNullOrEmptyString(pszPkgName) || !pdwId)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
pool = pSack->pPool;
idName = pool_str2id(pool, pszPkgName, 1);
queue_init(&q);
/* step 1: look at packages with the specified name */
FOR_PROVIDES(p, pp, idName)
if (pool->solvables[p].name == idName)
queue_push(&q, p);
if (!q.count)
{
dwError = ERROR_TDNF_NO_MATCH;
BAIL_ON_TDNF_ERROR(dwError);
}
pool_best_solvables(pool, &q, 0);
queue_truncate(&q, 1); /* use the first element */
/* step 2: check if a package has a provides/obsoletes combination
* for the best package */
FOR_PROVIDES(p, pp, idName)
{
if (pool->solvables[p].name == idName)
continue; /* already done in step 1 */
if (!is_obsoleting(pool, pool->solvables + p, pool->solvables + q.elements[0]))
continue;
queue_push(&q, p);
}
pool_best_solvables(pool, &q, 0);
*pdwId = q.elements[0];
cleanup:
queue_free(&q);
return dwError;
error:
goto cleanup;
}
uint32_t
SolvFindHighestAvailable(
PSolvSack pSack,
const char* pszPkgName,
int nSource,
Id* pdwId
)
{
uint32_t dwError = 0;
PSolvPackageList pAvailablePkgList = NULL;
Queue *pqAvail;
if(!pSack || IsNullOrEmptyString(pszPkgName) || !pdwId)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
if (!nSource) {
dwError = SolvFindBestAvailable(pSack, pszPkgName, pdwId);
if (dwError == 0)
goto cleanup;
dwError = SolvFindAvailablePkgByName(
pSack,
pszPkgName,
&pAvailablePkgList);
} else {
dwError = SolvFindAvailableSrcPkgByName(
pSack,
pszPkgName,
&pAvailablePkgList);
}
BAIL_ON_TDNF_ERROR(dwError);
pqAvail = &pAvailablePkgList->queuePackages;
pool_best_solvables(pSack->pPool, pqAvail, 0);
if (pqAvail->count == 0) { /* can this happen? */
dwError = ERROR_TDNF_NO_MATCH;
BAIL_ON_TDNF_ERROR(dwError);
}
*pdwId = pqAvail->elements[0];
cleanup:
if(pAvailablePkgList)
{
SolvFreePackageList(pAvailablePkgList);
}
return dwError;
error:
goto cleanup;
}
uint32_t
SolvFindLowestInstalled(
PSolvSack pSack,
const char* pszPkgName,
Id* pdwId
)
{
uint32_t dwError = 0;
Id dwLowestInstalled = 0;
if(!pSack || IsNullOrEmptyString(pszPkgName) || !pdwId)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvFindHighestOrLowestInstalled(
pSack,
pszPkgName,
&dwLowestInstalled,
0);
BAIL_ON_TDNF_ERROR(dwError);
*pdwId = dwLowestInstalled;
cleanup:
return dwError;
error:
goto cleanup;
}
uint32_t
SolvFindHighestInstalled(
PSolvSack pSack,
const char* pszPkgName,
Id* pdwId
)
{
uint32_t dwError = 0;
Id dwHighestInstalled = 0;
if(!pSack || IsNullOrEmptyString(pszPkgName) || !pdwId)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvFindHighestOrLowestInstalled(
pSack,
pszPkgName,
&dwHighestInstalled,
1);
BAIL_ON_TDNF_ERROR(dwError);
*pdwId = dwHighestInstalled;
cleanup:
return dwError;
error:
goto cleanup;
}
uint32_t
SolvFindHighestOrLowestInstalled(
PSolvSack pSack,
const char* pszPkgName,
Id* pdwId,
uint32_t dwFindHighest
)
{
uint32_t dwError = 0;
int dwEvrCompare = 0;
Id dwInstalledId = 0;
Id dwHighestOrLowestInstalled = 0;
PSolvPackageList pInstalledPkgList = NULL;
uint32_t dwCount = 0;
if(!pSack || IsNullOrEmptyString(pszPkgName) || !pdwId)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvFindInstalledPkgByName(
pSack,
pszPkgName,
&pInstalledPkgList);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetPackageId(
pInstalledPkgList,
0,
&dwHighestOrLowestInstalled);
BAIL_ON_TDNF_ERROR(dwError);
if(dwHighestOrLowestInstalled != 0)
{
dwError = SolvGetPackageListSize(pInstalledPkgList, &dwCount);
BAIL_ON_TDNF_ERROR(dwError);
for(uint32_t dwPkgIndex = 1; dwPkgIndex < dwCount; dwPkgIndex++)
{
dwError = SolvGetPackageId(
pInstalledPkgList,
dwPkgIndex,
&dwInstalledId);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvCmpEvr(
pSack,
dwInstalledId,
dwHighestOrLowestInstalled,
&dwEvrCompare);
BAIL_ON_TDNF_ERROR(dwError);
if(dwFindHighest)
{
if(dwEvrCompare > 0)
{
dwHighestOrLowestInstalled = dwInstalledId;
}
}
else
{
if(dwEvrCompare < 0)
{
dwHighestOrLowestInstalled = dwInstalledId;
}
}
}
}
*pdwId = dwHighestOrLowestInstalled;
cleanup:
if(pInstalledPkgList)
{
SolvFreePackageList(pInstalledPkgList);
}
return dwError;
error:
goto cleanup;
}
uint32_t
SolvSplitEvr(
const PSolvSack pSack,
const char *pszEVRstring,
char **ppszEpoch,
char **ppszVersion,
char **ppszRelease)
{
uint32_t dwError = 0;
char *pszEvr = NULL;
int eIndex = 0;
int rIndex = 0;
char *pszTempEpoch = NULL;
char *pszTempVersion = NULL;
char *pszTempRelease = NULL;
char *pszEpoch = NULL;
char *pszVersion = NULL;
char *pszRelease = NULL;
char *pszIt = NULL;
if(!pSack || IsNullOrEmptyString(pszEVRstring)
|| !ppszEpoch || !ppszVersion || !ppszRelease)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
dwError = TDNFAllocateString(pszEVRstring, &pszEvr);
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
// EVR string format: epoch : version-release
pszIt = pszEvr;
for( ; *pszIt != '\0'; pszIt++)
{
if(*pszIt == ':')
{
eIndex = pszIt - pszEvr;
}
else if(*pszIt == '-')
{
rIndex = pszIt - pszEvr;
}
}
pszTempVersion = pszEvr;
pszTempEpoch = NULL;
pszTempRelease = NULL;
if(eIndex != 0)
{
pszTempEpoch = pszEvr;
*(pszEvr + eIndex) = '\0';
pszTempVersion = pszEvr + eIndex + 1;
}
if(rIndex != 0 && rIndex > eIndex)
{
pszTempRelease = pszEvr + rIndex + 1;
*(pszEvr + rIndex) = '\0';
}
if(!IsNullOrEmptyString(pszTempEpoch))
{
dwError = TDNFAllocateString(pszTempEpoch, &pszEpoch);
BAIL_ON_TDNF_ERROR(dwError);
}
if(!IsNullOrEmptyString(pszTempVersion))
{
dwError = TDNFAllocateString(pszTempVersion, &pszVersion);
BAIL_ON_TDNF_ERROR(dwError);
}
if(!IsNullOrEmptyString(pszTempRelease))
{
dwError = TDNFAllocateString(pszTempRelease, &pszRelease);
BAIL_ON_TDNF_ERROR(dwError);
}
*ppszEpoch = pszEpoch;
*ppszVersion = pszVersion;
*ppszRelease = pszRelease;
cleanup:
TDNF_SAFE_FREE_MEMORY(pszEvr);
return dwError;
error:
if(ppszEpoch)
{
*ppszEpoch = NULL;
}
if(ppszVersion)
{
*ppszVersion = NULL;
}
if(ppszRelease)
{
*ppszRelease = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszEpoch);
TDNF_SAFE_FREE_MEMORY(pszVersion);
TDNF_SAFE_FREE_MEMORY(pszRelease);
goto cleanup;
}
/**
* Description: This function should check problem type and
* skipProblemType if both matches then return true
* else return false
* Arguments:
* SolverRuleinfo : Solver problem type
* TDNF_SKIPPROBLEM_TYPE: user specified problem type
* Return:
* true : if solver problem type and user specified problem matches
* false : if not matches
*/
static bool
SkipBasedOnType(
Solver* pSolv,
SolverRuleinfo type,
Id dwSource,
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
)
{
bool result = false;
if (dwSkipProblem & SKIPPROBLEM_CONFLICTS)
{
result = result || type == SOLVER_RULE_PKG_CONFLICTS ||
type == SOLVER_RULE_PKG_SELF_CONFLICT;
}
if (dwSkipProblem & SKIPPROBLEM_OBSOLETES)
{
result = result || type == SOLVER_RULE_PKG_OBSOLETES ||
type == SOLVER_RULE_PKG_IMPLICIT_OBSOLETES ||
type == SOLVER_RULE_PKG_INSTALLED_OBSOLETES;
}
if (dwSkipProblem & SKIPPROBLEM_BROKEN)
{
/* see https://github.com/openSUSE/libsolv/blob/master/src/rules.h */
result = result || type & SOLVER_RULE_PKG;
}
if (dwSkipProblem & SKIPPROBLEM_DISABLED)
{
/**
* If a package was marked not installable and it was disabled,
* then we can skip this error as the package was excluded
* conciously.
*/
if (type == SOLVER_RULE_PKG_NOT_INSTALLABLE)
{
Solvable *s = pSolv->pool->solvables + dwSource;
if (pool_disabled_solvable(pSolv->pool, s)) {
result = true;
}
}
}
return result;
}
static uint32_t
check_for_providers(
PSolvSack pSack,
SolverRuleinfo type,
const char *pszProblem,
char *prv_pkgname
)
{
char *beg;
const char *end;
uint32_t dwError = 0;
char pkgname[256] = {0};
PSolvPackageList pAvailablePkgList = NULL;
if (!pSack || !prv_pkgname || !pszProblem)
{
return ERROR_TDNF_INVALID_PARAMETER;
}
if (type != SOLVER_RULE_PKG_REQUIRES)
{
return dwError;
}
beg = strstr(pszProblem, " requires ");
if (beg)
{
beg += strlen(" requires ");
end = strchr(beg, ',');
}
if (!beg || !end)
{
pr_err("Error while trying to resolve\n");
return ERROR_TDNF_SOLV_FAILED;
}
for (int32_t i = 0; end > beg; beg++)
{
if (*beg != ' ')
{
pkgname[i++] = *beg;
}
}
if (!strcmp(pkgname, prv_pkgname))
{
return dwError;
}
dwError = SolvFindAvailablePkgByName(pSack, pkgname, &pAvailablePkgList);
if (pAvailablePkgList)
{
SolvFreePackageList(pAvailablePkgList);
}
strcpy(prv_pkgname, pkgname);
return dwError;
}
uint32_t
SolvReportProblems(
PSolvSack pSack,
Solver* pSolv,
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
)
{
int nCount = 0;
Id dwDep = 0;
Id dwSource = 0;
Id dwTarget = 0;
SolverRuleinfo type;
uint32_t dwError = 0;
uint32_t total_prblms = 0;
char prv_pkgname[256] = {0};
if (!pSolv)
{
return ERROR_TDNF_INVALID_PARAMETER;
}
nCount = solver_problem_count(pSolv);
for ( ; nCount > 0; nCount--)
{
const char *pszProblem = NULL;
Id dwProblemId = solver_findproblemrule(pSolv, nCount);
type = solver_ruleinfo(pSolv, dwProblemId,
&dwSource, &dwTarget, &dwDep);
if (SkipBasedOnType(pSolv, type, dwSource, dwSkipProblem))
{
continue;
}
pszProblem = solver_problemruleinfo2str(pSolv, type, dwSource,
dwTarget, dwDep);
if (dwSkipProblem != SKIPPROBLEM_NONE &&
type == SOLVER_RULE_PKG_REQUIRES)
{
if (!check_for_providers(pSack, type, pszProblem, prv_pkgname))
{
continue;
}
}
dwError = ERROR_TDNF_SOLV_FAILED;
pr_err("%u. %s\n", ++total_prblms, pszProblem);
}
if (dwError)
{
pr_err("Found %u problem(s) while resolving\n", total_prblms);
}
return dwError;
}
uint32_t
SolvAddExcludes(
Pool* pPool,
char** ppszExcludes
)
{
uint32_t dwError = 0;
Map *pExcludes = NULL;
if (!pPool || !ppszExcludes)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateMemory(
1,
sizeof(Map),
(void**)&pExcludes);
BAIL_ON_TDNF_ERROR(dwError);
map_init(pExcludes, pPool->nsolvables);
dwError = SolvDataIterator(pPool, ppszExcludes, pExcludes);
BAIL_ON_TDNF_ERROR(dwError);
if (!pPool->considered)
{
dwError = TDNFAllocateMemory(
1,
sizeof(Map),
(void**)&pPool->considered);
map_init(pPool->considered, pPool->nsolvables);
map_setall(pPool->considered);
}
map_subtract(pPool->considered, pExcludes);
cleanup:
TDNFFreeMemory(pExcludes);
return dwError;
error:
goto cleanup;
}
uint32_t
SolvDataIterator(
Pool* pPool,
char** ppszExcludes,
Map* pMap
)
{
Dataiterator di;
Id keyname = SOLVABLE_NAME;
char **ppszPkg = NULL;
uint32_t dwError = 0;
if (!pPool || !ppszExcludes || !pMap)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
for (ppszPkg = ppszExcludes; ppszPkg && *ppszPkg; ppszPkg++)
{
int flags = SEARCH_STRING;
if (SolvIsGlob(*ppszPkg))
{
flags = SEARCH_GLOB;
}
dwError = dataiterator_init(&di, pPool, 0, 0, keyname, *ppszPkg, flags);
BAIL_ON_TDNF_ERROR(dwError);
while (dataiterator_step(&di))
{
MAPSET(pMap, di.solvid);
}
dataiterator_free(&di);
}
cleanup:
return dwError;
error:
goto cleanup;
}
int
SolvIsGlob(
const char* pszString
)
{
int nResult = 0;
while(*pszString)
{
char ch = *pszString;
if(ch == '*' || ch == '?' || ch == '[')
{
nResult = 1;
break;
}
pszString++;
}
return nResult;
}
uint32_t
SolvGetNevraFromId(
PSolvSack pSack,
uint32_t dwPkgId,
uint32_t *pdwEpoch,
char **ppszName,
char **ppszVersion,
char **ppszRelease,
char **ppszArch,
char **ppszEVR
)
{
uint32_t dwError = 0;
const char* pszTmp = NULL;
Solvable *pSolv = NULL;
uint32_t dwEpoch = 0;
char *pszName = NULL;
char *pszEpoch = NULL;
char *pszVersion = NULL;
char *pszRelease = NULL;
char *pszArch = NULL;
char *pszEVR = NULL;
if(!pSack ||
!ppszName ||
!ppszVersion ||
!ppszRelease ||
!ppszArch ||
!pdwEpoch)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_NAME);
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszName);
BAIL_ON_TDNF_ERROR(dwError);
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_ARCH);
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszArch);
BAIL_ON_TDNF_ERROR(dwError);
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_EVR);
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszEVR);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvSplitEvr(pSack,
pszTmp,
&pszEpoch,
&pszVersion,
&pszRelease);
BAIL_ON_TDNF_ERROR(dwError);
if(!IsNullOrEmptyString(pszEpoch))
{
dwEpoch = strtol(pszEpoch, NULL, 10);
}
*pdwEpoch = dwEpoch;
*ppszName = pszName;
*ppszVersion = pszVersion;
*ppszRelease = pszRelease;
*ppszArch = pszArch;
if (ppszEVR)
{
*ppszEVR = pszEVR;
}
else
{
TDNF_SAFE_FREE_MEMORY(pszEVR);
}
cleanup:
TDNF_SAFE_FREE_MEMORY(pszEpoch);
return dwError;
error:
if(pdwEpoch)
{
*pdwEpoch = 0;
}
if(ppszName)
{
*ppszName = NULL;
}
if(ppszVersion)
{
*ppszVersion = NULL;
}
if(ppszRelease)
{
*ppszRelease = NULL;
}
if(ppszArch)
{
*ppszArch = NULL;
}
if(ppszEVR)
{
*ppszEVR = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszName);
TDNF_SAFE_FREE_MEMORY(pszVersion);
TDNF_SAFE_FREE_MEMORY(pszRelease);
TDNF_SAFE_FREE_MEMORY(pszArch);
TDNF_SAFE_FREE_MEMORY(pszEVR);
goto cleanup;
}
uint32_t
SolvGetDependenciesFromId(
PSolvSack pSack,
uint32_t dwPkgId,
REPOQUERY_DEP_KEY depKey,
char ***pppszDependencies)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Queue queueDeps = {0};
char **ppszDependencies = NULL;
const char *pszDep = NULL;
int nNumDeps, i, j;
if(!pSack || !pppszDependencies)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if (depKey == REPOQUERY_DEP_KEY_DEPENDS)
{
Id allDepKeys[] = {
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
queue_init(&queueDeps);
for (i = 0; i < (int)ARRAY_SIZE(allDepKeys); i++)
{
Queue queueTmp = {0};
solvable_lookup_deparray(pSolv, allDepKeys[i], &queueTmp, -1);
for (j = 0; j < queueTmp.count; j++)
{
queue_pushunique(&queueDeps, queueTmp.elements[j]);
}
queue_free(&queueTmp);
}
}
else if (depKey == REPOQUERY_DEP_KEY_REQUIRES_PRE)
{
solvable_lookup_deparray(pSolv, SOLVABLE_REQUIRES, &queueDeps, 1);
}
else
{
Id _allDepKeyIds[] = {
SOLVABLE_PROVIDES,
SOLVABLE_OBSOLETES,
SOLVABLE_CONFLICTS,
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
solvable_lookup_deparray(pSolv, _allDepKeyIds[depKey], &queueDeps, -1);
}
nNumDeps = queueDeps.count;
dwError = TDNFAllocateMemory(nNumDeps + 1, sizeof(char *), (void**)&ppszDependencies);
BAIL_ON_TDNF_ERROR(dwError);
for (i = 0; i < nNumDeps; i++)
{
pszDep = pool_dep2str(pSack->pPool, queueDeps.elements[i]);
dwError = TDNFAllocateString(pszDep, &ppszDependencies[i]);
BAIL_ON_TDNF_ERROR(dwError);
}
*pppszDependencies = ppszDependencies;
cleanup:
queue_free(&queueDeps);
return dwError;
error:
TDNFFreeStringArray(ppszDependencies);
goto cleanup;
}
uint32_t
SolvGetFileListFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char ***pppszFiles)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Dataiterator di;
int i = 0, nCount = 0;
char **ppszFiles = NULL;
if(!pSack || !pppszFiles)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId, SOLVABLE_FILELIST, NULL,
SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
while (dataiterator_step(&di)) {
nCount++;
}
dataiterator_free(&di);
dwError = TDNFAllocateMemory(nCount + 1, sizeof(char *), (void**)&ppszFiles);
BAIL_ON_TDNF_ERROR(dwError);
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId, SOLVABLE_FILELIST, NULL,
SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
while (dataiterator_step(&di)) {
dwError = TDNFAllocateString(di.kv.str, &ppszFiles[i++]);
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_free(&di);
*pppszFiles = ppszFiles;
cleanup:
return dwError;
error:
TDNFFreeStringArray(ppszFiles);
goto cleanup;
}
uint32_t
SolvGetFileQueueFromId(
PSolvSack pSack,
uint32_t dwPkgId,
Queue *pQueueFiles)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Dataiterator di;
if(!pSack || !pQueueFiles)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
queue_init(pQueueFiles);
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId,
SOLVABLE_FILELIST, NULL,
SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
while (dataiterator_step(&di)) {
/* apparently file names are not in the pool, so add if needed */
queue_push(pQueueFiles, pool_str2id(pSack->pPool, di.kv.str, 1));
}
dataiterator_free(&di);
cleanup:
return dwError;
error:
queue_free(pQueueFiles);
goto cleanup;
}
uint32_t
SolvGetSourceFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char **ppszName,
char **ppszArch,
char **ppszEVR
)
{
uint32_t dwError = 0;
const char* pszTmp = NULL;
Solvable *pSolv = NULL;
char *pszName = NULL;
char *pszArch = NULL;
char *pszEVR = NULL;
if(!pSack || !ppszName || !ppszArch || !ppszEVR)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_SOURCENAME);
if(!pszTmp)
{
/* if the name is the same we get NULL */
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_NAME);
}
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszName);
BAIL_ON_TDNF_ERROR(dwError);
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_SOURCEARCH);
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszArch);
BAIL_ON_TDNF_ERROR(dwError);
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_SOURCEEVR);
if(!pszTmp)
{
/* if the evr is the same we get NULL */
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_EVR);
}
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszEVR);
BAIL_ON_TDNF_ERROR(dwError);
*ppszName = pszName;
*ppszArch = pszArch;
*ppszEVR = pszEVR;
cleanup:
return dwError;
error:
if (ppszName)
{
*ppszName = NULL;
}
if (ppszArch)
{
*ppszArch = NULL;
}
if (ppszEVR)
{
*ppszEVR = NULL;
}
TDNF_SAFE_FREE_MEMORY(pszName);
TDNF_SAFE_FREE_MEMORY(pszArch);
TDNF_SAFE_FREE_MEMORY(pszEVR);
goto cleanup;
}
uint32_t
SolvGetChangeLogFromId(
PSolvSack pSack,
uint32_t dwPkgId,
PTDNF_PKG_CHANGELOG_ENTRY *ppEntries
)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Dataiterator di;
PTDNF_PKG_CHANGELOG_ENTRY pEntry = NULL;
PTDNF_PKG_CHANGELOG_ENTRY pEntryNext = NULL;
PTDNF_PKG_CHANGELOG_ENTRY pEntries = NULL;
if(!pSack || !ppEntries)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId,
SOLVABLE_CHANGELOG_AUTHOR, NULL, 0);
dataiterator_prepend_keyname(&di, SOLVABLE_CHANGELOG);
while (dataiterator_step(&di)) {
dataiterator_setpos_parent(&di);
pEntryNext = pEntry;
dwError = TDNFAllocateMemory(sizeof(TDNF_PKG_CHANGELOG_ENTRY), 1, (void **)&pEntry);
BAIL_ON_TDNF_ERROR(dwError);
if (pEntries == NULL)
{
pEntries = pEntry;
}
pEntry->pNext = pEntryNext;
pEntry->timeTime =
(time_t)pool_lookup_num(pSack->pPool, SOLVID_POS,
SOLVABLE_CHANGELOG_TIME, 0);
dwError = TDNFAllocateString(
pool_lookup_str(pSack->pPool, SOLVID_POS, SOLVABLE_CHANGELOG_AUTHOR),
&pEntry->pszAuthor);
BAIL_ON_TDNF_ERROR(dwError);
dwError = TDNFAllocateString(
pool_lookup_str(pSack->pPool, SOLVID_POS, SOLVABLE_CHANGELOG_TEXT),
&pEntry->pszText);
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_free(&di);
*ppEntries = pEntry;
cleanup:
return dwError;
error:
/* Coverity false positive, low impact if any */
/* coverity[overwrite_var] */
for (pEntry = pEntries; pEntry; pEntry = pEntryNext)
{
pEntryNext = pEntry->pNext;
TDNFFreeChangeLogEntry(pEntry);
}
goto cleanup;
}
uint32_t
SolvIdIsOrphaned(
PSolvSack pSack,
Id p,
int *pnIsOrphan
)
{
uint32_t dwError = 0;
Id q;
Solvable *s, *t;
int nIsOrphan = 1;
Id allDepKeys[] = {
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
Pool *pPool;
Queue qFiles = {0};
Queue qProvides = {0};
if(!pSack || !pnIsOrphan)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pPool = pSack->pPool;
s = pool_id2solvable(pPool, p);
/* Loop through installed, if any one requires p (aka s) it's not an orphan. */
FOR_REPO_SOLVABLES(pPool->installed, q, t)
{
if (p == q)
{
continue;
}
for (unsigned int k = 0; k < ARRAY_SIZE(allDepKeys); k++)
{
/* deps are names, not solvables, hence we check for s->name
and not p */
if (solvable_matchesdep(t, allDepKeys[k], s->name, 0))
{
nIsOrphan = 0;
goto loopexit; /* we can skip other checks */
}
}
}
/* check if p provides files that are needed by anything installed */
dwError = SolvGetFileQueueFromId(pSack, p, &qFiles);
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
FOR_REPO_SOLVABLES(pPool->installed, q, t)
{
if (p == q)
{
continue;
}
for (int i = 0; i < qFiles.count; i++)
{
for (unsigned int k = 0; k < ARRAY_SIZE(allDepKeys); k++)
{
if (solvable_matchesdep(t, allDepKeys[k], qFiles.elements[i], 0))
{
nIsOrphan = 0;
goto loopexit; /* save 3 break statements */
}
}
}
}
/* Check if p provides something in its provides list needed by an
installed package.
Corner case: two (or more) packages providing the same provide, in
which case all but one of them can be an orphan but we cannot decide which
one. We mark none of them as an orphan. */
solvable_lookup_deparray(s, SOLVABLE_PROVIDES, &qProvides, -1);
FOR_REPO_SOLVABLES(pPool->installed, q, t)
{
if (p == q)
{
continue;
}
for (int i = 0; i < qProvides.count; i++)
{
for (unsigned int k = 0; k < ARRAY_SIZE(allDepKeys); k++)
{
if (solvable_matchesdep(t, allDepKeys[k], qProvides.elements[i], 0))
{
nIsOrphan = 0;
goto loopexit; /* save 3 break statements */
}
}
}
}
loopexit:
*pnIsOrphan = nIsOrphan;
cleanup:
queue_free(&qFiles);
queue_free(&qProvides);
return dwError;
error:
goto cleanup;
}
uint32_t
SolvGetAutoInstalledOrphans(
PSolvSack pSack,
struct history_ctx *pHistoryCtx,
Queue *pQueueAutoInstalled)
{
uint32_t dwError = 0;
Pool *pPool;
Id p;
Solvable *s;
int rc;
if(!pSack || !pQueueAutoInstalled || !pHistoryCtx)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pPool = pSack->pPool;
queue_init(pQueueAutoInstalled);
FOR_REPO_SOLVABLES(pPool->installed, p, s)
{
const char *pszName;
int nIsAuto = 0, nIsOrphan = 0;
pszName = pool_id2str(pPool, s->name);
rc = history_get_auto_flag(pHistoryCtx, pszName, &nIsAuto);
if (rc != 0)
{
dwError = ERROR_TDNF_HISTORY_ERROR;
BAIL_ON_TDNF_ERROR(dwError);
}
if (nIsAuto == 0)
{
continue;
}
dwError = SolvIdIsOrphaned(pSack, p, &nIsOrphan);
BAIL_ON_TDNF_ERROR(dwError);
if (!nIsOrphan)
{
continue;
}
queue_push(pQueueAutoInstalled, p);
}
cleanup:
return dwError;
error:
goto cleanup;
}