LocalStore: Allow the physical and logical store directories to differ
This is primarily to subsume the functionality of the copy-from-other-stores substituter. For example, in the NixOS installer, we can now do (assuming we're in the target chroot, and the Nix store of the installation CD is bind-mounted on /tmp/nix): $ nix-build ... --option substituters 'local?state=/tmp/nix/var&real=/tmp/nix/store' However, unlike copy-from-other-stores, this also allows write access to such a store. One application might be fetching substitutes for /nix/store in a situation where the user doesn't have sufficient privileges to create /nix, e.g.: $ NIX_REMOTE="local?state=/home/alice/nix/var&real=/home/alice/nix/store" nix-build ...
This commit is contained in:
parent
064816ab98
commit
4494000e04
7 changed files with 68 additions and 158 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -44,7 +44,6 @@ Makefile.config
|
||||||
/scripts/nix-copy-closure
|
/scripts/nix-copy-closure
|
||||||
/scripts/NixConfig.pm
|
/scripts/NixConfig.pm
|
||||||
/scripts/NixManifest.pm
|
/scripts/NixManifest.pm
|
||||||
/scripts/copy-from-other-stores.pl
|
|
||||||
/scripts/download-from-binary-cache.pl
|
/scripts/download-from-binary-cache.pl
|
||||||
/scripts/find-runtime-roots.pl
|
/scripts/find-runtime-roots.pl
|
||||||
/scripts/build-remote.pl
|
/scripts/build-remote.pl
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
#! @perl@ -w @perlFlags@
|
|
||||||
|
|
||||||
use utf8;
|
|
||||||
use strict;
|
|
||||||
use File::Basename;
|
|
||||||
use IO::Handle;
|
|
||||||
|
|
||||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
|
||||||
|
|
||||||
|
|
||||||
STDOUT->autoflush(1);
|
|
||||||
binmode STDERR, ":encoding(utf8)";
|
|
||||||
|
|
||||||
my @remoteStoresAll = split ':', ($ENV{"NIX_OTHER_STORES"} or "");
|
|
||||||
|
|
||||||
my @remoteStores;
|
|
||||||
foreach my $dir (@remoteStoresAll) {
|
|
||||||
push @remoteStores, glob($dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit if scalar @remoteStores == 0;
|
|
||||||
print "\n";
|
|
||||||
|
|
||||||
|
|
||||||
$ENV{"NIX_REMOTE"} = "";
|
|
||||||
|
|
||||||
|
|
||||||
sub findStorePath {
|
|
||||||
my $storePath = shift;
|
|
||||||
foreach my $store (@remoteStores) {
|
|
||||||
my $sourcePath = "$store/store/" . basename $storePath;
|
|
||||||
next unless -e $sourcePath || -l $sourcePath;
|
|
||||||
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
|
||||||
return ($store, $sourcePath) if
|
|
||||||
system("$binDir/nix-store --check-validity $storePath") == 0;
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($ARGV[0] eq "--query") {
|
|
||||||
|
|
||||||
while (<STDIN>) {
|
|
||||||
chomp;
|
|
||||||
my ($cmd, @args) = split " ", $_;
|
|
||||||
|
|
||||||
if ($cmd eq "have") {
|
|
||||||
foreach my $storePath (@args) {
|
|
||||||
print "$storePath\n" if defined findStorePath($storePath);
|
|
||||||
}
|
|
||||||
print "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
elsif ($cmd eq "info") {
|
|
||||||
foreach my $storePath (@args) {
|
|
||||||
my ($store, $sourcePath) = findStorePath($storePath);
|
|
||||||
next unless defined $store;
|
|
||||||
|
|
||||||
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
|
||||||
|
|
||||||
my $deriver = `$binDir/nix-store --query --deriver $storePath`;
|
|
||||||
die "cannot query deriver of ‘$storePath’" if $? != 0;
|
|
||||||
chomp $deriver;
|
|
||||||
$deriver = "" if $deriver eq "unknown-deriver";
|
|
||||||
|
|
||||||
my @references = split "\n",
|
|
||||||
`$binDir/nix-store --query --references $storePath`;
|
|
||||||
die "cannot query references of ‘$storePath’" if $? != 0;
|
|
||||||
|
|
||||||
my $narSize = `$binDir/nix-store --query --size $storePath`;
|
|
||||||
die "cannot query size of ‘$storePath’" if $? != 0;
|
|
||||||
chomp $narSize;
|
|
||||||
|
|
||||||
print "$storePath\n";
|
|
||||||
print "$deriver\n";
|
|
||||||
print scalar @references, "\n";
|
|
||||||
print "$_\n" foreach @references;
|
|
||||||
print "0\n";
|
|
||||||
print "$narSize\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
print "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
else { die "unknown command ‘$cmd’"; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
elsif ($ARGV[0] eq "--substitute") {
|
|
||||||
die unless scalar @ARGV == 3;
|
|
||||||
my $storePath = $ARGV[1];
|
|
||||||
my $destPath = $ARGV[2];
|
|
||||||
my ($store, $sourcePath) = findStorePath $storePath;
|
|
||||||
die unless $store;
|
|
||||||
print STDERR "\n*** Copying ‘$storePath’ from ‘$sourcePath’\n\n";
|
|
||||||
system("@coreutils@/cp", "-rpd", $sourcePath, $destPath) == 0
|
|
||||||
or die "cannot copy ‘$sourcePath’ to ‘$storePath’";
|
|
||||||
print "\n"; # no hash to verify
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
else { die; }
|
|
|
@ -1269,6 +1269,9 @@ void DerivationGoal::tryToBuild()
|
||||||
{
|
{
|
||||||
trace("trying to build");
|
trace("trying to build");
|
||||||
|
|
||||||
|
if (worker.store.storeDir != worker.store.realStoreDir)
|
||||||
|
throw Error("building with a diverted Nix store is not supported");
|
||||||
|
|
||||||
/* Check for the possibility that some other goal in this process
|
/* Check for the possibility that some other goal in this process
|
||||||
has locked the output since we checked in haveDerivation().
|
has locked the output since we checked in haveDerivation().
|
||||||
(It can't happen between here and the lockPaths() call below
|
(It can't happen between here and the lockPaths() call below
|
||||||
|
|
|
@ -370,7 +370,6 @@ struct LocalStore::GCState
|
||||||
bool gcKeepDerivations;
|
bool gcKeepDerivations;
|
||||||
unsigned long long bytesInvalidated;
|
unsigned long long bytesInvalidated;
|
||||||
bool moveToTrash = true;
|
bool moveToTrash = true;
|
||||||
Path trashDir;
|
|
||||||
bool shouldDelete;
|
bool shouldDelete;
|
||||||
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
|
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
|
||||||
};
|
};
|
||||||
|
@ -407,10 +406,12 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
|
||||||
invalidatePathChecked(path);
|
invalidatePathChecked(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path realPath = realStoreDir + "/" + baseNameOf(path);
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(path.c_str(), &st)) {
|
if (lstat(realPath.c_str(), &st)) {
|
||||||
if (errno == ENOENT) return;
|
if (errno == ENOENT) return;
|
||||||
throw SysError(format("getting status of %1%") % path);
|
throw SysError(format("getting status of %1%") % realPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
printMsg(lvlInfo, format("deleting ‘%1%’") % path);
|
printMsg(lvlInfo, format("deleting ‘%1%’") % path);
|
||||||
|
@ -427,20 +428,20 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
|
||||||
// if the path was not valid, need to determine the actual
|
// if the path was not valid, need to determine the actual
|
||||||
// size.
|
// size.
|
||||||
try {
|
try {
|
||||||
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
|
if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1)
|
||||||
throw SysError(format("making ‘%1%’ writable") % path);
|
throw SysError(format("making ‘%1%’ writable") % realPath);
|
||||||
Path tmp = state.trashDir + "/" + baseNameOf(path);
|
Path tmp = trashDir + "/" + baseNameOf(path);
|
||||||
if (rename(path.c_str(), tmp.c_str()))
|
if (rename(realPath.c_str(), tmp.c_str()))
|
||||||
throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % path % tmp);
|
throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % realPath % tmp);
|
||||||
state.bytesInvalidated += size;
|
state.bytesInvalidated += size;
|
||||||
} catch (SysError & e) {
|
} catch (SysError & e) {
|
||||||
if (e.errNo == ENOSPC) {
|
if (e.errNo == ENOSPC) {
|
||||||
printMsg(lvlInfo, format("note: can't create move ‘%1%’: %2%") % path % e.msg());
|
printMsg(lvlInfo, format("note: can't create move ‘%1%’: %2%") % realPath % e.msg());
|
||||||
deleteGarbage(state, path);
|
deleteGarbage(state, realPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
deleteGarbage(state, path);
|
deleteGarbage(state, realPath);
|
||||||
|
|
||||||
if (state.results.bytesFreed + state.bytesInvalidated > state.options.maxFreed) {
|
if (state.results.bytesFreed + state.bytesInvalidated > state.options.maxFreed) {
|
||||||
printMsg(lvlInfo, format("deleted or invalidated more than %1% bytes; stopping") % state.options.maxFreed);
|
printMsg(lvlInfo, format("deleted or invalidated more than %1% bytes; stopping") % state.options.maxFreed);
|
||||||
|
@ -508,7 +509,8 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
if (path == linksDir || path == state.trashDir) return;
|
auto realPath = realStoreDir + "/" + baseNameOf(path);
|
||||||
|
if (realPath == linksDir || realPath == trashDir) return;
|
||||||
|
|
||||||
Activity act(*logger, lvlDebug, format("considering whether to delete ‘%1%’") % path);
|
Activity act(*logger, lvlDebug, format("considering whether to delete ‘%1%’") % path);
|
||||||
|
|
||||||
|
@ -590,7 +592,6 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
{
|
{
|
||||||
GCState state(results);
|
GCState state(results);
|
||||||
state.options = options;
|
state.options = options;
|
||||||
state.trashDir = storeDir + "/trash";
|
|
||||||
state.gcKeepOutputs = settings.gcKeepOutputs;
|
state.gcKeepOutputs = settings.gcKeepOutputs;
|
||||||
state.gcKeepDerivations = settings.gcKeepDerivations;
|
state.gcKeepDerivations = settings.gcKeepDerivations;
|
||||||
|
|
||||||
|
@ -639,9 +640,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
that is not reachable from `roots' is garbage. */
|
that is not reachable from `roots' is garbage. */
|
||||||
|
|
||||||
if (state.shouldDelete) {
|
if (state.shouldDelete) {
|
||||||
if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
|
if (pathExists(trashDir)) deleteGarbage(state, trashDir);
|
||||||
try {
|
try {
|
||||||
createDirs(state.trashDir);
|
createDirs(trashDir);
|
||||||
} catch (SysError & e) {
|
} catch (SysError & e) {
|
||||||
if (e.errNo == ENOSPC) {
|
if (e.errNo == ENOSPC) {
|
||||||
printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg());
|
printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg());
|
||||||
|
@ -671,8 +672,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
AutoCloseDir dir = opendir(storeDir.c_str());
|
AutoCloseDir dir = opendir(realStoreDir.c_str());
|
||||||
if (!dir) throw SysError(format("opening directory ‘%1%’") % storeDir);
|
if (!dir) throw SysError(format("opening directory ‘%1%’") % realStoreDir);
|
||||||
|
|
||||||
/* Read the store and immediately delete all paths that
|
/* Read the store and immediately delete all paths that
|
||||||
aren't valid. When using --max-freed etc., deleting
|
aren't valid. When using --max-freed etc., deleting
|
||||||
|
@ -725,8 +726,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
fds.clear();
|
fds.clear();
|
||||||
|
|
||||||
/* Delete the trash directory. */
|
/* Delete the trash directory. */
|
||||||
printMsg(lvlInfo, format("deleting ‘%1%’") % state.trashDir);
|
printMsg(lvlInfo, format("deleting ‘%1%’") % trashDir);
|
||||||
deleteGarbage(state, state.trashDir);
|
deleteGarbage(state, trashDir);
|
||||||
|
|
||||||
/* Clean up the links directory. */
|
/* Clean up the links directory. */
|
||||||
if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
|
if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
|
||||||
|
|
|
@ -38,10 +38,12 @@ namespace nix {
|
||||||
|
|
||||||
LocalStore::LocalStore(const Params & params)
|
LocalStore::LocalStore(const Params & params)
|
||||||
: LocalFSStore(params)
|
: LocalFSStore(params)
|
||||||
|
, realStoreDir(get(params, "real", storeDir))
|
||||||
, dbDir(get(params, "state", "") != "" ? get(params, "state", "") + "/db" : settings.nixDBPath)
|
, dbDir(get(params, "state", "") != "" ? get(params, "state", "") + "/db" : settings.nixDBPath)
|
||||||
, linksDir(storeDir + "/.links")
|
, linksDir(realStoreDir + "/.links")
|
||||||
, reservedPath(dbDir + "/reserved")
|
, reservedPath(dbDir + "/reserved")
|
||||||
, schemaPath(dbDir + "/schema")
|
, schemaPath(dbDir + "/schema")
|
||||||
|
, trashDir(realStoreDir + "/trash")
|
||||||
, requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option
|
, requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option
|
||||||
, publicKeys(getDefaultPublicKeys())
|
, publicKeys(getDefaultPublicKeys())
|
||||||
{
|
{
|
||||||
|
@ -53,7 +55,7 @@ LocalStore::LocalStore(const Params & params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create missing state directories if they don't already exist. */
|
/* Create missing state directories if they don't already exist. */
|
||||||
createDirs(storeDir);
|
createDirs(realStoreDir);
|
||||||
makeStoreWritable();
|
makeStoreWritable();
|
||||||
createDirs(linksDir);
|
createDirs(linksDir);
|
||||||
Path profilesDir = stateDir + "/profiles";
|
Path profilesDir = stateDir + "/profiles";
|
||||||
|
@ -83,21 +85,21 @@ LocalStore::LocalStore(const Params & params)
|
||||||
% settings.buildUsersGroup);
|
% settings.buildUsersGroup);
|
||||||
else {
|
else {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(storeDir.c_str(), &st))
|
if (stat(realStoreDir.c_str(), &st))
|
||||||
throw SysError(format("getting attributes of path ‘%1%’") % storeDir);
|
throw SysError(format("getting attributes of path ‘%1%’") % realStoreDir);
|
||||||
|
|
||||||
if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
|
if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
|
||||||
if (chown(storeDir.c_str(), 0, gr->gr_gid) == -1)
|
if (chown(realStoreDir.c_str(), 0, gr->gr_gid) == -1)
|
||||||
throw SysError(format("changing ownership of path ‘%1%’") % storeDir);
|
throw SysError(format("changing ownership of path ‘%1%’") % realStoreDir);
|
||||||
if (chmod(storeDir.c_str(), perm) == -1)
|
if (chmod(realStoreDir.c_str(), perm) == -1)
|
||||||
throw SysError(format("changing permissions on path ‘%1%’") % storeDir);
|
throw SysError(format("changing permissions on path ‘%1%’") % realStoreDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure that the store and its parents are not symlinks. */
|
/* Ensure that the store and its parents are not symlinks. */
|
||||||
if (getEnv("NIX_IGNORE_SYMLINK_STORE") != "1") {
|
if (getEnv("NIX_IGNORE_SYMLINK_STORE") != "1") {
|
||||||
Path path = storeDir;
|
Path path = realStoreDir;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
while (path != "/") {
|
while (path != "/") {
|
||||||
if (lstat(path.c_str(), &st))
|
if (lstat(path.c_str(), &st))
|
||||||
|
@ -343,15 +345,15 @@ void LocalStore::makeStoreWritable()
|
||||||
if (getuid() != 0) return;
|
if (getuid() != 0) return;
|
||||||
/* Check if /nix/store is on a read-only mount. */
|
/* Check if /nix/store is on a read-only mount. */
|
||||||
struct statvfs stat;
|
struct statvfs stat;
|
||||||
if (statvfs(storeDir.c_str(), &stat) != 0)
|
if (statvfs(realStoreDir.c_str(), &stat) != 0)
|
||||||
throw SysError("getting info about the Nix store mount point");
|
throw SysError("getting info about the Nix store mount point");
|
||||||
|
|
||||||
if (stat.f_flag & ST_RDONLY) {
|
if (stat.f_flag & ST_RDONLY) {
|
||||||
if (unshare(CLONE_NEWNS) == -1)
|
if (unshare(CLONE_NEWNS) == -1)
|
||||||
throw SysError("setting up a private mount namespace");
|
throw SysError("setting up a private mount namespace");
|
||||||
|
|
||||||
if (mount(0, storeDir.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
|
if (mount(0, realStoreDir.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
|
||||||
throw SysError(format("remounting %1% writable") % storeDir);
|
throw SysError(format("remounting %1% writable") % realStoreDir);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -917,23 +919,25 @@ void LocalStore::addToStore(const ValidPathInfo & info, const std::string & nar,
|
||||||
|
|
||||||
PathLocks outputLock;
|
PathLocks outputLock;
|
||||||
|
|
||||||
|
Path realPath = realStoreDir + "/" + baseNameOf(info.path);
|
||||||
|
|
||||||
/* Lock the output path. But don't lock if we're being called
|
/* Lock the output path. But don't lock if we're being called
|
||||||
from a build hook (whose parent process already acquired a
|
from a build hook (whose parent process already acquired a
|
||||||
lock on this path). */
|
lock on this path). */
|
||||||
Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS"));
|
Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS"));
|
||||||
if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end())
|
if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end())
|
||||||
outputLock.lockPaths({info.path});
|
outputLock.lockPaths({realPath});
|
||||||
|
|
||||||
if (repair || !isValidPath(info.path)) {
|
if (repair || !isValidPath(info.path)) {
|
||||||
|
|
||||||
deletePath(info.path);
|
deletePath(realPath);
|
||||||
|
|
||||||
StringSource source(nar);
|
StringSource source(nar);
|
||||||
restorePath(info.path, source);
|
restorePath(realPath, source);
|
||||||
|
|
||||||
canonicalisePathMetaData(info.path, -1);
|
canonicalisePathMetaData(realPath, -1);
|
||||||
|
|
||||||
optimisePath(info.path); // FIXME: combine with hashPath()
|
optimisePath(realPath); // FIXME: combine with hashPath()
|
||||||
|
|
||||||
registerValidPath(info);
|
registerValidPath(info);
|
||||||
}
|
}
|
||||||
|
@ -957,19 +961,21 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
|
||||||
/* The first check above is an optimisation to prevent
|
/* The first check above is an optimisation to prevent
|
||||||
unnecessary lock acquisition. */
|
unnecessary lock acquisition. */
|
||||||
|
|
||||||
PathLocks outputLock({dstPath});
|
Path realPath = realStoreDir + "/" + baseNameOf(dstPath);
|
||||||
|
|
||||||
|
PathLocks outputLock({realPath});
|
||||||
|
|
||||||
if (repair || !isValidPath(dstPath)) {
|
if (repair || !isValidPath(dstPath)) {
|
||||||
|
|
||||||
deletePath(dstPath);
|
deletePath(realPath);
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
StringSource source(dump);
|
StringSource source(dump);
|
||||||
restorePath(dstPath, source);
|
restorePath(realPath, source);
|
||||||
} else
|
} else
|
||||||
writeFile(dstPath, dump);
|
writeFile(realPath, dump);
|
||||||
|
|
||||||
canonicalisePathMetaData(dstPath, -1);
|
canonicalisePathMetaData(realPath, -1);
|
||||||
|
|
||||||
/* Register the SHA-256 hash of the NAR serialisation of
|
/* Register the SHA-256 hash of the NAR serialisation of
|
||||||
the path in the database. We may just have computed it
|
the path in the database. We may just have computed it
|
||||||
|
@ -980,9 +986,9 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
|
||||||
hash.first = hashAlgo == htSHA256 ? h : hashString(htSHA256, dump);
|
hash.first = hashAlgo == htSHA256 ? h : hashString(htSHA256, dump);
|
||||||
hash.second = dump.size();
|
hash.second = dump.size();
|
||||||
} else
|
} else
|
||||||
hash = hashPath(htSHA256, dstPath);
|
hash = hashPath(htSHA256, realPath);
|
||||||
|
|
||||||
optimisePath(dstPath); // FIXME: combine with hashPath()
|
optimisePath(realPath); // FIXME: combine with hashPath()
|
||||||
|
|
||||||
ValidPathInfo info;
|
ValidPathInfo info;
|
||||||
info.path = dstPath;
|
info.path = dstPath;
|
||||||
|
@ -1026,21 +1032,23 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
|
||||||
|
|
||||||
if (repair || !isValidPath(dstPath)) {
|
if (repair || !isValidPath(dstPath)) {
|
||||||
|
|
||||||
PathLocks outputLock({dstPath});
|
Path realPath = realStoreDir + "/" + baseNameOf(dstPath);
|
||||||
|
|
||||||
|
PathLocks outputLock({realPath});
|
||||||
|
|
||||||
if (repair || !isValidPath(dstPath)) {
|
if (repair || !isValidPath(dstPath)) {
|
||||||
|
|
||||||
deletePath(dstPath);
|
deletePath(realPath);
|
||||||
|
|
||||||
writeFile(dstPath, s);
|
writeFile(realPath, s);
|
||||||
|
|
||||||
canonicalisePathMetaData(dstPath, -1);
|
canonicalisePathMetaData(realPath, -1);
|
||||||
|
|
||||||
StringSink sink;
|
StringSink sink;
|
||||||
dumpString(s, sink);
|
dumpString(s, sink);
|
||||||
auto hash = hashString(htSHA256, *sink.s);
|
auto hash = hashString(htSHA256, *sink.s);
|
||||||
|
|
||||||
optimisePath(dstPath);
|
optimisePath(realPath);
|
||||||
|
|
||||||
ValidPathInfo info;
|
ValidPathInfo info;
|
||||||
info.path = dstPath;
|
info.path = dstPath;
|
||||||
|
@ -1067,7 +1075,7 @@ Path LocalStore::createTempDirInStore()
|
||||||
/* There is a slight possibility that `tmpDir' gets deleted by
|
/* There is a slight possibility that `tmpDir' gets deleted by
|
||||||
the GC between createTempDir() and addTempRoot(), so repeat
|
the GC between createTempDir() and addTempRoot(), so repeat
|
||||||
until `tmpDir' exists. */
|
until `tmpDir' exists. */
|
||||||
tmpDir = createTempDir(storeDir);
|
tmpDir = createTempDir(realStoreDir);
|
||||||
addTempRoot(tmpDir);
|
addTempRoot(tmpDir);
|
||||||
} while (!pathExists(tmpDir));
|
} while (!pathExists(tmpDir));
|
||||||
return tmpDir;
|
return tmpDir;
|
||||||
|
@ -1107,7 +1115,7 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
|
||||||
AutoCloseFD fdGCLock = openGCLock(ltWrite);
|
AutoCloseFD fdGCLock = openGCLock(ltWrite);
|
||||||
|
|
||||||
PathSet store;
|
PathSet store;
|
||||||
for (auto & i : readDirectory(storeDir)) store.insert(i.name);
|
for (auto & i : readDirectory(realStoreDir)) store.insert(i.name);
|
||||||
|
|
||||||
/* Check whether all valid paths actually exist. */
|
/* Check whether all valid paths actually exist. */
|
||||||
printMsg(lvlInfo, "checking path existence...");
|
printMsg(lvlInfo, "checking path existence...");
|
||||||
|
@ -1271,7 +1279,7 @@ void LocalStore::upgradeStore7()
|
||||||
{
|
{
|
||||||
if (getuid() != 0) return;
|
if (getuid() != 0) return;
|
||||||
printMsg(lvlError, "removing immutable bits from the Nix store (this may take a while)...");
|
printMsg(lvlError, "removing immutable bits from the Nix store (this may take a while)...");
|
||||||
makeMutable(storeDir);
|
makeMutable(realStoreDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -73,10 +73,12 @@ private:
|
||||||
|
|
||||||
Sync<State, std::recursive_mutex> _state;
|
Sync<State, std::recursive_mutex> _state;
|
||||||
|
|
||||||
|
const Path realStoreDir;
|
||||||
const Path dbDir;
|
const Path dbDir;
|
||||||
const Path linksDir;
|
const Path linksDir;
|
||||||
const Path reservedPath;
|
const Path reservedPath;
|
||||||
const Path schemaPath;
|
const Path schemaPath;
|
||||||
|
const Path trashDir;
|
||||||
|
|
||||||
bool requireSigs;
|
bool requireSigs;
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
|
||||||
/* Make the containing directory writable, but only if it's not
|
/* Make the containing directory writable, but only if it's not
|
||||||
the store itself (we don't want or need to mess with its
|
the store itself (we don't want or need to mess with its
|
||||||
permissions). */
|
permissions). */
|
||||||
bool mustToggle = !isStorePath(path);
|
bool mustToggle = dirOf(path) != realStoreDir;
|
||||||
if (mustToggle) makeWritable(dirOf(path));
|
if (mustToggle) makeWritable(dirOf(path));
|
||||||
|
|
||||||
/* When we're done, make the directory read-only again and reset
|
/* When we're done, make the directory read-only again and reset
|
||||||
|
@ -184,7 +184,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
|
||||||
MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
|
MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
|
||||||
|
|
||||||
Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
|
Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
|
||||||
% storeDir % getpid() % rand()).str();
|
% realStoreDir % getpid() % rand()).str();
|
||||||
|
|
||||||
if (link(linkPath.c_str(), tempLink.c_str()) == -1) {
|
if (link(linkPath.c_str(), tempLink.c_str()) == -1) {
|
||||||
if (errno == EMLINK) {
|
if (errno == EMLINK) {
|
||||||
|
@ -229,7 +229,7 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
|
||||||
addTempRoot(i);
|
addTempRoot(i);
|
||||||
if (!isValidPath(i)) continue; /* path was GC'ed, probably */
|
if (!isValidPath(i)) continue; /* path was GC'ed, probably */
|
||||||
Activity act(*logger, lvlChatty, format("hashing files in ‘%1%’") % i);
|
Activity act(*logger, lvlChatty, format("hashing files in ‘%1%’") % i);
|
||||||
optimisePath_(stats, i, inodeHash);
|
optimisePath_(stats, realStoreDir + "/" + baseNameOf(i), inodeHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue