diff options
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/download.cc | 35 | ||||
-rw-r--r-- | src/libstore/download.hh | 4 |
2 files changed, 30 insertions, 9 deletions
diff --git a/src/libstore/download.cc b/src/libstore/download.cc index 04a2b325c651..f099268953ab 100644 --- a/src/libstore/download.cc +++ b/src/libstore/download.cc @@ -3,6 +3,7 @@ #include "globals.hh" #include "hash.hh" #include "store-api.hh" +#include "archive.hh" #include <curl/curl.h> @@ -221,10 +222,21 @@ ref<Downloader> makeDownloader() return make_ref<CurlDownloader>(); } -Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack) +Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, const Hash & expectedHash) { auto url = resolveUri(url_); + string name; + auto p = url.rfind('/'); + if (p != string::npos) name = string(url, p + 1); + + Path expectedStorePath; + if (expectedHash) { + expectedStorePath = store->makeFixedOutputPath(unpack, expectedHash.type, expectedHash, name); + if (store->isValidPath(expectedStorePath)) + return expectedStorePath; + } + Path cacheDir = getCacheDir() + "/nix/tarballs"; createDirs(cacheDir); @@ -258,10 +270,6 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa storePath = ""; } - string name; - auto p = url.rfind('/'); - if (p != string::npos) name = string(url, p + 1); - if (!skip) { try { @@ -269,8 +277,16 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa options.expectedETag = expectedETag; auto res = download(url, options); - if (!res.cached) - storePath = store->addTextToStore(name, *res.data, PathSet(), false); + if (!res.cached) { + ValidPathInfo info; + StringSink sink; + dumpString(*res.data, sink); + Hash hash = hashString(expectedHash ? expectedHash.type : htSHA256, *res.data); + info.path = store->makeFixedOutputPath(false, hash.type, hash, name); + info.narHash = hashString(htSHA256, *sink.s); + store->addToStore(info, *sink.s, false, true); + storePath = info.path; + } assert(!storePath.empty()); replaceSymlink(storePath, fileLink); @@ -300,9 +316,12 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, false); } replaceSymlink(unpackedStorePath, unpackedLink); - return unpackedStorePath; + storePath = unpackedStorePath; } + if (expectedStorePath != "" && storePath != expectedStorePath) + throw nix::Error(format("hash mismatch in file downloaded from ‘%s’") % url); + return storePath; } diff --git a/src/libstore/download.hh b/src/libstore/download.hh index eb2b76678ac7..efddc55281fe 100644 --- a/src/libstore/download.hh +++ b/src/libstore/download.hh @@ -1,6 +1,7 @@ #pragma once #include "types.hh" +#include "hash.hh" #include <string> @@ -27,7 +28,8 @@ struct Downloader { virtual DownloadResult download(string url, const DownloadOptions & options) = 0; - Path downloadCached(ref<Store> store, const string & url, bool unpack); + Path downloadCached(ref<Store> store, const string & url, bool unpack, + const Hash & expectedHash = Hash()); enum Error { NotFound, Forbidden, Misc }; }; |