about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-06-01T12·49+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-06-01T14·24+0200
commit7850d3d27910c30232dd09dd86ee8afdaad26b90 (patch)
treeda539f14d98d815e89b6ad60ed8e1e1ab9981cbf
parent1b5b654fe25cf7f2219ebe96a943397d683bfa0e (diff)
Make the store directory a member variable of Store
-rw-r--r--Makefile2
-rw-r--r--perl/lib/Nix/Store.xs5
-rw-r--r--src/libexpr/eval.cc4
-rw-r--r--src/libexpr/primops.cc20
-rw-r--r--src/libstore/binary-cache-store.cc15
-rw-r--r--src/libstore/binary-cache-store.hh2
-rw-r--r--src/libstore/build.cc30
-rw-r--r--src/libstore/builtins.cc1
-rw-r--r--src/libstore/derivations.cc8
-rw-r--r--src/libstore/derivations.hh2
-rw-r--r--src/libstore/export-import.cc4
-rw-r--r--src/libstore/gc.cc16
-rw-r--r--src/libstore/http-binary-cache-store.cc6
-rw-r--r--src/libstore/local-binary-cache-store.cc8
-rw-r--r--src/libstore/local-fs-store.cc2
-rw-r--r--src/libstore/local-store.cc67
-rw-r--r--src/libstore/local-store.hh2
-rw-r--r--src/libstore/nar-info-disk-cache.cc35
-rw-r--r--src/libstore/nar-info-disk-cache.hh3
-rw-r--r--src/libstore/nar-info.cc12
-rw-r--r--src/libstore/nar-info.hh2
-rw-r--r--src/libstore/optimise-store.cc2
-rw-r--r--src/libstore/remote-store.cc41
-rw-r--r--src/libstore/remote-store.hh2
-rw-r--r--src/libstore/s3-binary-cache-store.cc8
-rw-r--r--src/libstore/s3-binary-cache-store.hh2
-rw-r--r--src/libstore/store-api.cc71
-rw-r--r--src/libstore/store-api.hh133
-rw-r--r--src/libstore/worker-protocol.hh4
-rw-r--r--src/nix-daemon/nix-daemon.cc40
-rw-r--r--src/nix-env/nix-env.cc4
-rw-r--r--src/nix-prefetch-url/nix-prefetch-url.cc4
-rw-r--r--src/nix-store/nix-store.cc50
-rw-r--r--src/nix/command.cc2
-rw-r--r--src/nix/installables.cc2
35 files changed, 315 insertions, 296 deletions
diff --git a/Makefile b/Makefile
index 8f3688475e62..90dca473f390 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,6 @@ makefiles = \
   src/nix-env/local.mk \
   src/nix-daemon/local.mk \
   src/nix-collect-garbage/local.mk \
-  src/download-via-ssh/local.mk \
   src/nix-prefetch-url/local.mk \
   perl/local.mk \
   scripts/local.mk \
@@ -22,6 +21,7 @@ makefiles = \
   misc/emacs/local.mk \
   doc/manual/local.mk \
   tests/local.mk
+  #src/download-via-ssh/local.mk \
 
 GLOBAL_CXXFLAGS += -std=c++11 -g -Wall
 
diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs
index 7a5458113675..697fd79f9b09 100644
--- a/perl/lib/Nix/Store.xs
+++ b/perl/lib/Nix/Store.xs
@@ -161,8 +161,7 @@ SV * topoSortPaths(...)
 SV * followLinksToStorePath(char * path)
     CODE:
         try {
-            store();
-            RETVAL = newSVpv(followLinksToStorePath(path).c_str(), 0);
+            RETVAL = newSVpv(store()->followLinksToStorePath(path).c_str(), 0);
         } catch (Error & e) {
             croak("%s", e.what());
         }
@@ -289,7 +288,7 @@ SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
     PPCODE:
         try {
             HashType ht = parseHashType(algo);
-            Path path = makeFixedOutputPath(recursive, ht,
+            Path path = store()->makeFixedOutputPath(recursive, ht,
                 parseHash16or32(ht, hash), name);
             XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
         } catch (Error & e) {
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 5a6428ca6b6f..0833603b2a9e 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -341,7 +341,7 @@ Path EvalState::checkSourcePath(const Path & path_)
     /* To support import-from-derivation, allow access to anything in
        the store. FIXME: only allow access to paths that have been
        constructed by this evaluation. */
-    if (isInStore(path)) return path;
+    if (store->isInStore(path)) return path;
 
 #if 0
     /* Hack to support the chroot dependencies of corepkgs (see
@@ -1517,7 +1517,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
         dstPath = srcToStore[path];
     else {
         dstPath = settings.readOnlyMode
-            ? computeStorePathForPath(checkSourcePath(path)).first
+            ? store->computeStorePathForPath(checkSourcePath(path)).first
             : store->addToStore(baseNameOf(path), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair);
         srcToStore[path] = dstPath;
         printMsg(lvlChatty, format("copied source ‘%1%’ -> ‘%2%’")
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index d7245fca52e1..565ed69ae77b 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -50,7 +50,7 @@ void EvalState::realiseContext(const PathSet & context)
     for (auto & i : context) {
         std::pair<string, string> decoded = decodeContext(i);
         Path ctx = decoded.first;
-        assert(isStorePath(ctx));
+        assert(store->isStorePath(ctx));
         if (!store->isValidPath(ctx))
             throw InvalidPathError(ctx);
         if (!decoded.second.empty() && nix::isDerivation(ctx))
@@ -82,7 +82,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
 
     path = state.checkSourcePath(path);
 
-    if (isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) {
+    if (state.store->isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) {
         Derivation drv = readDerivation(path);
         Value & w = *state.allocValue();
         state.mkAttrs(w, 3 + drv.outputs.size());
@@ -624,7 +624,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
         outputHash = printHash(h);
         if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
 
-        Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
+        Path outPath = state.store->makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
         drv.env["out"] = outPath;
         drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
     }
@@ -646,7 +646,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 
         for (auto & i : drv.outputs)
             if (i.second.path == "") {
-                Path outPath = makeOutputPath(i.first, h, drvName);
+                Path outPath = state.store->makeOutputPath(i.first, h, drvName);
                 drv.env[i.first] = outPath;
                 i.second.path = outPath;
             }
@@ -702,10 +702,10 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
     /* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
        directly in the store.  The latter condition is necessary so
        e.g. nix-push does the right thing. */
-    if (!isStorePath(path)) path = canonPath(path, true);
-    if (!isInStore(path))
+    if (!state.store->isStorePath(path)) path = canonPath(path, true);
+    if (!state.store->isInStore(path))
         throw EvalError(format("path ‘%1%’ is not in the Nix store, at %2%") % path % pos);
-    Path path2 = toStorePath(path);
+    Path path2 = state.store->toStorePath(path);
     if (!settings.readOnlyMode)
         state.store->ensurePath(path2);
     context.insert(path2);
@@ -897,7 +897,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
     }
 
     Path storePath = settings.readOnlyMode
-        ? computeStorePathForText(name, contents, refs)
+        ? state.store->computeStorePathForText(name, contents, refs)
         : state.store->addTextToStore(name, contents, refs, state.repair);
 
     /* Note: we don't need to add `context' to the context of the
@@ -963,7 +963,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
     path = state.checkSourcePath(path);
 
     Path dstPath = settings.readOnlyMode
-        ? computeStorePathForPath(path, true, htSHA256, filter).first
+        ? state.store->computeStorePathForPath(path, true, htSHA256, filter).first
         : state.store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair);
 
     mkString(v, dstPath, {dstPath});
@@ -1765,7 +1765,7 @@ void EvalState::createBaseEnv()
     mkString(v, nixVersion);
     addConstant("__nixVersion", v);
 
-    mkString(v, settings.nixStore);
+    mkString(v, store->storeDir);
     addConstant("__storeDir", v);
 
     /* Language version.  This should be increased every time a new
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 1a95e01a5e26..668f1e566c01 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -14,8 +14,9 @@
 
 namespace nix {
 
-BinaryCacheStore::BinaryCacheStore(const StoreParams & params)
-    : compression(get(params, "compression", "xz"))
+BinaryCacheStore::BinaryCacheStore(const Params & params)
+    : Store(params)
+    , compression(get(params, "compression", "xz"))
 {
     auto secretKeyFile = get(params, "secret-key", "");
     if (secretKeyFile != "")
@@ -32,7 +33,7 @@ void BinaryCacheStore::init()
 
     auto cacheInfo = getFile(cacheInfoFile);
     if (!cacheInfo) {
-        upsertFile(cacheInfoFile, "StoreDir: " + settings.nixStore + "\n");
+        upsertFile(cacheInfoFile, "StoreDir: " + storeDir + "\n");
     } else {
         for (auto & line : tokenizeString<Strings>(*cacheInfo, "\n")) {
             size_t colon = line.find(':');
@@ -40,9 +41,9 @@ void BinaryCacheStore::init()
             auto name = line.substr(0, colon);
             auto value = trim(line.substr(colon + 1, std::string::npos));
             if (name == "StoreDir") {
-                if (value != settings.nixStore)
+                if (value != storeDir)
                     throw Error(format("binary cache ‘%s’ is for Nix stores with prefix ‘%s’, not ‘%s’")
-                        % getUri() % value % settings.nixStore);
+                        % getUri() % value % storeDir);
             } else if (name == "WantMassQuery") {
                 wantMassQuery_ = value == "1";
             } else if (name == "Priority") {
@@ -181,7 +182,7 @@ std::shared_ptr<ValidPathInfo> BinaryCacheStore::queryPathInfoUncached(const Pat
     auto data = getFile(narInfoFile);
     if (!data) return 0;
 
-    auto narInfo = make_ref<NarInfo>(*data, narInfoFile);
+    auto narInfo = make_ref<NarInfo>(*this, *data, narInfoFile);
 
     stats.narInfoRead++;
 
@@ -249,7 +250,7 @@ struct BinaryCacheStoreAccessor : public FSAccessor
     {
         auto path = canonPath(path_);
 
-        auto storePath = toStorePath(path);
+        auto storePath = store->toStorePath(path);
         std::string restPath = std::string(path, storePath.size());
 
         if (!store->isValidPath(storePath))
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index 3f269b8cf024..2d10179f32ab 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -21,7 +21,7 @@ private:
 
 protected:
 
-    BinaryCacheStore(const StoreParams & params);
+    BinaryCacheStore(const Params & params);
 
     [[noreturn]] void notImpl();
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index cca357dfb31b..7be1571cbb16 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1442,7 +1442,7 @@ void DerivationGoal::buildDone()
 #if HAVE_STATVFS
             unsigned long long required = 8ULL * 1024 * 1024; // FIXME: make configurable
             struct statvfs st;
-            if (statvfs(settings.nixStore.c_str(), &st) == 0 &&
+            if (statvfs(worker.store.storeDir.c_str(), &st) == 0 &&
                 (unsigned long long) st.f_bavail * st.f_bsize < required)
                 diskFull = true;
             if (statvfs(tmpDir.c_str(), &st) == 0 &&
@@ -1701,7 +1701,7 @@ void DerivationGoal::startBuilder()
        shouldn't care, but this is useful for purity checking (e.g.,
        the compiler or linker might only want to accept paths to files
        in the store or in the build directory). */
-    env["NIX_STORE"] = settings.nixStore;
+    env["NIX_STORE"] = worker.store.storeDir;
 
     /* The maximum number of cores to utilize for parallel building. */
     env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
@@ -1784,10 +1784,10 @@ void DerivationGoal::startBuilder()
 
         /* Check that the store path is valid. */
         Path storePath = *i++;
-        if (!isInStore(storePath))
+        if (!worker.store.isInStore(storePath))
             throw BuildError(format("‘exportReferencesGraph’ contains a non-store path ‘%1%’")
                 % storePath);
-        storePath = toStorePath(storePath);
+        storePath = worker.store.toStorePath(storePath);
         if (!worker.store.isValidPath(storePath))
             throw BuildError(format("‘exportReferencesGraph’ contains an invalid path ‘%1%’")
                 % storePath);
@@ -1838,7 +1838,7 @@ void DerivationGoal::startBuilder()
 
         string defaultChrootDirs;
 #if __linux__
-        if (isInStore(BASH_PATH))
+        if (worker.store.isInStore(BASH_PATH))
             defaultChrootDirs = "/bin/sh=" BASH_PATH;
 #endif
 
@@ -1867,8 +1867,8 @@ void DerivationGoal::startBuilder()
         /* Add the closure of store paths to the chroot. */
         PathSet closure;
         for (auto & i : dirsInChroot)
-            if (isInStore(i.second))
-                worker.store.computeFSClosure(toStorePath(i.second), closure);
+            if (worker.store.isInStore(i.second))
+                worker.store.computeFSClosure(worker.store.toStorePath(i.second), closure);
         for (auto & i : closure)
             dirsInChroot[i] = i;
 
@@ -1953,7 +1953,7 @@ void DerivationGoal::startBuilder()
            can be bind-mounted).  !!! As an extra security
            precaution, make the fake Nix store only writable by the
            build user. */
