diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-06-01 14:49:12 +0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-06-01 16:24:17 +0200 |
commit | 7850d3d27910c30232dd09dd86ee8afdaad26b90 (patch) | |
tree | da539f14d98d815e89b6ad60ed8e1e1ab9981cbf /src | |
parent | 1b5b654fe25cf7f2219ebe96a943397d683bfa0e (diff) |
Make the store directory a member variable of Store
Diffstat (limited to 'src')
33 files changed, 312 insertions, 292 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5a6428ca6..0833603b2 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 d7245fca5..565ed69ae 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 1a95e01a5..668f1e566 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 3f269b8cf..2d10179f3 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 cca357dfb..7be1571cb 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 e1ce36e92..c2763f1ab 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 becf85245..8067e412a 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 6f98869b0..e27c93713 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 12b194643..6090ee3e9 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 f4cb672cd..df48e8b66 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 8c8d545c6..9587ac547 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 b418c9c04..bdc80cf90 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 303c3af27..ea9c6b541 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 cd3a74d80..32f4e31e0 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 |