diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 955bbe6fb..4007767a9 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -184,9 +184,11 @@ void SourceExprCommand::completeInstallable(std::string_view prefix) if (file) { evalSettings.pureEval = false; auto state = getEvalState(); - Expr *e = state->parseExprFromFile( - resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file))) - ); + Expr *e = + state->parseExprFromFile( + resolveExprPath( + state->rootPath( + lookupFileArg(*state, *file)))); Value root; state->eval(e, root); @@ -700,8 +702,9 @@ std::vector> SourceExprCommand::parseInstallables( if (file == "-") { auto e = state->parseStdin(); state->eval(e, *vFile); - } else if (file) - state->evalFile(lookupFileArg(*state, *file), *vFile); + } + else if (file) + state->evalFile(state->rootPath(lookupFileArg(*state, *file)), *vFile); else { auto e = state->parseExprFromString(*expr, absPath(".")); state->eval(e, *vFile); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 437c7fc53..2c62f28d3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -450,6 +450,7 @@ EvalState::EvalState( , sPrefix(symbols.create("prefix")) , repair(NoRepair) , emptyBindings(0) + , rootFS(makeFSInputAccessor("")) , store(store) , buildStore(buildStore ? buildStore : store) , regexCache(makeRegexCache()) @@ -527,6 +528,7 @@ void EvalState::allowAndSetStorePathString(const StorePath &storePath, Value & v v.mkString(path, PathSet({path})); } +#if 0 Path EvalState::checkSourcePath(const Path & path_) { if (!allowedPaths) return path_; @@ -572,6 +574,7 @@ Path EvalState::checkSourcePath(const Path & path_) throw RestrictedPathError("access to canonical path '%1%' is forbidden in restricted mode", path); } +#endif void EvalState::checkURI(const std::string & uri) @@ -593,12 +596,14 @@ void EvalState::checkURI(const std::string & uri) /* If the URI is a path, then check it against allowedPaths as well. */ if (hasPrefix(uri, "/")) { - checkSourcePath(uri); + // FIXME: use rootPath + //checkSourcePath(uri); return; } if (hasPrefix(uri, "file://")) { - checkSourcePath(std::string(uri, 7)); + // FIXME: use rootPath + //checkSourcePath(std::string(uri, 7)); return; } @@ -970,17 +975,23 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env) } -void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial) +void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial) { + #if 0 auto path = checkSourcePath(path_); + #endif + auto path = packPath(path_); + + // FIXME: use SourcePath as cache key FileEvalCache::iterator i; if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) { v = i->second; return; } - Path resolvedPath = resolveExprPath(path); + auto resolvedPath_ = resolveExprPath(path_); + auto resolvedPath = packPath(resolvedPath_); if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) { v = i->second; return; @@ -994,7 +1005,10 @@ void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial) e = j->second; if (!e) + e = parseExprFromFile(resolvedPath_); + #if 0 e = parseExprFromFile(checkSourcePath(resolvedPath)); + #endif cacheFile(path, resolvedPath, e, v, mustBeTrivial); } @@ -2045,9 +2059,19 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path) if (i != srcToStore.end()) dstPath = store->printStorePath(i->second); else { + // FIXME: use SourcePath + printError("COPY %s", path); + auto path2 = unpackPath(path); + #if 0 auto p = settings.readOnlyMode - ? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first - : store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair); + ? store->computeStorePathForPath(std::string(baseNameOf(path)), canonPath(path)).first + : store->addToStore(std::string(baseNameOf(path)), canonPath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair); + #endif + auto source = sinkToSource([&](Sink & sink) { + path2.accessor->dumpPath(path2.path, sink); + }); + // FIXME: readOnlyMode + auto p = store->addToStoreFromDump(*source, std::string(baseNameOf(path)), FileIngestionMethod::Recursive, htSHA256, repair); dstPath = store->printStorePath(p); allowPath(p); srcToStore.insert_or_assign(path, std::move(p)); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e7915dd99..482223036 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -7,6 +7,7 @@ #include "symbol-table.hh" #include "config.hh" #include "experimental-features.hh" +#include "input-accessor.hh" #include #include @@ -20,6 +21,7 @@ namespace nix { class Store; class EvalState; class StorePath; +struct SourcePath; enum RepairFlag : bool; @@ -95,6 +97,10 @@ public: Bindings emptyBindings; + ref rootFS; + + std::unordered_map> inputAccessors; + /* Store used to materialise .drv files. */ const ref store; @@ -153,6 +159,12 @@ public: SearchPath getSearchPath() { return searchPath; } + Path packPath(const SourcePath & path); + + SourcePath unpackPath(const Path & path); + + SourcePath rootPath(const Path & path); + /* Allow access to a path. */ void allowPath(const Path & path); @@ -163,10 +175,6 @@ public: /* Allow access to a store path and return it as a string. */ void allowAndSetStorePathString(const StorePath & storePath, Value & v); - /* Check whether access to a path is allowed and throw an error if - not. Otherwise return the canonicalised path. */ - Path checkSourcePath(const Path & path); - void checkURI(const std::string & uri); /* When using a diverted store and 'path' is in the Nix store, map @@ -179,8 +187,8 @@ public: Path toRealPath(const Path & path, const PathSet & context); /* Parse a Nix expression from the specified file. */ - Expr * parseExprFromFile(const Path & path); - Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv); + Expr * parseExprFromFile(const SourcePath & path); + Expr * parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv); /* Parse a Nix expression from the specified string. */ Expr * parseExprFromString(std::string s, const Path & basePath, StaticEnv & staticEnv); @@ -191,7 +199,7 @@ public: /* Evaluate an expression read from the given file to normal form. Optionally enforce that the top-level expression is trivial (i.e. doesn't require arbitrary computation). */ - void evalFile(const Path & path, Value & v, bool mustBeTrivial = false); + void evalFile(const SourcePath & path, Value & v, bool mustBeTrivial = false); /* Like `cacheFile`, but with an already parsed expression. */ void cacheFile( @@ -269,6 +277,7 @@ public: /* Path coercion. Converts strings, paths and derivations to a path. The result is guaranteed to be a canonicalised, absolute path. Nothing is copied to the store. */ + // FIXME: return SourcePath Path coerceToPath(const Pos & pos, Value & v, PathSet & context); /* Like coerceToPath, but the result must be a store path. */ @@ -427,7 +436,7 @@ std::string showType(const Value & v); NixStringContextElem decodeContext(const Store & store, std::string_view s); /* If `path' refers to a directory, then append "/default.nix". */ -Path resolveExprPath(Path path); +SourcePath resolveExprPath(const SourcePath & path); struct InvalidPathError : EvalError { diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 22257c6b3..7f2304e7e 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -216,7 +216,8 @@ static Flake getFlake( throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir); Value vInfo; - state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack + // FIXME: use accessor + state.evalFile(state.rootPath(flakeFile), vInfo, true); // FIXME: symlink attack expectType(state, nAttrs, vInfo, Pos(foFile, state.symbols.create(flakeFile), 0, 0)); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 919b9cfae..2d92455b2 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -674,10 +674,9 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin, } -Path resolveExprPath(Path path) +SourcePath resolveExprPath(const SourcePath & path) { - assert(path[0] == '/'); - + #if 0 unsigned int followCount = 0, maxFollow = 1024; /* If `path' is a symlink, follow it. This is so that relative @@ -697,21 +696,30 @@ Path resolveExprPath(Path path) path = canonPath(path + "/default.nix"); return path; + #endif + + // FIXME + auto path2 = path.path + "/default.nix"; + if (path.accessor->pathExists(path2)) + return {path.accessor, path2}; + + return path; } -Expr * EvalState::parseExprFromFile(const Path & path) +Expr * EvalState::parseExprFromFile(const SourcePath & path) { return parseExprFromFile(path, staticBaseEnv); } -Expr * EvalState::parseExprFromFile(const Path & path, StaticEnv & staticEnv) +Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv) { - auto buffer = readFile(path); - // readFile should have left some extra space for terminators + auto packed = packPath(path); + auto buffer = path.accessor->readFile(path.path); + // readFile hopefully have left some extra space for terminators buffer.append("\0\0", 2); - return parse(buffer.data(), buffer.size(), foFile, path, dirOf(path), staticEnv); + return parse(buffer.data(), buffer.size(), foFile, packed, dirOf(packed), staticEnv); } diff --git a/src/libexpr/paths.cc b/src/libexpr/paths.cc new file mode 100644 index 000000000..3b19066aa --- /dev/null +++ b/src/libexpr/paths.cc @@ -0,0 +1,39 @@ +#include "eval.hh" +#include "util.hh" + +namespace nix { + +static constexpr std::string_view marker = "/__virtual/"; + +Path EvalState::packPath(const SourcePath & path) +{ + printError("PACK %s", path.path); + assert(hasPrefix(path.path, "/")); + inputAccessors.emplace(path.accessor->number, path.accessor); + return std::string(marker) + std::to_string(path.accessor->number) + path.path; +} + +SourcePath EvalState::unpackPath(const Path & path) +{ + if (hasPrefix(path, marker)) { + auto s = path.substr(marker.size()); + auto slash = s.find('/'); + assert(slash != s.npos); + auto n = std::stoi(s.substr(0, slash)); + printError("GOT %d", n); + auto i = inputAccessors.find(n); + assert(i != inputAccessors.end()); + return {i->second, s.substr(slash)}; + } else { + printError("FIXME: %s", path); + return rootPath(path); + } +} + +SourcePath EvalState::rootPath(const Path & path) +{ + printError("ROOT %s", path); + return {rootFS, path}; +} + +} diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index f3eb5e925..d238adfdc 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -96,20 +96,23 @@ struct RealisePathFlags { bool checkForPureEval = true; }; -static Path realisePath(EvalState & state, const Pos & pos, Value & v, const RealisePathFlags flags = {}) +static SourcePath realisePath(EvalState & state, const Pos & pos, Value & v, const RealisePathFlags flags = {}) { PathSet context; auto path = [&]() { try { - return state.coerceToPath(pos, v, context); + return state.unpackPath(state.coerceToPath(pos, v, context)); } catch (Error & e) { e.addTrace(pos, "while realising the context of a path"); throw; } }(); + return path; + + #if 0 try { StringMap rewrites = state.realiseContext(context); @@ -122,6 +125,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea e.addTrace(pos, "while realising the context of path '%s'", path); throw; } + #endif } /* Add and attribute to the given attribute map from the output name to @@ -161,6 +165,18 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS { auto path = realisePath(state, pos, vPath); + #if 0 + // FIXME: use InputAccessor + if (path == corepkgsPrefix + "fetchurl.nix") { + state.eval(state.parseExprFromString( + #include "fetchurl.nix.gen.hh" + , "/"), v); + } + #endif + + state.evalFile(path, v); + +#if 0 // FIXME auto isValidDerivationInStore = [&]() -> std::optional { if (!state.store->isStorePath(path)) @@ -200,6 +216,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS state.forceAttrs(v, pos); } + // FIXME: use InputAccessor else if (path == corepkgsPrefix + "fetchurl.nix") { state.eval(state.parseExprFromString( #include "fetchurl.nix.gen.hh" @@ -232,6 +249,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS e->eval(state, *env, v); } } +#endif } static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info { @@ -312,6 +330,9 @@ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v); /* Load a ValueInitializer from a DSO and return whatever it initializes */ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v) { + throw UnimplementedError("importNative"); + + #if 0 auto path = realisePath(state, pos, *args[0]); std::string sym(state.forceStringNoCtx(*args[1], pos)); @@ -334,6 +355,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value (func)(state, v); /* We don't dlclose because v may be a primop referencing a function in the shared object file */ + #endif } @@ -1343,7 +1365,8 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V }); PathSet context; - Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context)); + // FIXME: check rootPath + Path path = state.coerceToPath(pos, *args[0], context); /* 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. */ @@ -1381,14 +1404,14 @@ static RegisterPrimOp primop_storePath({ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, Value & v) { /* We don’t check the path right now, because we don’t want to - throw if the path isn’t allowed, but just return false (and we - can’t just catch the exception here because we still want to - throw if something in the evaluation of `*args[0]` tries to - access an unauthorized path). */ + throw if the path isn’t allowed, but just return false (and we + can’t just catch the exception here because we still want to + throw if something in the evaluation of `*args[0]` tries to + access an unauthorized path). */ auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false }); try { - v.mkBool(pathExists(state.checkSourcePath(path))); + v.mkBool(path.accessor->pathExists(path.path)); } catch (SysError & e) { /* Don't give away info from errors while canonicalising ‘path’ in restricted mode. */ @@ -1453,16 +1476,15 @@ static RegisterPrimOp primop_dirOf({ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { auto path = realisePath(state, pos, *args[0]); - auto s = readFile(path); + auto s = path.accessor->readFile(path.path); if (s.find((char) 0) != std::string::npos) throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path); - StorePathSet refs; - if (state.store->isInStore(path)) { - try { - refs = state.store->queryPathInfo(state.store->toStorePath(path).first)->references; - } catch (Error &) { // FIXME: should be InvalidPathError - } - } + auto refs = + #if 0 + state.store->isInStore(path) ? + state.store->queryPathInfo(state.store->toStorePath(path).first)->references : + #endif + StorePathSet{}; auto context = state.store->printStorePathSet(refs); v.mkString(s, context); } @@ -1480,6 +1502,7 @@ static RegisterPrimOp primop_readFile({ which are desugared to 'findFile __nixPath "x"'. */ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { + #if 0 state.forceList(*args[0], pos); SearchPath searchPath; @@ -1500,26 +1523,18 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va pos ); - PathSet context; - auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned(); - - try { - auto rewrites = state.realiseContext(context); - path = rewriteStrings(path, rewrites); - } catch (InvalidPathError & e) { - throw EvalError({ - .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), - .errPos = pos - }); - } - + auto path = realisePath(state, pos, *i->value, { .requireAbsolutePath = false }); searchPath.emplace_back(prefix, path); } auto path = state.forceStringNoCtx(*args[1], pos); - v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos))); + // FIXME: checkSourcePath? + v.mkPath(state.findFile(searchPath, path, pos)); + #endif + + throw UnimplementedError("findFile"); } static RegisterPrimOp primop_findFile(RegisterPrimOp::Info { @@ -1541,7 +1556,8 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va auto path = realisePath(state, pos, *args[1]); - v.mkString(hashFile(*ht, path).to_string(Base16, false)); + // FIXME: state.toRealPath(path, context) + v.mkString(hashString(*ht, path.accessor->readFile(path.path)).to_string(Base16, false)); } static RegisterPrimOp primop_hashFile({ @@ -1560,17 +1576,19 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val { auto path = realisePath(state, pos, *args[0]); - DirEntries entries = readDirectory(path); - + auto entries = path.accessor->readDirectory(path.path); auto attrs = state.buildBindings(entries.size()); - for (auto & ent : entries) { - if (ent.type == DT_UNKNOWN) - ent.type = getFileType(path + "/" + ent.name); - attrs.alloc(ent.name).mkString( - ent.type == DT_REG ? "regular" : - ent.type == DT_DIR ? "directory" : - ent.type == DT_LNK ? "symlink" : + for (auto & [name, type] : entries) { + #if 0 + // FIXME? + if (type == InputAccessor::Type::Misc) + ent.type = getFileType(path + "/" + name); + #endif + attrs.alloc(name).mkString( + type == InputAccessor::Type::tRegular ? "regular" : + type == InputAccessor::Type::tDirectory ? "directory" : + type == InputAccessor::Type::tSymlink ? "symlink" : "unknown"); } @@ -1902,9 +1920,12 @@ static void addPath( } } + // FIXME + #if 0 path = evalSettings.pureEval && expectedHash ? path : state.checkSourcePath(path); + #endif PathFilter filter = filterFun ? ([&](const Path & path) { auto st = lstat(path); diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index bc9a76b0b..b6f9d0648 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -5,6 +5,7 @@ #include "path.hh" #include "attrs.hh" #include "url.hh" +#include "input-accessor.hh" #include @@ -27,7 +28,6 @@ struct InputScheme; * "fromURL()" or "fromAttrs()" static functions which are provided * the url or attrset specified in the flake file. */ - struct Input { friend struct InputScheme; @@ -98,7 +98,6 @@ public: std::optional getLastModified() const; }; - /* The InputScheme represents a type of fetcher. Each fetcher * registers with nix at startup time. When processing an input for a * flake, each scheme is given an opportunity to "recognize" that @@ -107,7 +106,6 @@ public: * recognized. The Input object contains the information the fetcher * needs to actually perform the "fetch()" when called. */ - struct InputScheme { virtual ~InputScheme() @@ -133,6 +131,11 @@ struct InputScheme virtual void markChangedFile(const Input & input, std::string_view file, std::optional commitMsg); virtual std::pair fetch(ref store, const Input & input) = 0; + + virtual ref getAccessor() + { + throw UnimplementedError("getAccessor"); + } }; void registerInputScheme(std::shared_ptr && fetcher); diff --git a/src/libfetchers/input-accessor.cc b/src/libfetchers/input-accessor.cc new file mode 100644 index 000000000..b548f1baf --- /dev/null +++ b/src/libfetchers/input-accessor.cc @@ -0,0 +1,178 @@ +#include "input-accessor.hh" +#include "util.hh" + +#include + +namespace nix { + +static std::atomic nextNumber{0}; + +InputAccessor::InputAccessor() + : number(++nextNumber) +{ + printError("CREATE %d", number); +} + +// FIXME: merge with archive.cc. +const std::string narVersionMagic1 = "nix-archive-1"; + +static string caseHackSuffix = "~nix~case~hack~"; + +void InputAccessor::dumpPath( + const Path & path, + Sink & sink, + PathFilter & filter) +{ + auto dumpContents = [&](std::string_view path) + { + // FIXME: pipe + auto s = readFile(path); + sink << "contents" << s.size(); + sink(s); + writePadding(s.size(), sink); + }; + + std::function dump; + + dump = [&](const std::string & path) { + checkInterrupt(); + + auto st = lstat(path); + + sink << "("; + + if (st.type == tRegular) { + sink << "type" << "regular"; + if (st.isExecutable) + sink << "executable" << ""; + dumpContents(path); + } + + else if (st.type == tDirectory) { + sink << "type" << "directory"; + + /* If we're on a case-insensitive system like macOS, undo + the case hack applied by restorePath(). */ + std::map unhacked; + for (auto & i : readDirectory(path)) + if (/* archiveSettings.useCaseHack */ false) { // FIXME + string name(i.first); + size_t pos = i.first.find(caseHackSuffix); + if (pos != string::npos) { + debug(format("removing case hack suffix from '%s'") % (path + "/" + i.first)); + name.erase(pos); + } + if (!unhacked.emplace(name, i.first).second) + throw Error("file name collision in between '%s' and '%s'", + (path + "/" + unhacked[name]), + (path + "/" + i.first)); + } else + unhacked.emplace(i.first, i.first); + + for (auto & i : unhacked) + if (filter(path + "/" + i.first)) { + sink << "entry" << "(" << "name" << i.first << "node"; + dump(path + "/" + i.second); + sink << ")"; + } + } + + else if (st.type == tSymlink) + sink << "type" << "symlink" << "target" << readLink(path); + + else throw Error("file '%s' has an unsupported type", path); + + sink << ")"; + }; + + sink << narVersionMagic1; + dump(path); +} + +struct FSInputAccessor : InputAccessor +{ + Path root; + + FSInputAccessor(const Path & root) + : root(root) + { } + + std::string readFile(std::string_view path) override + { + auto absPath = makeAbsPath(path); + printError("READ %s", absPath); + checkAllowed(absPath); + return nix::readFile(absPath); + } + + bool pathExists(std::string_view path) override + { + auto absPath = makeAbsPath(path); + printError("EXISTS %s", absPath); + return isAllowed(absPath) && nix::pathExists(absPath); + } + + Stat lstat(std::string_view path) override + { + auto absPath = makeAbsPath(path); + printError("LSTAT %s", absPath); + checkAllowed(absPath); + auto st = nix::lstat(absPath); + return Stat { + .type = + S_ISREG(st.st_mode) ? tRegular : + S_ISDIR(st.st_mode) ? tDirectory : + S_ISLNK(st.st_mode) ? tSymlink : + tMisc, + .isExecutable = S_ISREG(st.st_mode) && st.st_mode & S_IXUSR + }; + } + + DirEntries readDirectory(std::string_view path) override + { + auto absPath = makeAbsPath(path); + printError("READDIR %s", absPath); + checkAllowed(absPath); + abort(); + } + + std::string readLink(std::string_view path) override + { + auto absPath = makeAbsPath(path); + printError("READLINK %s", absPath); + checkAllowed(absPath); + return nix::readLink(absPath); + } + + Path makeAbsPath(std::string_view path) + { + assert(hasPrefix(path, "/")); + return canonPath(root + std::string(path)); + } + + void checkAllowed(std::string_view absPath) + { + if (!isAllowed(absPath)) + throw Error("access to path '%s' is not allowed", absPath); + } + + bool isAllowed(std::string_view absPath) + { + if (!isDirOrInDir(absPath, root)) + return false; + return true; + } +}; + +ref makeFSInputAccessor(const Path & root) +{ + return make_ref(root); +} + +std::ostream & operator << (std::ostream & str, const SourcePath & path) +{ + str << path.path; // FIXME + return str; +} + +} diff --git a/src/libfetchers/input-accessor.hh b/src/libfetchers/input-accessor.hh new file mode 100644 index 000000000..d2fe9c4ed --- /dev/null +++ b/src/libfetchers/input-accessor.hh @@ -0,0 +1,57 @@ +#pragma once + +#include "ref.hh" +#include "types.hh" +#include "archive.hh" + +namespace nix { + +struct InputAccessor +{ + const size_t number; + + InputAccessor(); + + virtual ~InputAccessor() + { } + + virtual std::string readFile(std::string_view path) = 0; + + virtual bool pathExists(std::string_view path) = 0; + + enum Type { tRegular, tSymlink, tDirectory, tMisc }; + + struct Stat + { + Type type = tMisc; + //uint64_t fileSize = 0; // regular files only + bool isExecutable = false; // regular files only + }; + + virtual Stat lstat(std::string_view path) = 0; + + typedef std::optional DirEntry; + + typedef std::map DirEntries; + + virtual DirEntries readDirectory(std::string_view path) = 0; + + virtual std::string readLink(std::string_view path) = 0; + + virtual void dumpPath( + const Path & path, + Sink & sink, + PathFilter & filter = defaultPathFilter); +}; + +ref makeFSInputAccessor(const Path & root); + +struct SourcePath +{ + ref accessor; + Path path; +}; + +std::ostream & operator << (std::ostream & str, const SourcePath & path); + +} diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index faa8c078f..3b35795f1 100755 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -304,7 +304,11 @@ static void main_nix_build(int argc, char * * argv) else /* If we're in a #! script, interpret filenames relative to the script. */ - exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, + exprs.push_back( + state->parseExprFromFile( + resolveExprPath( + state->rootPath( + lookupFileArg(*state, inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i))))); } } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 9a68899cd..d68cde6a0 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -159,7 +159,7 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v) throw SysError("getting information about '%1%'", path); if (isNixExpr(path, st)) - state.evalFile(path, v); + state.evalFile(state.rootPath(path), v); /* The path is a directory. Put the Nix expressions in the directory in a set, with the file name of each expression as diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 78692b9c6..5a922ff74 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -22,7 +22,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv) Path manifestFile = userEnv + "/manifest.nix"; if (pathExists(manifestFile)) { Value v; - state.evalFile(manifestFile, v); + state.evalFile(state.rootPath(manifestFile), v); Bindings & bindings(*state.allocBindings(0)); getDerivations(state, v, "", bindings, elems, false); } diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 3ec0e6e7c..630868017 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -182,7 +182,7 @@ static int main_nix_instantiate(int argc, char * * argv) for (auto & i : files) { Expr * e = fromArgs ? state->parseExprFromString(i, absPath(".")) - : state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i)))); + : state->parseExprFromFile(resolveExprPath(state->rootPath(lookupFileArg(*state, i)))); processExpr(*state, attrPaths, parseOnly, strict, autoArgs, evalOnly, outputKind, xmlOutputSourceLocation, e); } diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc index f2dd44ba4..0fe163c4e 100644 --- a/src/nix/prefetch.cc +++ b/src/nix/prefetch.cc @@ -192,9 +192,11 @@ static int main_nix_prefetch_url(int argc, char * * argv) throw UsageError("you must specify a URL"); url = args[0]; } else { - Path path = resolveExprPath(lookupFileArg(*state, args.empty() ? "." : args[0])); Value vRoot; - state->evalFile(path, vRoot); + state->evalFile( + resolveExprPath( + state->rootPath(lookupFileArg(*state, args.empty() ? "." : args[0]))), + vRoot); Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first); state->forceAttrs(v, noPos); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 1f9d4fb4e..5ad85691b 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -624,7 +624,7 @@ void NixRepl::loadFile(const Path & path) loadedFiles.remove(path); loadedFiles.push_back(path); Value v, v2; - state->evalFile(lookupFileArg(*state, path), v); + state->evalFile(state->rootPath(lookupFileArg(*state, path)), v); state->autoCallFunction(*autoArgs, v, v2); addAttrsToScope(v2); } diff --git a/tests/plugins/local.mk b/tests/plugins/local.mk index 82ad99402..3745e50b5 100644 --- a/tests/plugins/local.mk +++ b/tests/plugins/local.mk @@ -8,4 +8,4 @@ libplugintest_ALLOW_UNDEFINED := 1 libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1 -libplugintest_CXXFLAGS := -I src/libutil -I src/libexpr +libplugintest_CXXFLAGS := -I src/libutil -I src/libexpr -I src/libfetchers