-        Path chrootStoreDir = chrootRootDir + settings.nixStore;
+        Path chrootStoreDir = chrootRootDir + worker.store.storeDir;
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
@@ -2408,7 +2408,7 @@ void DerivationGoal::runChild()
 
             /* And we want the store in there regardless of how empty dirsInChroot. We include the innermost
                path component this time, since it's typically /nix/store and we care about that. */
-            Path cur = settings.nixStore;
+            Path cur = worker.store.storeDir;
             while (cur.compare("/") != 0) {
                 ancestry.insert(cur);
                 cur = dirOf(cur);
@@ -2532,12 +2532,12 @@ void DerivationGoal::runChild()
 /* Parse a list of reference specifiers.  Each element must either be
    a store path, or the symbolic name of the output of the derivation
    (such as `out'). */
-PathSet parseReferenceSpecifiers(const BasicDerivation & drv, string attr)
+PathSet parseReferenceSpecifiers(Store & store, const BasicDerivation & drv, string attr)
 {
     PathSet result;
     Paths paths = tokenizeString<Paths>(attr);
     for (auto & i : paths) {
-        if (isStorePath(i))
+        if (store.isStorePath(i))
             result.insert(i);
         else if (drv.outputs.find(i) != drv.outputs.end())
             result.insert(drv.outputs.find(i)->second.path);
@@ -2660,7 +2660,7 @@ void DerivationGoal::registerOutputs()
                the derivation to its content-addressed location. */
             Hash h2 = recursive ? hashPath(ht, actualPath).first : hashFile(ht, actualPath);
             if (buildMode == bmHash) {
-                Path dest = makeFixedOutputPath(recursive, ht, h2, drv->env["name"]);
+                Path dest = worker.store.makeFixedOutputPath(recursive, ht, h2, drv->env["name"]);
                 printMsg(lvlError, format("build produced path ‘%1%’ with %2% hash ‘%3%’")
                     % dest % printHashType(ht) % printHash16or32(h2));
                 if (worker.store.isValidPath(dest))
@@ -2733,7 +2733,7 @@ void DerivationGoal::registerOutputs()
         auto checkRefs = [&](const string & attrName, bool allowed, bool recursive) {
             if (drv->env.find(attrName) == drv->env.end()) return;
 
-            PathSet spec = parseReferenceSpecifiers(*drv, get(drv->env, attrName));
+            PathSet spec = parseReferenceSpecifiers(worker.store, *drv, get(drv->env, attrName));
 
             PathSet used;
             if (recursive) {
@@ -2965,9 +2965,9 @@ PathSet DerivationGoal::checkPathValidity(bool returnValid, bool checkHash)
 
 Path DerivationGoal::addHashRewrite(const Path & path)
 {
-    string h1 = string(path, settings.nixStore.size() + 1, 32);
+    string h1 = string(path, worker.store.storeDir.size() + 1, 32);
     string h2 = string(printHash32(hashString(htSHA256, "rewrite:" + drvPath + ":" + path)), 0, 32);
-    Path p = settings.nixStore + "/" + h2 + string(path, settings.nixStore.size() + 33);
+    Path p = worker.store.storeDir + "/" + h2 + string(path, worker.store.storeDir.size() + 33);
     deletePath(p);
     assert(path.size() == p.size());
     rewritesToTmp[h1] = h2;
diff --git a/src/libstore/builtins.cc b/src/libstore/builtins.cc
index e1ce36e922e1..c2763f1ab4d8 100644
--- a/src/libstore/builtins.cc
+++ b/src/libstore/builtins.cc
@@ -26,7 +26,6 @@ void builtinFetchurl(const BasicDerivation & drv)
     if (out == drv.env.end()) throw Error("attribute ‘url’ missing");
 
     Path storePath = out->second;
-    assertStorePath(storePath);
 
     auto unpack = drv.env.find("unpack");
     if (unpack != drv.env.end() && unpack->second == "1") {
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index becf8524546c..8067e412adf2 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -81,7 +81,7 @@ Path writeDerivation(ref<Store> store,
     string suffix = name + drvExtension;
     string contents = drv.unparse();
     return settings.readOnlyMode
-        ? computeStorePathForText(suffix, contents, references)
+        ? store->computeStorePathForText(suffix, contents, references)
         : store->addTextToStore(suffix, contents, references, repair);
 }
 
@@ -336,7 +336,7 @@ PathSet BasicDerivation::outputPaths() const
 }
 
 
-Source & operator >> (Source & in, BasicDerivation & drv)
+Source & readDerivation(Source & in, Store & store, BasicDerivation & drv)
 {
     drv.outputs.clear();
     auto nr = readInt(in);
@@ -344,11 +344,11 @@ Source & operator >> (Source & in, BasicDerivation & drv)
         auto name = readString(in);
         DerivationOutput o;
         in >> o.path >> o.hashAlgo >> o.hash;
-        assertStorePath(o.path);
+        store.assertStorePath(o.path);
         drv.outputs[name] = o;
     }
 
-    drv.inputSrcs = readStorePaths<PathSet>(in);
+    drv.inputSrcs = readStorePaths<PathSet>(store, in);
     in >> drv.platform >> drv.builder;
     drv.args = readStrings<Strings>(in);
 
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index 6f98869b0fe0..e27c937132e8 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -114,7 +114,7 @@ bool wantOutput(const string & output, const std::set<string> & wanted);
 struct Source;
 struct Sink;
 
-Source & operator >> (Source & in, BasicDerivation & drv);
+Source & readDerivation(Source & in, Store & store, BasicDerivation & drv);
 Sink & operator << (Sink & out, const BasicDerivation & drv);
 
 }
diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc
index 12b194643b12..6090ee3e9f83 100644
--- a/src/libstore/export-import.cc
+++ b/src/libstore/export-import.cc
@@ -101,11 +101,11 @@ Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
 
         ValidPathInfo info;
 
-        info.path = readStorePath(source);
+        info.path = readStorePath(*this, source);
 
         Activity act(*logger, lvlInfo, format("importing path ‘%s’") % info.path);
 
-        info.references = readStorePaths<PathSet>(source);
+        info.references = readStorePaths<PathSet>(*this, source);
 
         info.deriver = readString(source);
         if (info.deriver != "") assertStorePath(info.deriver);
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index f4cb672cdeb9..df48e8b662e1 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -204,7 +204,7 @@ typedef std::shared_ptr<AutoCloseFD> FDPtr;
 typedef list<FDPtr> FDs;
 
 
-static void readTempRoots(PathSet & tempRoots, FDs & fds)
+static void readTempRoots(Store & store, PathSet & tempRoots, FDs & fds)
 {
     /* Read the `temproots' directory for per-process temporary root
        files. */
@@ -251,7 +251,7 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
         while ((end = contents.find((char) 0, pos)) != string::npos) {
             Path root(contents, pos, end - pos);
             debug(format("got temporary root ‘%1%’") % root);
-            assertStorePath(root);
+            store.assertStorePath(root);
             tempRoots.insert(root);
             pos = end + 1;
         }
@@ -304,7 +304,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
         }
 
         else if (type == DT_REG) {
-            Path storePath = settings.nixStore + "/" + baseNameOf(path);
+            Path storePath = storeDir + "/" + baseNameOf(path);
             if (isStorePath(storePath) && isValidPath(storePath))
                 roots[path] = storePath;
         }
@@ -594,7 +594,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
 {
     GCState state(results);
     state.options = options;
-    state.trashDir = settings.nixStore + "/trash";
+    state.trashDir = storeDir + "/trash";
     state.gcKeepOutputs = settings.gcKeepOutputs;
     state.gcKeepDerivations = settings.gcKeepDerivations;
 
@@ -635,7 +635,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
        per-process temporary root files.  So after this point no paths
        can be added to the set of temporary roots. */
     FDs fds;
-    readTempRoots(state.tempRoots, fds);
+    readTempRoots(*this, state.tempRoots, fds);
     state.roots.insert(state.tempRoots.begin(), state.tempRoots.end());
 
     /* After this point the set of roots or temporary roots cannot
@@ -675,8 +675,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
 
         try {
 
-            AutoCloseDir dir = opendir(settings.nixStore.c_str());
-            if (!dir) throw SysError(format("opening directory ‘%1%’") % settings.nixStore);
+            AutoCloseDir dir = opendir(storeDir.c_str());
+            if (!dir) throw SysError(format("opening directory ‘%1%’") % storeDir);
 
             /* Read the store and immediately delete all paths that
                aren't valid.  When using --max-freed etc., deleting
@@ -690,7 +690,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
                 checkInterrupt();
                 string name = dirent->d_name;
                 if (name == "." || name == "..") continue;
-                Path path = settings.nixStore + "/" + name;
+                Path path = storeDir + "/" + name;
                 if (isStorePath(path) && isValidPath(path))
                     entries.push_back(path);
                 else
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 8c8d545c6d85..9587ac5474fb 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -18,7 +18,7 @@ private:
 public:
 
     HttpBinaryCacheStore(
-        const StoreParams & params, const Path & _cacheUri)
+        const Params & params, const Path & _cacheUri)
         : BinaryCacheStore(params)
         , cacheUri(_cacheUri)
         , downloaders(
@@ -45,7 +45,7 @@ public:
             } catch (UploadToHTTP &) {
                 throw Error(format("‘%s’ does not appear to be a binary cache") % cacheUri);
             }
-            diskCache->createCache(cacheUri, wantMassQuery_, priority);
+            diskCache->createCache(cacheUri, storeDir, wantMassQuery_, priority);
         }
     }
 
@@ -91,7 +91,7 @@ protected:
 };
 
 static RegisterStoreImplementation regStore([](
-    const std::string & uri, const StoreParams & params)
+    const std::string & uri, const Store::Params & params)
     -> std::shared_ptr<Store>
 {
     if (std::string(uri, 0, 7) != "http://" &&
diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc
index b418c9c04148..bdc80cf90fee 100644
--- a/src/libstore/local-binary-cache-store.cc
+++ b/src/libstore/local-binary-cache-store.cc
@@ -13,7 +13,7 @@ private:
 public:
 
     LocalBinaryCacheStore(
-        const StoreParams & params, const Path & binaryCacheDir)
+        const Params & params, const Path & binaryCacheDir)
         : BinaryCacheStore(params)
         , binaryCacheDir(binaryCacheDir)
     {
@@ -45,7 +45,7 @@ protected:
             if (entry.name.size() != 40 ||
                 !hasSuffix(entry.name, ".narinfo"))
                 continue;
-            paths.insert(settings.nixStore + "/" + entry.name.substr(0, entry.name.size() - 8));
+            paths.insert(storeDir + "/" + entry.name.substr(0, entry.name.size() - 8));
         }
 
         return paths;
@@ -59,7 +59,7 @@ void LocalBinaryCacheStore::init()
     BinaryCacheStore::init();
 
     if (diskCache && !diskCache->cacheExists(getUri()))
-        diskCache->createCache(getUri(), wantMassQuery_, priority);
+        diskCache->createCache(getUri(), storeDir, wantMassQuery_, priority);
 }
 
 static void atomicWrite(const Path & path, const std::string & s)
@@ -93,7 +93,7 @@ std::shared_ptr<std::string> LocalBinaryCacheStore::getFile(const std::string &
 }
 
 static RegisterStoreImplementation regStore([](
-    const std::string & uri, const StoreParams & params)
+    const std::string & uri, const Store::Params & params)
     -> std::shared_ptr<Store>
 {
     if (std::string(uri, 0, 7) != "file://") return 0;
diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc
index 303c3af27b8d..ea9c6b541a1f 100644
--- a/src/libstore/local-fs-store.cc
+++ b/src/libstore/local-fs-store.cc
@@ -12,7 +12,7 @@ struct LocalStoreAccessor : public FSAccessor
 
     void assertStore(const Path & path)
     {
-        Path storePath = toStorePath(path);
+        Path storePath = store->toStorePath(path);
         if (!store->isValidPath(storePath))
             throw Error(format("path ‘%1%’ is not a valid store path") % storePath);
     }
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index cd3a74d80d82..32f4e31e07e4 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -36,26 +36,9 @@
 namespace nix {
 
 
-void checkStoreNotSymlink()
-{
-    if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return;
-    Path path = settings.nixStore;
-    struct stat st;
-    while (path != "/") {
-        if (lstat(path.c_str(), &st))
-            throw SysError(format("getting status of ‘%1%’") % path);
-        if (S_ISLNK(st.st_mode))
-            throw Error(format(
-                "the path ‘%1%’ is a symlink; "
-                "this is not allowed for the Nix store and its parent directories")
-                % path);
-        path = dirOf(path);
-    }
-}
-
-
-LocalStore::LocalStore()
-    : linksDir(settings.nixStore + "/.links")
+LocalStore::LocalStore(const Params & params)
+    : LocalFSStore(params)
+    , linksDir(storeDir + "/.links")
     , reservedPath(settings.nixDBPath + "/reserved")
     , schemaPath(settings.nixDBPath + "/schema")
     , requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option
@@ -69,7 +52,7 @@ LocalStore::LocalStore()
     }
 
     /* Create missing state directories if they don't already exist. */
-    createDirs(settings.nixStore);
+    createDirs(storeDir);
     makeStoreWritable();
     createDirs(linksDir);
     Path profilesDir = settings.nixStateDir + "/profiles";
@@ -99,19 +82,33 @@ LocalStore::LocalStore()
                 % settings.buildUsersGroup);
         else {
             struct stat st;
-            if (stat(settings.nixStore.c_str(), &st))
-                throw SysError(format("getting attributes of path ‘%1%’") % settings.nixStore);
+            if (stat(storeDir.c_str(), &st))
+                throw SysError(format("getting attributes of path ‘%1%’") % storeDir);
 
             if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
-                if (chown(settings.nixStore.c_str(), 0, gr->gr_gid) == -1)
-                    throw SysError(format("changing ownership of path ‘%1%’") % settings.nixStore);
-                if (chmod(settings.nixStore.c_str(), perm) == -1)
-                    throw SysError(format("changing permissions on path ‘%1%’") % settings.nixStore);
+                if (chown(storeDir.c_str(), 0, gr->gr_gid) == -1)
+                    throw SysError(format("changing ownership of path ‘%1%’") % storeDir);
+                if (chmod(storeDir.c_str(), perm) == -1)
+                    throw SysError(format("changing permissions on path ‘%1%’") % storeDir);
             }
         }
     }
 
-    checkStoreNotSymlink();
+    /* Ensure that the store and its parents are not symlinks. */
+    if (getEnv("NIX_IGNORE_SYMLINK_STORE") != "1") {
+        Path path = storeDir;
+        struct stat st;
+        while (path != "/") {
+            if (lstat(path.c_str(), &st))
+                throw SysError(format("getting status of ‘%1%’") % path);
+            if (S_ISLNK(st.st_mode))
+                throw Error(format(
+                        "the path ‘%1%’ is a symlink; "
+                        "this is not allowed for the Nix store and its parent directories")
+                    % path);
+            path = dirOf(path);
+        }
+    }
 
     /* We can't open a SQLite database if the disk is full.  Since
        this prevents the garbage collector from running when it's most
@@ -351,15 +348,15 @@ void LocalStore::makeStoreWritable()
     if (getuid() != 0) return;
     /* Check if /nix/store is on a read-only mount. */
     struct statvfs stat;
-    if (statvfs(settings.nixStore.c_str(), &stat) != 0)
+    if (statvfs(storeDir.c_str(), &stat) != 0)
         throw SysError("getting info about the Nix store mount point");
 
     if (stat.f_flag & ST_RDONLY) {
         if (unshare(CLONE_NEWNS) == -1)
             throw SysError("setting up a private mount namespace");
 
-        if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
-            throw SysError(format("remounting %1% writable") % settings.nixStore);
+        if (mount(0, storeDir.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
+            throw SysError(format("remounting %1% writable") % storeDir);
     }
 #endif
 }
@@ -771,7 +768,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
 {
     if (hashPart.size() != storePathHashLen) throw Error("invalid hash part");
 
-    Path prefix = settings.nixStore + "/" + hashPart;
+    Path prefix = storeDir + "/" + hashPart;
 
     return retrySQLite<Path>([&]() {
         auto state(_state.lock());
@@ -1071,7 +1068,7 @@ Path LocalStore::createTempDirInStore()
         /* There is a slight possibility that `tmpDir' gets deleted by
            the GC between createTempDir() and addTempRoot(), so repeat
            until `tmpDir' exists. */
-        tmpDir = createTempDir(settings.nixStore);
+        tmpDir = createTempDir(storeDir);
         addTempRoot(tmpDir);
     } while (!pathExists(tmpDir));
     return tmpDir;
@@ -1111,7 +1108,7 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
     AutoCloseFD fdGCLock = openGCLock(ltWrite);
 
     PathSet store;
-    for (auto & i : readDirectory(settings.nixStore)) store.insert(i.name);
+    for (auto & i : readDirectory(storeDir)) store.insert(i.name);
 
     /* Check whether all valid paths actually exist. */
     printMsg(lvlInfo, "checking path existence...");
@@ -1275,7 +1272,7 @@ void LocalStore::upgradeStore7()
 {
     if (getuid() != 0) return;
     printMsg(lvlError, "removing immutable bits from the Nix store (this may take a while)...");
-    makeMutable(settings.nixStore);
+    makeMutable(storeDir);
 }
 
 #else
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 231ae65a31ef..eb5fcf83360b 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -85,7 +85,7 @@ public:
 
     /* Initialise the local store, upgrading the schema if
        necessary. */
-    LocalStore();
+    LocalStore(const Params & params);
 
     ~LocalStore();
 
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index ae368e152866..b05f2661ea8d 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -1,7 +1,6 @@
 #include "nar-info-disk-cache.hh"
 #include "sync.hh"
 #include "sqlite.hh"
-#include "globals.hh"
 
 #include <sqlite3.h>
 
@@ -54,11 +53,17 @@ public:
     /* How long negative lookups are valid. */
     const int ttlNegative = 3600;
 
+    struct Cache
+    {
+        int id;
+        Path storeDir;
+    };
+
     struct State
     {
         SQLite db;
         SQLiteStmt insertCache, queryCache, insertNAR, queryNAR, insertNARExistence, queryNARExistence;
-        std::map<std::string, int> caches;
+        std::map<std::string, Cache> caches;
     };
 
     Sync<State> _state;
@@ -106,22 +111,22 @@ public:
             "select exist, timestamp from NARExistence where cache = ? and storePath = ?");
     }
 
-    int uriToInt(State & state, const std::string & uri)
+    Cache & getCache(State & state, const std::string & uri)
     {
         auto i = state.caches.find(uri);
         if (i == state.caches.end()) abort();
         return i->second;
     }
 
-    void createCache(const std::string & uri, bool wantMassQuery, int priority) override
+    void createCache(const std::string & uri, const Path & storeDir, bool wantMassQuery, int priority) override
     {
         auto state(_state.lock());
 
         // FIXME: race
 
-        state->insertCache.use()(uri)(time(0))(settings.nixStore)(wantMassQuery)(priority).exec();
+        state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority).exec();
         assert(sqlite3_changes(state->db) == 1);
-        state->caches[uri] = sqlite3_last_insert_rowid(state->db);
+        state->caches[uri] = Cache{(int) sqlite3_last_insert_rowid(state->db), storeDir};
     }
 
     bool cacheExists(const std::string & uri) override
@@ -134,7 +139,7 @@ public:
         auto queryCache(state->queryCache.use()(uri));
 
         if (queryCache.next()) {
-            state->caches[uri] = queryCache.getInt(0);
+            state->caches[uri] = Cache{(int) queryCache.getInt(0), queryCache.getStr(1)};
             return true;
         }
 
@@ -146,9 +151,9 @@ public:
     {
         auto state(_state.lock());
 
-        auto queryNAR(state->queryNAR.use()
-            (uriToInt(*state, uri))
-            (hashPart));
+        auto & cache(getCache(*state, uri));
+
+        auto queryNAR(state->queryNAR.use()(cache.id)(hashPart));
 
         if (!queryNAR.next())
             // FIXME: check NARExistence
@@ -159,7 +164,7 @@ public:
         // FIXME: implement TTL.
 
         auto namePart = queryNAR.getStr(2);
-        narInfo->path = settings.nixStore + "/" +
+        narInfo->path = cache.storeDir + "/" +
             hashPart + (namePart.empty() ? "" : "-" + namePart);
         narInfo->url = queryNAR.getStr(3);
         narInfo->compression = queryNAR.getStr(4);
@@ -169,9 +174,9 @@ public:
         narInfo->narHash = parseHash(queryNAR.getStr(7));
         narInfo->narSize = queryNAR.getInt(8);
         for (auto & r : tokenizeString<Strings>(queryNAR.getStr(9), " "))
-            narInfo->references.insert(settings.nixStore + "/" + r);
+            narInfo->references.insert(cache.storeDir + "/" + r);
         if (!queryNAR.isNull(10))
-            narInfo->deriver = settings.nixStore + "/" + queryNAR.getStr(10);
+            narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(10);
         for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(11), " "))
             narInfo->sigs.insert(sig);
 
@@ -184,6 +189,8 @@ public:
     {
         auto state(_state.lock());
 
+        auto & cache(getCache(*state, uri));
+
         if (info) {
 
             auto narInfo = std::dynamic_pointer_cast<NarInfo>(info);
@@ -191,7 +198,7 @@ public:
             assert(hashPart == storePathToHash(info->path));
 
             state->insertNAR.use()
-                (uriToInt(*state, uri))
+                (cache.id)
                 (hashPart)
                 (storePathToName(info->path))
                 (narInfo ? narInfo->url : "", narInfo != 0)
diff --git a/src/libstore/nar-info-disk-cache.hh b/src/libstore/nar-info-disk-cache.hh
index ce5da062c5e3..f86d720a9586 100644
--- a/src/libstore/nar-info-disk-cache.hh
+++ b/src/libstore/nar-info-disk-cache.hh
@@ -10,7 +10,8 @@ class NarInfoDiskCache
 public:
     typedef enum { oValid, oInvalid, oUnknown } Outcome;
 
-    virtual void createCache(const std::string & uri, bool wantMassQuery, int priority) = 0;
+    virtual void createCache(const std::string & uri, const Path & storeDir,
+        bool wantMassQuery, int priority) = 0;
 
     virtual bool cacheExists(const std::string & uri) = 0;
 
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index 4ff4c996dabd..1aacca84b800 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -3,7 +3,7 @@
 
 namespace nix {
 
-NarInfo::NarInfo(const std::string & s, const std::string & whence)
+NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence)
 {
     auto corrupt = [&]() {
         throw Error("NAR info file ‘%1%’ is corrupt");
@@ -32,7 +32,7 @@ NarInfo::NarInfo(const std::string & s, const std::string & whence)
         std::string value(s, colon + 2, eol - colon - 2);
 
         if (name == "StorePath") {
-            if (!isStorePath(value)) corrupt();
+            if (!store.isStorePath(value)) corrupt();
             path = value;
         }
         else if (name == "URL")
@@ -53,14 +53,14 @@ NarInfo::NarInfo(const std::string & s, const std::string & whence)
             auto refs = tokenizeString<Strings>(value, " ");
             if (!references.empty()) corrupt();
             for (auto & r : refs) {
-                auto r2 = settings.nixStore + "/" + r;
-                if (!isStorePath(r2)) corrupt();
+                auto r2 = store.storeDir + "/" + r;
+                if (!store.isStorePath(r2)) corrupt();
                 references.insert(r2);
             }
         }
         else if (name == "Deriver") {
-            auto p = settings.nixStore + "/" + value;
-            if (!isStorePath(p)) corrupt();
+            auto p = store.storeDir + "/" + value;
+            if (!store.isStorePath(p)) corrupt();
             deriver = p;
         }
         else if (name == "System")
diff --git a/src/libstore/nar-info.hh b/src/libstore/nar-info.hh
index 6bc2f03b139b..4995061fbb6d 100644
--- a/src/libstore/nar-info.hh
+++ b/src/libstore/nar-info.hh
@@ -16,7 +16,7 @@ struct NarInfo : ValidPathInfo
 
     NarInfo() { }
     NarInfo(const ValidPathInfo & info) : ValidPathInfo(info) { }
-    NarInfo(const std::string & s, const std::string & whence);
+    NarInfo(const Store & store, const std::string & s, const std::string & whence);
 
     std::string to_string() const;
 };
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index ad7fe0e8bebf..33f002f9dbb1 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -184,7 +184,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
     MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
 
     Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
-        % settings.nixStore % getpid() % rand()).str();
+        % storeDir % getpid() % rand()).str();
 
     if (link(linkPath.c_str(), tempLink.c_str()) == -1) {
         if (errno == EMLINK) {
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 48653595f0e8..3654ffbffc44 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -21,26 +21,27 @@
 namespace nix {
 
 
-Path readStorePath(Source & from)
+Path readStorePath(Store & store, Source & from)
 {
     Path path = readString(from);
-    assertStorePath(path);
+    store.assertStorePath(path);
     return path;
 }
 
 
-template<class T> T readStorePaths(Source & from)
+template<class T> T readStorePaths(Store & store, Source & from)
 {
     T paths = readStrings<T>(from);
-    for (auto & i : paths) assertStorePath(i);
+    for (auto & i : paths) store.assertStorePath(i);
     return paths;
 }
 
-template PathSet readStorePaths(Source & from);
+template PathSet readStorePaths(Store & store, Source & from);
 
 
-RemoteStore::RemoteStore(size_t maxConnections)
-    : connections(make_ref<Pool<Connection>>(
+RemoteStore::RemoteStore(const Params & params, size_t maxConnections)
+    : LocalFSStore(params)
+    , connections(make_ref<Pool<Connection>>(
             maxConnections,
             [this]() { return openConnection(); },
             [](const ref<Connection> & r) { return r->to.good() && r->from.good(); }
@@ -168,7 +169,7 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths)
     } else {
         conn->to << wopQueryValidPaths << paths;
         conn->processStderr();
-        return readStorePaths<PathSet>(conn->from);
+        return readStorePaths<PathSet>(*this, conn->from);
     }
 }
 
@@ -178,7 +179,7 @@ PathSet RemoteStore::queryAllValidPaths()
     auto conn(connections->get());
     conn->to << wopQueryAllValidPaths;
     conn->processStderr();
-    return readStorePaths<PathSet>(conn->from);
+    return readStorePaths<PathSet>(*this, conn->from);
 }
 
 
@@ -196,7 +197,7 @@ PathSet RemoteStore::querySubstitutablePaths(const PathSet & paths)
     } else {
         conn->to << wopQuerySubstitutablePaths << paths;
         conn->processStderr();
-        return readStorePaths<PathSet>(conn->from);
+        return readStorePaths<PathSet>(*this, conn->from);
     }
 }
 
@@ -220,7 +221,7 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
             if (reply == 0) continue;
             info.deriver = readString(conn->from);
             if (info.deriver != "") assertStorePath(info.deriver);
-            info.references = readStorePaths<PathSet>(conn->from);
+            info.references = readStorePaths<PathSet>(*this, conn->from);
             info.downloadSize = readLongLong(conn->from);
             info.narSize = GET_PROTOCOL_MINOR(conn->daemonVersion) >= 7 ? readLongLong(conn->from) : 0;
             infos[i] = info;
@@ -232,11 +233,11 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
         conn->processStderr();
         unsigned int count = readInt(conn->from);
         for (unsigned int n = 0; n < count; n++) {
-            Path path = readStorePath(conn->from);
+            Path path = readStorePath(*this, conn->from);
             SubstitutablePathInfo & info(infos[path]);
             info.deriver = readString(conn->from);
             if (info.deriver != "") assertStorePath(info.deriver);
-            info.references = readStorePaths<PathSet>(conn->from);
+            info.references = readStorePaths<PathSet>(*this, conn->from);
             info.downloadSize = readLongLong(conn->from);
             info.narSize = readLongLong(conn->from);
         }
@@ -266,7 +267,7 @@ std::shared_ptr<ValidPathInfo> RemoteStore::queryPathInfoUncached(const Path & p
     info->deriver = readString(conn->from);
     if (info->deriver != "") assertStorePath(info->deriver);
     info->narHash = parseHash(htSHA256, readString(conn->from));
-    info->references = readStorePaths<PathSet>(conn->from);
+    info->references = readStorePaths<PathSet>(*this, conn->from);
     info->registrationTime = readInt(conn->from);
     info->narSize = readLongLong(conn->from);
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) {
@@ -283,7 +284,7 @@ void RemoteStore::queryReferrers(const Path & path,
     auto conn(connections->get());
     conn->to << wopQueryReferrers << path;
     conn->processStderr();
-    PathSet referrers2 = readStorePaths<PathSet>(conn->from);
+    PathSet referrers2 = readStorePaths<PathSet>(*this, conn->from);
     referrers.insert(referrers2.begin(), referrers2.end());
 }
 
@@ -293,7 +294,7 @@ PathSet RemoteStore::queryValidDerivers(const Path & path)
     auto conn(connections->get());
     conn->to << wopQueryValidDerivers << path;
     conn->processStderr();
-    return readStorePaths<PathSet>(conn->from);
+    return readStorePaths<PathSet>(*this, conn->from);
 }
 
 
@@ -302,7 +303,7 @@ PathSet RemoteStore::queryDerivationOutputs(const Path & path)
     auto conn(connections->get());
     conn->to << wopQueryDerivationOutputs << path;
     conn->processStderr();
-    return readStorePaths<PathSet>(conn->from);
+    return readStorePaths<PathSet>(*this, conn->from);
 }
 
 
@@ -363,7 +364,7 @@ Path RemoteStore::addToStore(const string & name, const Path & _srcPath,
         throw;
     }
 
-    return readStorePath(conn->from);
+    return readStorePath(*this, conn->from);
 }
 
 
@@ -376,7 +377,7 @@ Path RemoteStore::addTextToStore(const string & name, const string & s,
     conn->to << wopAddTextToStore << name << s << references;
 
     conn->processStderr();
-    return readStorePath(conn->from);
+    return readStorePath(*this, conn->from);
 }
 
 
@@ -465,7 +466,7 @@ Roots RemoteStore::findRoots()
     Roots result;
     while (count--) {
         Path link = readString(conn->from);
-        Path target = readStorePath(conn->from);
+        Path target = readStorePath(*this, conn->from);
         result[link] = target;
     }
     return result;
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 3e0fc4e04f41..e756805ea05b 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -22,7 +22,7 @@ class RemoteStore : public LocalFSStore
 {
 public:
 
-    RemoteStore(size_t maxConnections = std::numeric_limits<size_t>::max());
+    RemoteStore(const Params & params, size_t maxConnections = std::numeric_limits<size_t>::max());
 
     /* Implementations of abstract store API methods. */
 
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index 371bf24fd419..33cc9659a0cd 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -47,7 +47,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
     Stats stats;
 
     S3BinaryCacheStoreImpl(
-        const StoreParams & params, const std::string & bucketName)
+        const Params & params, const std::string & bucketName)
         : S3BinaryCacheStore(params)
         , bucketName(bucketName)
         , config(makeConfig())
@@ -95,7 +95,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 
             BinaryCacheStore::init();
 
-            diskCache->createCache(getUri(), wantMassQuery_, priority);
+            diskCache->createCache(getUri(), storeDir, wantMassQuery_, priority);
         }
     }
 
