Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/libcmd/include/nix/cmd/command.hh
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,20 @@ struct MixEnvironment : virtual Args
void setEnviron();
};

struct MixNoCheckSigs : virtual Args
{
CheckSigsFlag checkSigs = CheckSigs;

MixNoCheckSigs()
{
addFlag({
.longName = "no-check-sigs",
.description = "Do not require that paths are signed by trusted keys.",
.handler = {&checkSigs, NoCheckSigs},
});
}
};

void completeFlakeInputAttrPath(
AddCompletions & completions,
ref<EvalState> evalState,
Expand Down
2 changes: 1 addition & 1 deletion src/libmain/shared.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ int handleExceptions(const std::string & programName, std::function<void()> fun)
return e.status;
} catch (UsageError & e) {
logError(e.info());
printError("Try '%1% --help' for more information.", programName);
printError("\nTry '%1% --help' for more information.", programName);
return 1;
} catch (BaseError & e) {
logError(e.info());
Expand Down
10 changes: 6 additions & 4 deletions src/libstore/common-protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ void CommonProto::Serialise<std::string>::write(

StorePath CommonProto::Serialise<StorePath>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)
{
return store.parseStorePath(readString(conn.from));
return conn.shortStorePaths ? StorePath(readString(conn.from)) : store.parseStorePath(readString(conn.from));
}

void CommonProto::Serialise<StorePath>::write(
const StoreDirConfig & store, CommonProto::WriteConn conn, const StorePath & storePath)
{
conn.to << store.printStorePath(storePath);
conn.to << (conn.shortStorePaths ? storePath.to_string() : store.printStorePath(storePath));
}

ContentAddress CommonProto::Serialise<ContentAddress>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)
Expand Down Expand Up @@ -73,13 +73,15 @@ std::optional<StorePath>
CommonProto::Serialise<std::optional<StorePath>>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)
{
auto s = readString(conn.from);
return s == "" ? std::optional<StorePath>{} : store.parseStorePath(s);
return s == "" ? std::optional<StorePath>{} : conn.shortStorePaths ? StorePath(s) : store.parseStorePath(s);
}

void CommonProto::Serialise<std::optional<StorePath>>::write(
const StoreDirConfig & store, CommonProto::WriteConn conn, const std::optional<StorePath> & storePathOpt)
{
conn.to << (storePathOpt ? store.printStorePath(*storePathOpt) : "");
conn.to
<< (storePathOpt ? (conn.shortStorePaths ? storePathOpt->to_string() : store.printStorePath(*storePathOpt))
: "");
}

std::optional<ContentAddress>
Expand Down
204 changes: 132 additions & 72 deletions src/libstore/export-import.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,152 @@
#include "nix/util/archive.hh"
#include "nix/store/common-protocol.hh"
#include "nix/store/common-protocol-impl.hh"

#include <algorithm>
#include "nix/store/worker-protocol.hh"

