From 4494000e04122f24558e1436e66d20d89028b4bd Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 2 Jun 2016 15:08:18 +0200 Subject: 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 ... --- src/libstore/gc.cc | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'src/libstore/gc.cc') diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index e5be048d8..77d13bbdc 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -370,7 +370,6 @@ struct LocalStore::GCState bool gcKeepDerivations; unsigned long long bytesInvalidated; bool moveToTrash = true; - Path trashDir; bool shouldDelete; GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { } }; @@ -407,10 +406,12 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) invalidatePathChecked(path); } + Path realPath = realStoreDir + "/" + baseNameOf(path); + struct stat st; - if (lstat(path.c_str(), &st)) { + if (lstat(realPath.c_str(), &st)) { 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); @@ -427,20 +428,20 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) // if the path was not valid, need to determine the actual // size. try { - if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) - throw SysError(format("making ‘%1%’ writable") % path); - Path tmp = state.trashDir + "/" + baseNameOf(path); - if (rename(path.c_str(), tmp.c_str())) - throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % path % tmp); + if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1) + throw SysError(format("making ‘%1%’ writable") % realPath); + Path tmp = trashDir + "/" + baseNameOf(path); + if (rename(realPath.c_str(), tmp.c_str())) + throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % realPath % tmp); state.bytesInvalidated += size; } catch (SysError & e) { if (e.errNo == ENOSPC) { - printMsg(lvlInfo, format("note: can't create move ‘%1%’: %2%") % path % e.msg()); - deleteGarbage(state, path); + printMsg(lvlInfo, format("note: can't create move ‘%1%’: %2%") % realPath % e.msg()); + deleteGarbage(state, realPath); } } } else - deleteGarbage(state, path); + deleteGarbage(state, realPath); if (state.results.bytesFreed + state.bytesInvalidated > 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(); - 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); @@ -590,7 +592,6 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) { GCState state(results); state.options = options; - state.trashDir = storeDir + "/trash"; state.gcKeepOutputs = settings.gcKeepOutputs; state.gcKeepDerivations = settings.gcKeepDerivations; @@ -639,9 +640,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) that is not reachable from `roots' is garbage. */ if (state.shouldDelete) { - if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir); + if (pathExists(trashDir)) deleteGarbage(state, trashDir); try { - createDirs(state.trashDir); + createDirs(trashDir); } catch (SysError & e) { if (e.errNo == ENOSPC) { 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 { - AutoCloseDir dir = opendir(storeDir.c_str()); - if (!dir) throw SysError(format("opening directory ‘%1%’") % storeDir); + AutoCloseDir dir = opendir(realStoreDir.c_str()); + if (!dir) throw SysError(format("opening directory ‘%1%’") % realStoreDir); /* Read the store and immediately delete all paths that aren't valid. When using --max-freed etc., deleting @@ -725,8 +726,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) fds.clear(); /* Delete the trash directory. */ - printMsg(lvlInfo, format("deleting ‘%1%’") % state.trashDir); - deleteGarbage(state, state.trashDir); + printMsg(lvlInfo, format("deleting ‘%1%’") % trashDir); + deleteGarbage(state, trashDir); /* Clean up the links directory. */ if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) { -- cgit v1.2.3