From e124b3654eec9cac66792e0fe77cbde0ad99f059 Mon Sep 17 00:00:00 2001
From: Keerthana K <keerthanak@vmware.com>
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 <sys/utsname.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
 // libsolv
 #include <solv/evr.h>
 #include <solv/pool.h>
@@ -20,6 +22,7 @@
 #include <solv/selection.h>
 #include <solv/solverdebug.h>
 #include <solv/testcase.h>
+#include <solv/chksum.h>
 
 #include <tdnf.h>
 #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;
+}