namespace nix {

static void exportPath(Store & store, const StorePath & path, Sink & sink)
{
auto info = store.queryPathInfo(path);

HashSink hashSink(HashAlgorithm::SHA256);
TeeSink teeSink(sink, hashSink);

store.narFromPath(path, teeSink);

/* Refuse to export paths that have changed. This prevents
filesystem corruption from spreading to other machines.
Don't complain if the stored hash is zero (unknown). */
Hash hash = hashSink.currentHash().hash;
if (hash != info->narHash && info->narHash != Hash(info->narHash.algo))
throw Error(
"hash of path '%s' has changed from '%s' to '%s'!",
store.printStorePath(path),
info->narHash.to_string(HashFormat::Nix32, true),
hash.to_string(HashFormat::Nix32, true));

teeSink << exportMagic << store.printStorePath(path);
CommonProto::write(store, CommonProto::WriteConn{.to = teeSink}, info->references);
teeSink << (info->deriver ? store.printStorePath(*info->deriver) : "") << 0;
}
static const uint32_t exportMagicV1 = 0x4558494e;
static const uint64_t exportMagicV2 = 0x324f4952414e; // = 'NARIO2'

void exportPaths(Store & store, const StorePathSet & paths, Sink & sink)
void exportPaths(Store & store, const StorePathSet & paths, Sink & sink, unsigned int version)
{
auto sorted = store.topoSortPaths(paths);
std::reverse(sorted.begin(), sorted.end());

for (auto & path : sorted) {
sink << 1;
exportPath(store, path, sink);
auto dumpNar = [&](const ValidPathInfo & info) {
HashSink hashSink(HashAlgorithm::SHA256);
TeeSink teeSink(sink, hashSink);

store.narFromPath(info.path, teeSink);

/* Refuse to export paths that have changed. This prevents
filesystem corruption from spreading to other machines.
Don't complain if the stored hash is zero (unknown). */
Hash hash = hashSink.currentHash().hash;
if (hash != info.narHash && info.narHash != Hash(info.narHash.algo))
throw Error(
"hash of path '%s' has changed from '%s' to '%s'!",
store.printStorePath(info.path),
info.narHash.to_string(HashFormat::Nix32, true),
hash.to_string(HashFormat::Nix32, true));
};

switch (version) {

case 1:
for (auto & path : sorted) {
sink << 1;
auto info = store.queryPathInfo(path);
dumpNar(*info);
sink << exportMagicV1 << store.printStorePath(path);
CommonProto::write(store, CommonProto::WriteConn{.to = sink}, info->references);
sink << (info->deriver ? store.printStorePath(*info->deriver) : "") << 0;
}
sink << 0;
break;

case 2:
sink << exportMagicV2;

for (auto & path : sorted) {
Activity act(*logger, lvlTalkative, actUnknown, fmt("exporting path '%s'", store.printStorePath(path)));
sink << 1;
auto info = store.queryPathInfo(path);
// FIXME: move to CommonProto?
WorkerProto::Serialise<ValidPathInfo>::write(
store, WorkerProto::WriteConn{.to = sink, .version = 16, .shortStorePaths = true}, *info);
dumpNar(*info);
}

sink << 0;
break;

default:
throw Error("unsupported nario version %d", version);
}

sink << 0;
}

StorePaths importPaths(Store & store, Source & source, CheckSigsFlag checkSigs)
{
StorePaths res;
while (true) {
auto n = readNum<uint64_t>(source);
if (n == 0)
break;
if (n != 1)
throw Error("input doesn't look like something created by 'nix-store --export'");

/* Extract the NAR from the source. */
StringSink saved;
TeeSource tee{source, saved};
NullFileSystemObjectSink ether;
parseDump(ether, tee);

uint32_t magic = readInt(source);
if (magic != exportMagic)
throw Error("Nix archive cannot be imported; wrong format");

auto path = store.parseStorePath(readString(source));

// Activity act(*logger, lvlInfo, "importing path '%s'", info.path);

auto references = CommonProto::Serialise<StorePathSet>::read(store, CommonProto::ReadConn{.from = source});
auto deriver = readString(source);
auto narHash = hashString(HashAlgorithm::SHA256, saved.s);

ValidPathInfo info{path, narHash};
if (deriver != "")
info.deriver = store.parseStorePath(deriver);
info.references = references;
info.narSize = saved.s.size();

// Ignore optional legacy signature.
if (readInt(source) == 1)
readString(source);

// Can't use underlying source, which would have been exhausted
auto source = StringSource(saved.s);
store.addToStore(info, source, NoRepair, checkSigs);

res.push_back(info.path);

auto version = readNum<uint64_t>(source);

/* Note: nario version 1 lacks an explicit header. The first
integer denotes whether a store path follows or not. So look
for 0 or 1. */
switch (version) {

case 0:
/* Empty version 1 nario, nothing to do. */
break;

case 1:
/* Non-empty version 1 nario. */
while (true) {
/* Extract the NAR from the source. */
StringSink saved;
TeeSource tee{source, saved};
NullFileSystemObjectSink ether;
parseDump(ether, tee);

uint32_t magic = readInt(source);
if (magic != exportMagicV1)
throw Error("nario cannot be imported; wrong format");

auto path = store.parseStorePath(readString(source));

auto references = CommonProto::Serialise<StorePathSet>::read(store, CommonProto::ReadConn{.from = source});
auto deriver = readString(source);
auto narHash = hashString(HashAlgorithm::SHA256, saved.s);

ValidPathInfo info{path, narHash};
if (deriver != "")
info.deriver = store.parseStorePath(deriver);
info.references = references;
info.narSize = saved.s.size();

// Ignore optional legacy signature.
if (readInt(source) == 1)
readString(source);

// Can't use underlying source, which would have been exhausted.
auto source2 = StringSource(saved.s);
store.addToStore(info, source2, NoRepair, checkSigs);

res.push_back(info.path);

auto n = readNum<uint64_t>(source);
if (n == 0)
break;
if (n != 1)
throw Error("input doesn't look like a nario");
}
break;

case exportMagicV2:
while (true) {
auto n = readNum<uint64_t>(source);
if (n == 0)
break;
if (n != 1)
throw Error("input doesn't look like a nario");

auto info = WorkerProto::Serialise<ValidPathInfo>::read(
store, WorkerProto::ReadConn{.from = source, .version = 16, .shortStorePaths = true});

Activity act(
*logger, lvlTalkative, actUnknown, fmt("importing path '%s'", store.printStorePath(info.path)));

store.addToStore(info, source, NoRepair, checkSigs);

res.push_back(info.path);
}

break;

default:
throw Error("input doesn't look like a nario");
}

return res;
Expand Down
2 changes: 2 additions & 0 deletions src/libstore/include/nix/store/common-protocol.hh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct CommonProto
struct ReadConn
{
Source & from;
bool shortStorePaths = false;
};

/**
Expand All @@ -39,6 +40,7 @@ struct CommonProto
struct WriteConn
{
Sink & to;
bool shortStorePaths = false;
};

template<typename T>
Expand Down
7 changes: 1 addition & 6 deletions src/libstore/include/nix/store/export-import.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@

namespace nix {

/**
* Magic header of exportPath() output (obsolete).
*/
const uint32_t exportMagic = 0x4558494e;

/**
* Export multiple paths in the format expected by `nix-store
* --import`. The paths will be sorted topologically.
*/
void exportPaths(Store & store, const StorePathSet & paths, Sink & sink);
void exportPaths(Store & store, const StorePathSet & paths, Sink & sink, unsigned int version);

/**
* Import a sequence of NAR dumps created by `exportPaths()` into the
Expand Down
6 changes: 4 additions & 2 deletions src/libstore/include/nix/store/worker-protocol-impl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ struct WorkerProto::Serialise
{
static T read(const StoreDirConfig & store, WorkerProto::ReadConn conn)
{
return CommonProto::Serialise<T>::read(store, CommonProto::ReadConn{.from = conn.from});
return CommonProto::Serialise<T>::read(
store, CommonProto::ReadConn{.from = conn.from, .shortStorePaths = conn.shortStorePaths});
}

static void write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const T & t)
{
CommonProto::Serialise<T>::write(store, CommonProto::WriteConn{.to = conn.to}, t);
CommonProto::Serialise<T>::write(
store, CommonProto::WriteConn{.to = conn.to, .shortStorePaths = conn.shortStorePaths}, t);
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/libstore/include/nix/store/worker-protocol.hh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct WorkerProto
{
Source & from;
Version version;
bool shortStorePaths = false;
};

/**
Expand All @@ -76,6 +77,7 @@ struct WorkerProto
{
Sink & to;
Version version;
bool shortStorePaths = false;
};

/**
Expand Down
9 changes: 4 additions & 5 deletions src/libstore/worker-protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,10 @@ void WorkerProto::Serialise<ValidPathInfo>::write(

UnkeyedValidPathInfo WorkerProto::Serialise<UnkeyedValidPathInfo>::read(const StoreDirConfig & store, ReadConn conn)
{
auto deriver = readString(conn.from);
auto deriver = WorkerProto::Serialise<std::optional<StorePath>>::read(store, conn);
auto narHash = Hash::parseAny(readString(conn.from), HashAlgorithm::SHA256);
UnkeyedValidPathInfo info(narHash);
if (deriver != "")
info.deriver = store.parseStorePath(deriver);
info.deriver = std::move(deriver);
info.references = WorkerProto::Serialise<StorePathSet>::read(store, conn);
conn.from >> info.registrationTime >> info.narSize;
if (GET_PROTOCOL_MINOR(conn.version) >= 16) {
Expand All @@ -237,8 +236,8 @@ UnkeyedValidPathInfo WorkerProto::Serialise<UnkeyedValidPathInfo>::read(const St
void WorkerProto::Serialise<UnkeyedValidPathInfo>::write(
const StoreDirConfig & store, WriteConn conn, const UnkeyedValidPathInfo & pathInfo)
{
conn.to << (pathInfo.deriver ? store.printStorePath(*pathInfo.deriver) : "")
<< pathInfo.narHash.to_string(HashFormat::Base16, false);
WorkerProto::write(store, conn, pathInfo.deriver);
conn.to << pathInfo.narHash.to_string(HashFormat::Base16, false);
WorkerProto::write(store, conn, pathInfo.references);
conn.to << pathInfo.registrationTime << pathInfo.narSize;
if (GET_PROTOCOL_MINOR(conn.version) >= 16) {
Expand Down
Loading