Skip to content

Commit

Permalink
builtins.{fetchurl,fetchTarball}: Support a sha256 attribute
Browse files Browse the repository at this point in the history
Also, allow builtins.{fetchurl,fetchTarball} in restricted mode if a
hash is specified.
  • Loading branch information
edolstra committed Jul 26, 2016
1 parent ee3032e commit 06bbfb6
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 12 deletions.
10 changes: 7 additions & 3 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1680,9 +1680,8 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a
void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
const string & who, bool unpack)
{
if (state.restricted) throw Error(format("‘%1%’ is not allowed in restricted mode") % who);

string url;
Hash expectedHash;

state.forceValue(*args[0]);

Expand All @@ -1694,6 +1693,8 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
string name(attr.name);
if (name == "url")
url = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (name == "sha256")
expectedHash = parseHash16or32(htSHA256, state.forceStringNoCtx(*attr.value, *attr.pos));
else
throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
}
Expand All @@ -1704,7 +1705,10 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
} else
url = state.forceStringNoCtx(*args[0], pos);

Path res = makeDownloader()->downloadCached(state.store, url, unpack);
if (state.restricted && !expectedHash)
throw Error(format("‘%1%’ is not allowed in restricted mode") % who);

Path res = makeDownloader()->downloadCached(state.store, url, unpack, expectedHash);
mkString(v, res, PathSet({res}));
}

Expand Down
35 changes: 27 additions & 8 deletions src/libstore/download.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "globals.hh"
#include "hash.hh"
#include "store-api.hh"
#include "archive.hh"

#include <curl/curl.h>

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -258,19 +270,23 @@ 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 {
DownloadOptions options;
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);
Expand Down Expand Up @@ -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;
}

Expand Down
4 changes: 3 additions & 1 deletion src/libstore/download.hh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "types.hh"
#include "hash.hh"

#include <string>

Expand All @@ -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 };
};
Expand Down

0 comments on commit 06bbfb6

Please sign in to comment.