From e124b3654eec9cac66792e0fe77cbde0ad99f059 Mon Sep 17 00:00:00 2001 From: Keerthana K Date: Fri, 23 Nov 2018 07:11:23 +0000 Subject: [PATCH] Support for Libsolv caching of metadata This change includes the support of libsolv caching of metadata which is a .solv file. When the cache is created, tdnf creates a metadata cache file (*.solv) in cache directory (/var/cache/tdnf/REPO-NAME/solvcache/). This is consumed by tdnf in subsequent tdnf operations till the refresh timer expires. Solv cache file improves the time consumed by tdnf operation which results in quicker results. Change-Id: I42894260b8e9a110188c38027fc480dd83bfdc10 --- diff --git a/client/defines.h b/client/defines.h index c112074..e604c49 100644 --- a/client/defines.h +++ b/client/defines.h @@ -139,6 +139,7 @@ #define TDNF_DEFAULT_DISTROARCHPKG "x86_64" #define TDNF_RPM_CACHE_DIR_NAME "rpms" #define TDNF_REPODATA_DIR_NAME "repodata" +#define TDNF_SOLVCACHE_DIR_NAME "solvcache" #define TDNF_REPO_DEFAULT_METADATA_EXPIRE "8294400"//48 hours in seconds #define TDNF_REPO_METADATA_EXPIRE_NEVER "never" //var names @@ -177,6 +178,10 @@ {ERROR_TDNF_SOLV_VALIDATION, "ERROR_TDNF_SOLV_VALIDATION", "Solv - validation check failed"}, \ {ERROR_TDNF_SOLV_NO_SOLUTION, "ERROR_TDNF_SOLV_NO_SOLUTION", "Solv - goal found no solutions"}, \ {ERROR_TDNF_SOLV_NO_CAPABILITY, "ERROR_TDNF_SOLV_NO_CAPABILITY", "Solv - the capability was not available"}, \ + {ERROR_TDNF_SOLV_CHKSUM, "ERROR_TDNF_SOLV_CHKSUM", "Solv - Checksum creation failed"}, \ + {ERROR_TDNF_REPO_WRITE, "ERROR_TDNF_REPO_WRITE", "Solv - Failed to write repo"}, \ + {ERROR_TDNF_SOLV_CACHE_NOT_CREATED, "ERROR_TDNF_SOLV_CACHE_NOT_CREATED", "Solv - Solv cache not found"}, \ + {ERROR_TDNF_ADD_SOLV, "ERROR_TDNF_ADD_SOLV", "Solv - Failed to add solv"}, \ {ERROR_TDNF_REPO_BASE, "ERROR_TDNF_REPO_BASE", "Repo error base"}, \ {ERROR_TDNF_REPO_PERFORM, "ERROR_TDNF_REPO_PERFORM", "Error during repo handle execution"}, \ {ERROR_TDNF_REPO_GETINFO, "ERROR_TDNF_REPO_GETINFO", "Repo during repo result getinfo"}, \ diff --git a/client/init.c b/client/init.c index 493bf7e..8823599 100644 --- a/client/init.c +++ b/client/init.c @@ -226,6 +226,13 @@ dwError = 0;//Ignore non existent folders } BAIL_ON_TDNF_ERROR(dwError); + + dwError = TDNFRemoveSolvCache(pTdnf, pTempRepo->pszId); + if(dwError == ERROR_TDNF_FILE_NOT_FOUND) + { + dwError = 0;//Ignore non existent folders + } + BAIL_ON_TDNF_ERROR(dwError); } if(pSack) diff --git a/client/prototypes.h b/client/prototypes.h index 7bfb714..87e8dfe 100644 --- a/client/prototypes.h +++ b/client/prototypes.h @@ -125,6 +125,12 @@ ); uint32_t +TDNFRemoveSolvCache( + PTDNF pTdnf, + const char* pszRepoId + ); + +uint32_t TDNFRepoApplyProxySettings( PTDNF_CONF pConf, CURL *pCurl @@ -424,7 +430,7 @@ //repo.c uint32_t TDNFInitRepoFromMetadata( - PSolvSack pSack, + Repo *pRepo, const char* pszRepoName, PTDNF_REPO_METADATA pRepoMD ); @@ -768,11 +774,6 @@ uint32_t TDNFUtilsMakeDir( - const char* pszPath - ); - -uint32_t -TDNFUtilsMakeDirs( const char* pszPath ); diff --git a/client/repo.c b/client/repo.c index 01b1f8f..5967689 100644 --- a/client/repo.c +++ b/client/repo.c @@ -34,14 +34,19 @@ char* pszLastRefreshMarker = NULL; PTDNF_REPO_METADATA pRepoMD = NULL; PTDNF_CONF pConf = NULL; + Repo* pRepo = NULL; + Pool* pPool = NULL;; + int nUseMetaDataCache = 0; + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo = NULL; - if(!pTdnf || !pTdnf->pConf || !pRepoData || !pSack) + if(!pTdnf || !pTdnf->pConf || !pRepoData || !pSack || !pSack->pPool) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_ERROR(dwError); } pConf = pTdnf->pConf; + pPool = pSack->pPool; dwError = TDNFAllocateStringPrintf( &pszRepoCacheDir, @@ -63,8 +68,38 @@ &pRepoMD); BAIL_ON_TDNF_ERROR(dwError); - dwError = TDNFInitRepoFromMetadata(pSack, pRepoData->pszId, pRepoMD); + dwError = TDNFAllocateMemory( + 1, + sizeof(SOLV_REPO_INFO_INTERNAL), + (void**)&pSolvRepoInfo); BAIL_ON_TDNF_ERROR(dwError); + + pRepo = repo_create(pPool, pRepoData->pszId); + + if (!pRepo) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + pSolvRepoInfo->pRepo = pRepo; + pRepo->appdata = pSolvRepoInfo; + + dwError = SolvCalculateCookieForRepoMD(pRepoMD->pszRepoMD, pSolvRepoInfo->cookie); + BAIL_ON_TDNF_ERROR(dwError); + + pSolvRepoInfo->nCookieSet = 1; + dwError = SolvUseMetaDataCache(pSack, pSolvRepoInfo, &nUseMetaDataCache); + BAIL_ON_TDNF_ERROR(dwError); + + if (nUseMetaDataCache == 0) + { + dwError = TDNFInitRepoFromMetadata(pSolvRepoInfo->pRepo, pRepoData->pszId, pRepoMD); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = SolvCreateMetaDataCache(pSack, pSolvRepoInfo); + BAIL_ON_TDNF_ERROR(dwError); + } + pool_createwhatprovides(pPool); dwError = TDNFAllocateStringPrintf( &pszLastRefreshMarker, @@ -81,9 +116,13 @@ TDNF_SAFE_FREE_MEMORY(pszLastRefreshMarker); TDNF_SAFE_FREE_MEMORY(pszRepoDataDir); TDNF_SAFE_FREE_MEMORY(pszRepoCacheDir); + TDNF_SAFE_FREE_MEMORY(pSolvRepoInfo); return dwError; - error: + if(pRepo) + { + repo_free(pRepo, 1); + } //If there is an error during init, log the error //remove any cache data that could be potentially corrupt. if(pRepoData) @@ -101,23 +140,22 @@ } goto cleanup; } - uint32_t TDNFInitRepoFromMetadata( - PSolvSack pSack, + Repo *pRepo, const char* pszRepoName, PTDNF_REPO_METADATA pRepoMD ) { uint32_t dwError = 0; - if(!pSack || !pRepoMD || IsNullOrEmptyString(pszRepoName)) + if(!pRepo || !pRepoMD || IsNullOrEmptyString(pszRepoName)) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_ERROR(dwError); } - dwError = SolvReadYumRepo(pSack, + dwError = SolvReadYumRepo(pRepo, pszRepoName, pRepoMD->pszRepoMD, pRepoMD->pszPrimary, diff --git a/client/repoutils.c b/client/repoutils.c index 179ad96..63040ea 100644 --- a/client/repoutils.c +++ b/client/repoutils.c @@ -277,6 +277,87 @@ } uint32_t +TDNFRemoveSolvCache( + PTDNF pTdnf, + const char* pszRepoId + ) +{ + uint32_t dwError = 0; + char* pszSolvCacheDir = NULL; + char* pszFilePath = NULL; + DIR *pDir = NULL; + struct dirent *pEnt = NULL; + + if(!pTdnf || !pTdnf->pConf || IsNullOrEmptyString(pszRepoId)) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + + dwError = TDNFAllocateStringPrintf( + &pszSolvCacheDir, + "%s/%s/%s", + pTdnf->pConf->pszCacheDir, + pszRepoId, + TDNF_SOLVCACHE_DIR_NAME); + BAIL_ON_TDNF_ERROR(dwError); + + pDir = opendir(pszSolvCacheDir); + if(pDir == NULL) + { + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR(dwError); + } + + while ((pEnt = readdir (pDir)) != NULL ) + { + if (!strcmp(pEnt->d_name, ".") || !strcmp(pEnt->d_name, "..")) + { + continue; + } + + dwError = TDNFAllocateStringPrintf( + &pszFilePath, + "%s/%s", + pszSolvCacheDir, + pEnt->d_name); + BAIL_ON_TDNF_ERROR(dwError); + if(pszFilePath) + { + if(unlink(pszFilePath)) + { + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR(dwError); + } + TDNF_SAFE_FREE_MEMORY(pszFilePath); + pszFilePath = NULL; + } + else + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + } + if(rmdir(pszSolvCacheDir)) + { + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR(dwError); + } + +cleanup: + TDNF_SAFE_FREE_MEMORY(pszFilePath); + TDNF_SAFE_FREE_MEMORY(pszSolvCacheDir); + if(pDir) + { + closedir(pDir); + } + return dwError; + +error: + goto cleanup; +} + +uint32_t TDNFRepoApplyProxySettings( PTDNF_CONF pConf, CURL *pCurl diff --git a/common/prototypes.h b/common/prototypes.h index 9508dc1..50cd00f 100644 --- a/common/prototypes.h +++ b/common/prototypes.h @@ -136,3 +136,8 @@ TDNFFreePackageInfoContents( PTDNF_PKG_INFO pPkgInfo ); + +uint32_t +TDNFUtilsMakeDirs( + const char* pszPath + ); diff --git a/include/tdnferror.h b/include/tdnferror.h index 9033efc..1be2b0f 100644 --- a/include/tdnferror.h +++ b/include/tdnferror.h @@ -92,6 +92,14 @@ #define ERROR_TDNF_SOLV_NO_SOLUTION (ERROR_TDNF_SOLV_BASE + 10) // the capability was not available #define ERROR_TDNF_SOLV_NO_CAPABILITY (ERROR_TDNF_SOLV_BASE + 11) +// Solv Checksum Error +#define ERROR_TDNF_SOLV_CHKSUM (ERROR_TDNF_SOLV_BASE + 12) +// Solv file write failed +#define ERROR_TDNF_REPO_WRITE (ERROR_TDNF_SOLV_BASE + 13) +// Solv File not created +#define ERROR_TDNF_SOLV_CACHE_NOT_CREATED (ERROR_TDNF_SOLV_BASE + 14) +// Add solv file to repo failed +#define ERROR_TDNF_ADD_SOLV (ERROR_TDNF_SOLV_BASE + 15) //Repo errors 1400 to 1469 #define ERROR_TDNF_REPO_BASE 1400 diff --git a/solv/defines.h b/solv/defines.h index 2796d56..79a5444 100644 --- a/solv/defines.h +++ b/solv/defines.h @@ -1,5 +1,8 @@ #define SYSTEM_REPO_NAME "@System" #define CMDLINE_REPO_NAME "@commandline" +#define SOLV_COOKIE_IDENT "tdnf" +#define TDNF_SOLVCACHE_DIR_NAME "solvcache" +#define SOLV_COOKIE_LEN 32 #define BAIL_ON_TDNF_LIBSOLV_ERROR(dwError) \ do { \ diff --git a/solv/includes.h b/solv/includes.h index 6e26b66..d2f0903 100644 --- a/solv/includes.h +++ b/solv/includes.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include // libsolv #include #include @@ -20,6 +22,7 @@ #include #include #include +#include #include #include "defines.h" diff --git a/solv/prototypes.h b/solv/prototypes.h index 2484649..d8a3f41 100644 --- a/solv/prototypes.h +++ b/solv/prototypes.h @@ -36,6 +36,13 @@ Queue queuePackages; } SolvPackageList, *PSolvPackageList; +typedef struct _SOLV_REPO_INFO_INTERNAL_ +{ + Repo* pRepo; + unsigned char cookie[SOLV_COOKIE_LEN]; + int nCookieSet; +}SOLV_REPO_INFO_INTERNAL, *PSOLV_REPO_INFO_INTERNAL; + // tdnfpackage.c uint32_t SolvGetPkgInfoFromId( @@ -412,7 +419,7 @@ // tdnfrepo.c uint32_t SolvReadYumRepo( - PSolvSack pSack, + Repo *pRepo, const char *pszRepoName, const char *pszRepomd, const char *pszPrimary, @@ -479,6 +486,39 @@ SolvIsGlob( const char* pszString ); + +uint32_t +SolvCalculateCookieForRepoMD( + char* pszRepoMD, + unsigned char* pszCookie + ); + +uint32_t +SolvGetMetaDataCachePath( + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo, + PSolvSack pSack, + char** ppszCachePath + ); + +uint32_t +SolvAddSolvMetaData( + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo, + char *pszTempSolvFile + ); + +uint32_t +SolvCreateMetaDataCache( + PSolvSack pSack, + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo + ); + +uint32_t +SolvUseMetaDataCache( + PSolvSack pSack, + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo, + int *nUseMetaDataCache + ); + #ifdef __cplusplus } #endif diff --git a/solv/tdnfrepo.c b/solv/tdnfrepo.c index 76b8b62..b243c36 100644 --- a/solv/tdnfrepo.c +++ b/solv/tdnfrepo.c @@ -152,7 +152,7 @@ uint32_t SolvReadYumRepo( - PSolvSack pSack, + Repo *pRepo, const char *pszRepoName, const char *pszRepomd, const char *pszPrimary, @@ -161,21 +161,12 @@ ) { uint32_t dwError = 0; - Repo* pRepo = NULL; - Pool* pPool = NULL; - if(!pSack || !pSack->pPool || !pszRepoName || !pszRepomd || !pszPrimary) + if(!pRepo || !pszRepoName || !pszRepomd || !pszPrimary) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); } - pPool = pSack->pPool; - pRepo = repo_create(pPool, pszRepoName); - if( !pRepo ) - { - dwError = ERROR_TDNF_INVALID_PARAMETER; - BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); - } dwError = SolvLoadRepomd(pRepo, pszRepomd); BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); @@ -196,17 +187,12 @@ BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); } - pool_createwhatprovides(pPool); cleanup: return dwError; error: - if(pRepo) - { - repo_free(pRepo, 1); - } goto cleanup; } @@ -288,4 +274,329 @@ repo_free(pRepo, 1); } goto cleanup; -} \ No newline at end of file +} + +uint32_t +SolvCalculateCookieForRepoMD( + char* pszRepoMD, + unsigned char* pszCookie + ) +{ + uint32_t dwError = 0; + FILE *fp = NULL; + Chksum *pChkSum = NULL; + int nLen = 0; + char buf[4096]; + + if (!pszRepoMD) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + fp = fopen(pszRepoMD, "r"); + if (fp == NULL) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + pChkSum = solv_chksum_create(REPOKEY_TYPE_SHA256); + if (!pChkSum) + { + dwError = ERROR_TDNF_SOLV_CHKSUM; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + solv_chksum_add(pChkSum, SOLV_COOKIE_IDENT, strlen(SOLV_COOKIE_IDENT)); + + while ((nLen = fread(buf, 1, sizeof(buf), fp)) > 0) + { + solv_chksum_add(pChkSum, buf, nLen); + } + solv_chksum_free(pChkSum, pszCookie); + +cleanup: + if (fp != NULL) + { + fclose(fp); + } + return dwError; +error: + goto cleanup; +} + +uint32_t +SolvGetMetaDataCachePath( + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo, + PSolvSack pSack, + char** ppszCachePath + ) +{ + char *pszCachePath = NULL; + uint32_t dwError = 0; + Repo *pRepo = NULL; + + if (!pSolvRepoInfo || !pSack || !pSolvRepoInfo->pRepo || !ppszCachePath) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + pRepo = pSolvRepoInfo->pRepo; + if (!IsNullOrEmptyString(pRepo->name)) + { + dwError = TDNFAllocateStringPrintf( + &pszCachePath, + "%s/%s/%s/%s.solv", + pSack->pszCacheDir, + pRepo->name, + TDNF_SOLVCACHE_DIR_NAME, + pRepo->name); + BAIL_ON_TDNF_ERROR(dwError); + } + *ppszCachePath = pszCachePath; +cleanup: + return dwError; +error: + TDNF_SAFE_FREE_MEMORY(pszCachePath); + goto cleanup; +} + +uint32_t +SolvAddSolvMetaData( + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo, + char *pszTempSolvFile + ) +{ + uint32_t dwError = 0; + Repo *pRepo = NULL; + FILE *fp = NULL; + int i = 0; + + if (!pSolvRepoInfo || !pSolvRepoInfo->pRepo || !pszTempSolvFile) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + pRepo = pSolvRepoInfo->pRepo; + if (!pRepo->pool) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + for (i = pRepo->start; i < pRepo->end; i++) + { + if (pRepo->pool->solvables[i].repo != pRepo) + { + break; + } + } + if (i < pRepo->end) + { + goto cleanup; + } + fp = fopen (pszTempSolvFile, "r"); + if (fp == NULL) + { + dwError = errno; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + repo_empty(pRepo, 1); + if (repo_add_solv(pRepo, fp, SOLV_ADD_NO_STUBS)) + { + dwError = ERROR_TDNF_ADD_SOLV; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + +cleanup: + if (fp != NULL) + { + fclose(fp); + } + return dwError; +error: + goto cleanup; +} + +uint32_t +SolvUseMetaDataCache( + PSolvSack pSack, + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo, + int *nUseMetaDataCache + ) +{ + uint32_t dwError = 0; + FILE *fp = NULL; + Repo *pRepo = NULL; + unsigned char *pszCookie = NULL; + unsigned char pszTempCookie[32]; + char *pszCacheFilePath = NULL; + + if (!pSack || !pSolvRepoInfo || !pSolvRepoInfo->pRepo) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + pRepo = pSolvRepoInfo->pRepo; + pszCookie = pSolvRepoInfo->nCookieSet ? pSolvRepoInfo->cookie : 0; + + dwError = SolvGetMetaDataCachePath(pSolvRepoInfo, pSack, &pszCacheFilePath); + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + + if (IsNullOrEmptyString(pszCacheFilePath)) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + fp = fopen(pszCacheFilePath, "r"); + if (fp == NULL) + { + dwError = ERROR_TDNF_SOLV_CACHE_NOT_CREATED; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + // Reading the cookie from cached Solv File + if (fseek (fp, -sizeof(pszTempCookie), SEEK_END) || fread (pszTempCookie, sizeof(pszTempCookie), 1, fp) != 1) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + // compare the calculated cookie with the one read from Solv file + if (pszCookie && memcmp (pszCookie, pszTempCookie, sizeof(pszTempCookie)) != 0) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + rewind(fp); + if (repo_add_solv(pRepo, fp, 0)) + { + dwError = ERROR_TDNF_ADD_SOLV; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + *nUseMetaDataCache = 1; + +cleanup: + if (fp != NULL) + { + fclose(fp); + } + TDNF_SAFE_FREE_MEMORY(pszCacheFilePath); + return dwError; +error: + if (dwError == ERROR_TDNF_SOLV_CACHE_NOT_CREATED) + { + dwError = 0; + } + goto cleanup; +} + +uint32_t +SolvCreateMetaDataCache( + PSolvSack pSack, + PSOLV_REPO_INFO_INTERNAL pSolvRepoInfo + ) +{ + uint32_t dwError = 0; + Repo *pRepo = NULL; + FILE *fp = NULL; + int fd = 0; + char *pszSolvCacheDir = NULL; + char *pszTempSolvFile = NULL; + char *pszCacheFilePath = NULL; + + if (!pSack || !pSolvRepoInfo|| !pSolvRepoInfo->nCookieSet) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + pRepo = pSolvRepoInfo->pRepo; + dwError = TDNFAllocateStringPrintf( + &pszSolvCacheDir, + "%s/%s/%s", + pSack->pszCacheDir, + pRepo->name, + TDNF_SOLVCACHE_DIR_NAME); + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + + if (access(pszSolvCacheDir, W_OK| X_OK) != 0) + { + if(errno != ENOENT) + { + dwError = errno; + } + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + + dwError = TDNFUtilsMakeDirs(pszSolvCacheDir); + if (dwError == ERROR_TDNF_ALREADY_EXISTS) + { + dwError = 0; + } + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + pszTempSolvFile = solv_dupjoin(pszSolvCacheDir, "/", ".newsolv-XXXXXX"); + fd = mkstemp(pszTempSolvFile); + if (fd < 0) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + fchmod (fd, 0444); + fp = fdopen(fd, "w"); + if (fp == NULL) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + if (repo_write(pRepo, fp)) + { + dwError = ERROR_TDNF_REPO_WRITE; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + if (fwrite(pSolvRepoInfo->cookie, SOLV_COOKIE_LEN, 1, fp) != 1) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + if (fclose(fp)) + { + dwError = ERROR_TDNF_SOLV_IO; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + fp = NULL; + dwError = SolvAddSolvMetaData(pSolvRepoInfo, pszTempSolvFile); + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + + dwError = SolvGetMetaDataCachePath(pSolvRepoInfo, pSack, &pszCacheFilePath); + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + + if (IsNullOrEmptyString(pszCacheFilePath)) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + if (rename (pszTempSolvFile, pszCacheFilePath)) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + unlink(pszTempSolvFile); +cleanup: + TDNF_SAFE_FREE_MEMORY(pszTempSolvFile); + TDNF_SAFE_FREE_MEMORY(pszSolvCacheDir); + TDNF_SAFE_FREE_MEMORY(pszCacheFilePath); + return dwError; +error: + if (fp != NULL) + { + fclose(fp); + unlink(pszTempSolvFile); + } + else if (fd > 0) + { + close(fd); + unlink(pszTempSolvFile); + } + goto cleanup; +}