@@ -232,7 +232,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
             for (auto object : contents) {
                 auto & key = object.GetKey();
                 if (key.size() != 40 || !hasSuffix(key, ".narinfo")) continue;
-                paths.insert(settings.nixStore + "/" + key.substr(0, key.size() - 8));
+                paths.insert(storeDir + "/" + key.substr(0, key.size() - 8));
             }
 
             marker = res.GetNextMarker();
@@ -244,7 +244,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 };
 
 static RegisterStoreImplementation regStore([](
-    const std::string & uri, const StoreParams & params)
+    const std::string & uri, const Store::Params & params)
     -> std::shared_ptr<Store>
 {
     if (std::string(uri, 0, 5) != "s3://") return 0;
diff --git a/src/libstore/s3-binary-cache-store.hh b/src/libstore/s3-binary-cache-store.hh
index 3f9bd891274b..79ab72e5a940 100644
--- a/src/libstore/s3-binary-cache-store.hh
+++ b/src/libstore/s3-binary-cache-store.hh
@@ -10,7 +10,7 @@ class S3BinaryCacheStore : public BinaryCacheStore
 {
 protected:
 
-    S3BinaryCacheStore(const StoreParams & params)
+    S3BinaryCacheStore(const Params & params)
         : BinaryCacheStore(params)
     { }
 
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index f39d6b54787c..cea4b4b6ebcb 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -8,32 +8,32 @@
 namespace nix {
 
 
-bool isInStore(const Path & path)
+bool Store::isInStore(const Path & path) const
 {
-    return isInDir(path, settings.nixStore);
+    return isInDir(path, storeDir);
 }
 
 
-bool isStorePath(const Path & path)
+bool Store::isStorePath(const Path & path) const
 {
     return isInStore(path)
-        && path.size() >= settings.nixStore.size() + 1 + storePathHashLen
-        && path.find('/', settings.nixStore.size() + 1) == Path::npos;
+        && path.size() >= storeDir.size() + 1 + storePathHashLen
+        && path.find('/', storeDir.size() + 1) == Path::npos;
 }
 
 
-void assertStorePath(const Path & path)
+void Store::assertStorePath(const Path & path) const
 {
     if (!isStorePath(path))
         throw Error(format("path ‘%1%’ is not in the Nix store") % path);
 }
 
 
-Path toStorePath(const Path & path)
+Path Store::toStorePath(const Path & path) const
 {
     if (!isInStore(path))
         throw Error(format("path ‘%1%’ is not in the Nix store") % path);
-    Path::size_type slash = path.find('/', settings.nixStore.size() + 1);
+    Path::size_type slash = path.find('/', storeDir.size() + 1);
     if (slash == Path::npos)
         return path;
     else
@@ -41,7 +41,7 @@ Path toStorePath(const Path & path)
 }
 
 
-Path followLinksToStore(const Path & _path)
+Path Store::followLinksToStore(const Path & _path) const
 {
     Path path = absPath(_path);
     while (!isInStore(path)) {
@@ -55,7 +55,7 @@ Path followLinksToStore(const Path & _path)
 }
 
 
-Path followLinksToStorePath(const Path & path)
+Path Store::followLinksToStorePath(const Path & path) const
 {
     return toStorePath(followLinksToStore(path));
 }
@@ -63,18 +63,17 @@ Path followLinksToStorePath(const Path & path)
 
 string storePathToName(const Path & path)
 {
-    assertStorePath(path);
-    auto l = settings.nixStore.size() + 1 + storePathHashLen;
-    assert(path.size() >= l);
-    return path.size() == l ? "" : string(path, l + 1);
+    auto base = baseNameOf(path);
+    assert(base.size() == storePathHashLen || (base.size() > storePathHashLen && base[storePathHashLen] == '-'));
+    return base.size() == storePathHashLen ? "" : string(base, storePathHashLen + 1);
 }
 
 
 string storePathToHash(const Path & path)
 {
-    assertStorePath(path);
-    assert(path.size() >= settings.nixStore.size() + 1 + storePathHashLen);
-    return string(path, settings.nixStore.size() + 1, storePathHashLen);
+    auto base = baseNameOf(path);
+    assert(base.size() >= storePathHashLen);
+    return string(base, 0, storePathHashLen);
 }
 
 
@@ -168,31 +167,31 @@ void checkStoreName(const string & name)
 */
 
 
-Path makeStorePath(const string & type,
-    const Hash & hash, const string & name)
+Path Store::makeStorePath(const string & type,
+    const Hash & hash, const string & name) const
 {
     /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
     string s = type + ":sha256:" + printHash(hash) + ":"
-        + settings.nixStore + ":" + name;
+        + storeDir + ":" + name;
 
     checkStoreName(name);
 
-    return settings.nixStore + "/"
+    return storeDir + "/"
         + printHash32(compressHash(hashString(htSHA256, s), 20))
         + "-" + name;
 }
 
 
-Path makeOutputPath(const string & id,
-    const Hash & hash, const string & name)
+Path Store::makeOutputPath(const string & id,
+    const Hash & hash, const string & name) const
 {
     return makeStorePath("output:" + id, hash,
         name + (id == "out" ? "" : "-" + id));
 }
 
 
-Path makeFixedOutputPath(bool recursive,
-    HashType hashAlgo, Hash hash, string name)
+Path Store::makeFixedOutputPath(bool recursive,
+    HashType hashAlgo, Hash hash, string name) const
 {
     return hashAlgo == htSHA256 && recursive
         ? makeStorePath("source", hash, name)
@@ -203,8 +202,8 @@ Path makeFixedOutputPath(bool recursive,
 }
 
 
-std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
-    bool recursive, HashType hashAlgo, PathFilter & filter)
+std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath,
+    bool recursive, HashType hashAlgo, PathFilter & filter) const
 {
     HashType ht(hashAlgo);
     Hash h = recursive ? hashPath(ht, srcPath, filter).first : hashFile(ht, srcPath);
@@ -214,8 +213,8 @@ std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
 }
 
 
-Path computeStorePathForText(const string & name, const string & s,
-    const PathSet & references)
+Path Store::computeStorePathForText(const string & name, const string & s,
+    const PathSet & references) const
 {
     Hash hash = hashString(htSHA256, s);
     /* Stuff the references (if any) into the type.  This is a bit
@@ -230,6 +229,12 @@ Path computeStorePathForText(const string & name, const string & s,
 }
 
 
+Store::Store(const Params & params)
+    : storeDir(settings.nixStore)
+{
+}
+
+
 std::string Store::getUri()
 {
     return "";
@@ -465,7 +470,7 @@ RegisterStoreImplementation::Implementations * RegisterStoreImplementation::impl
 ref<Store> openStoreAt(const std::string & uri_)
 {
     auto uri(uri_);
-    StoreParams params;
+    Store::Params params;
     auto q = uri.find('?');
     if (q != std::string::npos) {
         for (auto s : tokenizeString<Strings>(uri.substr(q + 1), "&")) {
@@ -492,7 +497,7 @@ ref<Store> openStore()
 
 
 static RegisterStoreImplementation regStore([](
-    const std::string & uri, const StoreParams & params)
+    const std::string & uri, const Store::Params & params)
     -> std::shared_ptr<Store>
 {
     enum { mDaemon, mLocal, mAuto } mode;
@@ -512,8 +517,8 @@ static RegisterStoreImplementation regStore([](
     }
 
     return mode == mDaemon
-        ? std::shared_ptr<Store>(std::make_shared<RemoteStore>())
-        : std::shared_ptr<Store>(std::make_shared<LocalStore>());
+        ? std::shared_ptr<Store>(std::make_shared<RemoteStore>(params))
+        : std::shared_ptr<Store>(std::make_shared<LocalStore>(params));
 });
 
 
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index ab7baf82d5f8..45cf7e7819a9 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -177,6 +177,12 @@ class NarInfoDiskCache;
 
 class Store : public std::enable_shared_from_this<Store>
 {
+public:
+
+    typedef std::map<std::string, std::string> Params;
+
+    const Path storeDir;
+
 protected:
 
     struct State
@@ -188,12 +194,71 @@ protected:
 
     std::shared_ptr<NarInfoDiskCache> diskCache;
 
+    Store(const Params & params);
+
 public:
 
     virtual ~Store() { }
 
     virtual std::string getUri() = 0;
 
+    /* Return true if ‘path’ is in the Nix store (but not the Nix
+       store itself). */
+    bool isInStore(const Path & path) const;
+
+    /* Return true if ‘path’ is a store path, i.e. a direct child of
+       the Nix store. */
+    bool isStorePath(const Path & path) const;
+
+    /* Throw an exception if ‘path’ is not a store path. */
+    void assertStorePath(const Path & path) const;
+
+    /* Chop off the parts after the top-level store name, e.g.,
+       /nix/store/abcd-foo/bar => /nix/store/abcd-foo. */
+    Path toStorePath(const Path & path) const;
+
+    /* Follow symlinks until we end up with a path in the Nix store. */
+    Path followLinksToStore(const Path & path) const;
+
+    /* Same as followLinksToStore(), but apply toStorePath() to the
+       result. */
+    Path followLinksToStorePath(const Path & path) const;
+
+    /* Constructs a unique store path name. */
+    Path makeStorePath(const string & type,
+        const Hash & hash, const string & name) const;
+
+    Path makeOutputPath(const string & id,
+        const Hash & hash, const string & name) const;
+
+    Path makeFixedOutputPath(bool recursive,
+        HashType hashAlgo, Hash hash, string name) const;
+
+    /* This is the preparatory part of addToStore() and
+       addToStoreFixed(); it computes the store path to which srcPath
+       is to be copied.  Returns the store path and the cryptographic
+       hash of the contents of srcPath. */
+    std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
+        bool recursive = true, HashType hashAlgo = htSHA256,
+        PathFilter & filter = defaultPathFilter) const;
+
+    /* Preparatory part of addTextToStore().
+
+       !!! Computation of the path should take the references given to
+       addTextToStore() into account, otherwise we have a (relatively
+       minor) security hole: a caller can register a source file with
+       bogus references.  If there are too many references, the path may
+       not be garbage collected when it has to be (not really a problem,
+       the caller could create a root anyway), or it may be garbage
+       collected when it shouldn't be (more serious).
+
+       Hashing the references would solve this (bogus references would
+       simply yield a different store path, so other users wouldn't be
+       affected), but it has some backwards compatibility issues (the
+       hashing scheme changes), so I'm not doing that for now. */
+    Path computeStorePathForText(const string & name, const string & s,
+        const PathSet & references) const;
+
     /* Check whether a path is valid. */
     bool isValidPath(const Path & path);
 
@@ -429,80 +494,26 @@ protected:
 
 class LocalFSStore : public Store
 {
+protected:
+    using Store::Store;
 public:
     void narFromPath(const Path & path, Sink & sink) override;
     ref<FSAccessor> getFSAccessor() override;
 };
 
 
-/* !!! These should be part of the store API, I guess. */
-
-/* Throw an exception if `path' is not directly in the Nix store. */
-void assertStorePath(const Path & path);
-
-bool isInStore(const Path & path);
-bool isStorePath(const Path & path);
-
 /* Extract the name part of the given store path. */
 string storePathToName(const Path & path);
 
 /* Extract the hash part of the given store path. */
 string storePathToHash(const Path & path);
 
+/* Check whether ‘name’ is a valid store path name part, i.e. contains
+   only the characters [a-zA-Z0-9\+\-\.\_\?\=] and doesn't start with
+   a dot. */
 void checkStoreName(const string & name);
 
 
-/* Chop off the parts after the top-level store name, e.g.,
-   /nix/store/abcd-foo/bar => /nix/store/abcd-foo. */
-Path toStorePath(const Path & path);
-
-
-/* Follow symlinks until we end up with a path in the Nix store. */
-Path followLinksToStore(const Path & path);
-
-
-/* Same as followLinksToStore(), but apply toStorePath() to the
-   result. */
-Path followLinksToStorePath(const Path & path);
-
-
-/* Constructs a unique store path name. */
-Path makeStorePath(const string & type,
-    const Hash & hash, const string & name);
-
-Path makeOutputPath(const string & id,
-    const Hash & hash, const string & name);
-
-Path makeFixedOutputPath(bool recursive,
-    HashType hashAlgo, Hash hash, string name);
-
-
-/* This is the preparatory part of addToStore() and addToStoreFixed();
-   it computes the store path to which srcPath is to be copied.
-   Returns the store path and the cryptographic hash of the
-   contents of srcPath. */
-std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
-    bool recursive = true, HashType hashAlgo = htSHA256,
-    PathFilter & filter = defaultPathFilter);
-
-/* Preparatory part of addTextToStore().
-
-   !!! Computation of the path should take the references given to
-   addTextToStore() into account, otherwise we have a (relatively
-   minor) security hole: a caller can register a source file with
-   bogus references.  If there are too many references, the path may
-   not be garbage collected when it has to be (not really a problem,
-   the caller could create a root anyway), or it may be garbage
-   collected when it shouldn't be (more serious).
-
-   Hashing the references would solve this (bogus references would
-   simply yield a different store path, so other users wouldn't be
-   affected), but it has some backwards compatibility issues (the
-   hashing scheme changes), so I'm not doing that for now. */
-Path computeStorePathForText(const string & name, const string & s,
-    const PathSet & references);
-
-
 /* Copy a path from one store to another. */
 void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
     const Path & storePath, bool repair = false);
@@ -542,10 +553,8 @@ std::list<ref<Store>> getDefaultSubstituters();
 
 
 /* Store implementation registration. */
-typedef std::map<std::string, std::string> StoreParams;
-
 typedef std::function<std::shared_ptr<Store>(
-    const std::string & uri, const StoreParams & params)> OpenStore;
+    const std::string & uri, const Store::Params & params)> OpenStore;
 
 struct RegisterStoreImplementation
 {
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index 7ff0553a016c..f8cd7cc4be29 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -56,8 +56,8 @@ typedef enum {
 #define STDERR_ERROR 0x63787470
 
 
-Path readStorePath(Source & from);
-template<class T> T readStorePaths(Source & from);
+Path readStorePath(Store & store, Source & from);
+template<class T> T readStorePaths(Store & store, Source & from);
 
 
 }
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 9757086c650e..6a992b95340d 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -176,7 +176,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
            connection.  */
         Path path = readString(from);
         startWork();
-        assertStorePath(path);
+        store->assertStorePath(path);
         bool result = store->isValidPath(path);
         stopWork();
         to << result;
@@ -184,7 +184,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQueryValidPaths: {
-        PathSet paths = readStorePaths<PathSet>(from);
+        PathSet paths = readStorePaths<PathSet>(*store, from);
         startWork();
         PathSet res = store->queryValidPaths(paths);
         stopWork();
@@ -193,7 +193,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopHasSubstitutes: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         PathSet res = store->querySubstitutablePaths({path});
         stopWork();
@@ -202,7 +202,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQuerySubstitutablePaths: {
-        PathSet paths = readStorePaths<PathSet>(from);
+        PathSet paths = readStorePaths<PathSet>(*store, from);
         startWork();
         PathSet res = store->querySubstitutablePaths(paths);
         stopWork();
@@ -211,7 +211,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQueryPathHash: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         auto hash = store->queryPathInfo(path)->narHash;
         stopWork();
@@ -223,7 +223,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     case wopQueryReferrers:
     case wopQueryValidDerivers:
     case wopQueryDerivationOutputs: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         PathSet paths;
         if (op == wopQueryReferences)
@@ -239,7 +239,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQueryDerivationOutputNames: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         StringSet names;
         names = store->queryDerivationOutputNames(path);
@@ -249,7 +249,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQueryDeriver: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         auto deriver = store->queryPathInfo(path)->deriver;
         stopWork();
@@ -302,7 +302,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     case wopAddTextToStore: {
         string suffix = readString(from);
         string s = readString(from);
-        PathSet refs = readStorePaths<PathSet>(from);
+        PathSet refs = readStorePaths<PathSet>(*store, from);
         startWork();
         Path path = store->addTextToStore(suffix, s, refs);
         stopWork();
@@ -311,7 +311,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopExportPath: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         readInt(from); // obsolete
         startWork();
         TunnelSink sink(to);
@@ -331,7 +331,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopBuildPaths: {
-        PathSet drvs = readStorePaths<PathSet>(from);
+        PathSet drvs = readStorePaths<PathSet>(*store, from);
         BuildMode mode = bmNormal;
         if (GET_PROTOCOL_MINOR(clientVersion) >= 15) {
             mode = (BuildMode)readInt(from);
@@ -349,9 +349,9 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopBuildDerivation: {
-        Path drvPath = readStorePath(from);
+        Path drvPath = readStorePath(*store, from);
         BasicDerivation drv;
-        from >> drv;
+        readDerivation(from, *store, drv);
         BuildMode buildMode = (BuildMode) readInt(from);
         startWork();
         if (!trusted)
@@ -363,7 +363,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopEnsurePath: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         store->ensurePath(path);
         stopWork();
@@ -372,7 +372,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopAddTempRoot: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         startWork();
         store->addTempRoot(path);
         stopWork();
@@ -410,7 +410,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     case wopCollectGarbage: {
         GCOptions options;
         options.action = (GCOptions::GCAction) readInt(from);
-        options.pathsToDelete = readStorePaths<PathSet>(from);
+        options.pathsToDelete = readStorePaths<PathSet>(*store, from);
         options.ignoreLiveness = readInt(from);
         options.maxFreed = readLongLong(from);
         readInt(from); // obsolete field
@@ -486,7 +486,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQuerySubstitutablePathInfos: {
-        PathSet paths = readStorePaths<PathSet>(from);
+        PathSet paths = readStorePaths<PathSet>(*store, from);
         startWork();
         SubstitutablePathInfos infos;
         store->querySubstitutablePathInfos(paths, infos);
@@ -508,7 +508,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopQueryPathInfo: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         std::shared_ptr<const ValidPathInfo> info;
         startWork();
         try {
@@ -553,7 +553,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
     }
 
     case wopAddSignatures: {
-        Path path = readStorePath(from);
+        Path path = readStorePath(*store, from);
         StringSet sigs = readStrings<StringSet>(from);
         startWork();
         if (!trusted)
@@ -607,7 +607,7 @@ static void processConnection(bool trusted)
 #endif
 
         /* Open the store. */
-        auto store = make_ref<LocalStore>();
+        auto store = make_ref<LocalStore>(Store::Params()); // FIXME: get params from somewhere
 
         stopWork();
         to.flush();
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index 6b6c245d3637..fbb0f61a19d2 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -387,7 +387,7 @@ static void queryInstSources(EvalState & state,
         case srcStorePaths: {
 
             for (auto & i : args) {
-                Path path = followLinksToStorePath(i);
+                Path path = state.store->followLinksToStorePath(i);
 
                 string name = baseNameOf(path);
                 string::size_type dash = name.find('-');
@@ -742,7 +742,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
             for (auto & j : selectors)
                 /* !!! the repeated calls to followLinksToStorePath()
                    are expensive, should pre-compute them. */
-                if ((isPath(j) && i.queryOutPath() == followLinksToStorePath(j))
+                if ((isPath(j) && i.queryOutPath() == globals.state->store->followLinksToStorePath(j))
                     || DrvName(j).matches(drvName))
                 {
                     printMsg(lvlInfo, format("uninstalling ‘%1%’") % i.name);
diff --git a/src/nix-prefetch-url/nix-prefetch-url.cc b/src/nix-prefetch-url/nix-prefetch-url.cc
index 64da10513711..44a16743d886 100644
--- a/src/nix-prefetch-url/nix-prefetch-url.cc
+++ b/src/nix-prefetch-url/nix-prefetch-url.cc
@@ -146,7 +146,7 @@ int main(int argc, char * * argv)
         Path storePath;
         if (args.size() == 2) {
             expectedHash = parseHash16or32(ht, args[1]);
-            storePath = makeFixedOutputPath(unpack, ht, expectedHash, name);
+            storePath = store->makeFixedOutputPath(unpack, ht, expectedHash, name);
             if (store->isValidPath(storePath))
                 hash = expectedHash;
             else
@@ -197,7 +197,7 @@ int main(int argc, char * * argv)
                into the Nix store. */
             storePath = store->addToStore(name, tmpFile, unpack, ht);
 
-            assert(storePath == makeFixedOutputPath(unpack, ht, hash, name));
+            assert(storePath == store->makeFixedOutputPath(unpack, ht, hash, name));
         }
 
         if (!printPath)
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 1fd8a148e472..cd00412a8a86 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -124,7 +124,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
     Paths paths;
     for (auto & i : opArgs) {
         DrvPathWithOutputs p = parseDrvPathWithOutputs(i);
-        paths.push_back(makeDrvPathWithOutputs(followLinksToStorePath(p.first), p.second));
+        paths.push_back(makeDrvPathWithOutputs(store->followLinksToStorePath(p.first), p.second));
     }
 
     unsigned long long downloadSize, narSize;
@@ -207,7 +207,7 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
     string name = *i++;
 
     cout << format("%1%\n") %
-        makeFixedOutputPath(recursive, hashAlgo,
+        store->makeFixedOutputPath(recursive, hashAlgo,
             parseHash16or32(hashAlgo, hash), name);
 }
 
@@ -315,7 +315,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
 
         case qOutputs: {
             for (auto & i : opArgs) {
-                i = followLinksToStorePath(i);
+                i = store->followLinksToStorePath(i);
                 if (forceRealise) realisePath(i);
                 Derivation drv = store->derivationFromPath(i);
                 for (auto & j : drv.outputs)
@@ -330,7 +330,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
         case qReferrersClosure: {
             PathSet paths;
             for (auto & i : opArgs) {
-                PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
+                PathSet ps = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise);
                 for (auto & j : ps) {
                     if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs);
                     else if (query == qReferences) {
@@ -350,7 +350,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
 
         case qDeriver:
             for (auto & i : opArgs) {
-                Path deriver = store->queryPathInfo(followLinksToStorePath(i))->deriver;
+                Path deriver = store->queryPathInfo(store->followLinksToStorePath(i))->deriver;
                 cout << format("%1%\n") %
                     (deriver == "" ? "unknown-deriver" : deriver);
             }
@@ -358,7 +358,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
 
         case qBinding:
             for (auto & i : opArgs) {
-                Path path = useDeriver(followLinksToStorePath(i));
+                Path path = useDeriver(store->followLinksToStorePath(i));
                 Derivation drv = store->derivationFromPath(path);
                 StringPairs::iterator j = drv.env.find(bindingName);
                 if (j == drv.env.end())
@@ -371,7 +371,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
         case qHash:
         case qSize:
             for (auto & i : opArgs) {
-                PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
+                PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise);
                 for (auto & j : paths) {
                     auto info = store->queryPathInfo(j);
                     if (query == qHash) {
@@ -386,14 +386,14 @@ static void opQuery(Strings opFlags, Strings opArgs)
         case qTree: {
             PathSet done;
             for (auto & i : opArgs)
-                printTree(followLinksToStorePath(i), "", "", done);
+                printTree(store->followLinksToStorePath(i), "", "", done);
             break;
         }
 
         case qGraph: {
             PathSet roots;
             for (auto & i : opArgs) {
-                PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
+                PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise);
                 roots.insert(paths.begin(), paths.end());
             }
             printDotGraph(ref<Store>(store), roots);
@@ -403,7 +403,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
         case qXml: {
             PathSet roots;
             for (auto & i : opArgs) {
-                PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
+                PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise);
                 roots.insert(paths.begin(), paths.end());
             }
             printXmlGraph(ref<Store>(store), roots);
@@ -412,14 +412,14 @@ static void opQuery(Strings opFlags, Strings opArgs)
 
         case qResolve: {
             for (auto & i : opArgs)
-                cout << format("%1%\n") % followLinksToStorePath(i);
+                cout << format("%1%\n") % store->followLinksToStorePath(i);
             break;
         }
 
         case qRoots: {
             PathSet referrers;
             for (auto & i : opArgs) {
-                PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
+                PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise);
                 for (auto & j : paths)
                     store->computeFSClosure(j, referrers, true,
                         settings.gcKeepOutputs, settings.gcKeepDerivations);
@@ -479,7 +479,7 @@ static void opReadLog(Strings opFlags, Strings opArgs)
     RunPager pager;
 
     for (auto & i : opArgs) {
-        Path path = useDeriver(followLinksToStorePath(i));
+        Path path = useDeriver(store->followLinksToStorePath(i));
 
         string baseName = baseNameOf(path);
         bool found = false;
@@ -599,7 +599,7 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
         else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     for (auto & i : opArgs) {
-        Path path = followLinksToStorePath(i);
+        Path path = store->followLinksToStorePath(i);
         if (!store->isValidPath(path)) {
             if (printInvalid)
                 cout << format("%1%\n") % path;
@@ -662,7 +662,7 @@ static void opDelete(Strings opFlags, Strings opArgs)
         else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     for (auto & i : opArgs)
-        options.pathsToDelete.insert(followLinksToStorePath(i));
+        options.pathsToDelete.insert(store->followLinksToStorePath(i));
 
     GCResults results;
     PrintFreed freed(true, results);
@@ -761,7 +761,7 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
     int status = 0;
 
     for (auto & i : opArgs) {
-        Path path = followLinksToStorePath(i);
+        Path path = store->followLinksToStorePath(i);
         printMsg(lvlTalkative, format("checking path ‘%1%’...") % path);
         auto info = store->queryPathInfo(path);
         HashSink sink(info->narHash.type);
@@ -787,7 +787,7 @@ static void opRepairPath(Strings opFlags, Strings opArgs)
         throw UsageError("no flags expected");
 
     for (auto & i : opArgs) {
-        Path path = followLinksToStorePath(i);
+        Path path = store->followLinksToStorePath(i);
         ensureLocalStore()->repairPath(path);
     }
 }
@@ -847,7 +847,7 @@ static void opServe(Strings opFlags, Strings opArgs)
             case cmdQueryValidPaths: {
                 bool lock = readInt(in);
                 bool substitute = readInt(in);
-                PathSet paths = readStorePaths<PathSet>(in);
+                PathSet paths = readStorePaths<PathSet>(*store, in);
                 if (lock && writeAllowed)
                     for (auto & path : paths)
                         store->addTempRoot(path);
@@ -879,7 +879,7 @@ static void opServe(Strings opFlags, Strings opArgs)
             }
 
             case cmdQueryPathInfos: {
-                PathSet paths = readStorePaths<PathSet>(in);
+                PathSet paths = readStorePaths<PathSet>(*store, in);
                 // !!! Maybe we want a queryPathInfos?
                 for (auto & i : paths) {
                     try {
@@ -896,7 +896,7 @@ static void opServe(Strings opFlags, Strings opArgs)
             }
 
             case cmdDumpStorePath:
-                dumpPath(readStorePath(in), out);
+                dumpPath(readStorePath(*store, in), out);
                 break;
 
             case cmdImportPaths: {
@@ -908,7 +908,7 @@ static void opServe(Strings opFlags, Strings opArgs)
 
             case cmdExportPaths: {
                 readInt(in); // obsolete
-                Paths sorted = store->topoSortPaths(readStorePaths<PathSet>(in));
+                Paths sorted = store->topoSortPaths(readStorePaths<PathSet>(*store, in));
                 reverse(sorted.begin(), sorted.end());
                 store->exportPaths(sorted, out);
                 break;
@@ -917,7 +917,7 @@ static void opServe(Strings opFlags, Strings opArgs)
             case cmdBuildPaths: { /* Used by build-remote.pl. */
 
                 if (!writeAllowed) throw Error("building paths is not allowed");
-                PathSet paths = readStorePaths<PathSet>(in);
+                PathSet paths = readStorePaths<PathSet>(*store, in);
 
                 getBuildSettings();
 
@@ -936,9 +936,9 @@ static void opServe(Strings opFlags, Strings opArgs)
 
                 if (!writeAllowed) throw Error("building paths is not allowed");
 
-                Path drvPath = readStorePath(in); // informational only
+                Path drvPath = readStorePath(*store, in); // informational only
                 BasicDerivation drv;
-                in >> drv;
+                readDerivation(in, *store, drv);
 
                 getBuildSettings();
 
@@ -952,7 +952,7 @@ static void opServe(Strings opFlags, Strings opArgs)
 
             case cmdQueryClosure: {
                 bool includeOutputs = readInt(in);
-                PathSet paths = readStorePaths<PathSet>(in);
+                PathSet paths = readStorePaths<PathSet>(*store, in);
                 PathSet closure;
                 for (auto & i : paths)
                     store->computeFSClosure(i, closure, false, includeOutputs);
diff --git a/src/nix/command.cc b/src/nix/command.cc
index 253c9686ba75..37534015b89f 100644
--- a/src/nix/command.cc
+++ b/src/nix/command.cc
@@ -102,7 +102,7 @@ void StorePathsCommand::run(ref<Store> store)
 
     else {
         for (auto & storePath : storePaths)
-            storePath = followLinksToStorePath(storePath);
+            storePath = store->followLinksToStorePath(storePath);
 
         if (recursive) {
             PathSet closure;
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index fb5a515825aa..6257c7679af9 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -17,7 +17,7 @@ UserEnvElems MixInstallables::evalInstallables(ref<Store> store)
 
         if (std::string(installable, 0, 1) == "/") {
 
-            if (isStorePath(installable)) {
+            if (store->isStorePath(installable)) {
 
                 if (isDerivation(installable)) {
                     UserEnvElem elem;