Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into lazy-trees
Browse files Browse the repository at this point in the history
  • Loading branch information
Ericson2314 committed Nov 24, 2023
2 parents b39148e + 8a52325 commit 0e8672d
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 198 deletions.
10 changes: 7 additions & 3 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -345,16 +345,19 @@ LockedFlake lockFlake(
debug("old lock file: %s", oldLockFile);

std::map<InputPath, std::tuple<FlakeInput, SourcePath, std::optional<InputPath>>> overrides;
std::set<InputPath> explicitCliOverrides;
std::set<InputPath> overridesUsed, updatesUsed;
std::map<ref<Node>, SourcePath> nodePaths;

for (auto & i : lockFlags.inputOverrides)
for (auto & i : lockFlags.inputOverrides) {
overrides.emplace(
i.first,
std::make_tuple(
FlakeInput { .ref = i.second },
state.rootPath(CanonPath::root),
std::nullopt));
explicitCliOverrides.insert(i.first);
}

LockFile newLockFile;

Expand Down Expand Up @@ -431,6 +434,7 @@ LockedFlake lockFlake(
ancestors? */
auto i = overrides.find(inputPath);
bool hasOverride = i != overrides.end();
bool hasCliOverride = explicitCliOverrides.contains(inputPath);
if (hasOverride)
overridesUsed.insert(inputPath);
auto input = hasOverride ? std::get<0>(i->second) : input2;
Expand Down Expand Up @@ -507,7 +511,7 @@ LockedFlake lockFlake(
if (oldLock
&& oldLock->originalRef == *input.ref
&& oldLock->parentPath == overridenParentPath
&& !hasOverride)
&& !hasCliOverride)
{
debug("keeping existing input '%s'", inputPathS);

Expand Down Expand Up @@ -596,7 +600,7 @@ LockedFlake lockFlake(
nuked the next time we update the lock
file. That is, overrides are sticky unless you
use --no-write-lock-file. */
auto ref = input2.ref ? *input2.ref : *input.ref;
auto ref = (input2.ref && explicitCliOverrides.contains(inputPath)) ? *input2.ref : *input.ref;

if (input.isFlake) {
auto inputFlake = getInputFlake();
Expand Down
13 changes: 10 additions & 3 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3205,9 +3205,16 @@ static RegisterPrimOp primop_foldlStrict({
.doc = R"(
Reduce a list by applying a binary operator, from left to right,
e.g. `foldl' op nul [x0 x1 x2 ...] = op (op (op nul x0) x1) x2)
...`. For example, `foldl' (x: y: x + y) 0 [1 2 3]` evaluates to 6.
The return value of each application of `op` is evaluated immediately,
even for intermediate values.
...`.
For example, `foldl' (acc: elem: acc + elem) 0 [1 2 3]` evaluates
to `6` and `foldl' (acc: elem: { "${elem}" = elem; } // acc) {}
["a" "b"]` evaluates to `{ a = "a"; b = "b"; }`.
The first argument of `op` is the accumulator whereas the second
argument is the current element being processed. The return value
of each application of `op` is evaluated immediately, even for
intermediate values.
)",
.fun = prim_foldlStrict,
});
Expand Down
5 changes: 5 additions & 0 deletions src/libfetchers/git.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "fs-input-accessor.hh"
#include "mounted-input-accessor.hh"
#include "git-utils.hh"
#include "logging.hh"
#include "finally.hh"

#include "fetch-settings.hh"

Expand Down Expand Up @@ -307,6 +309,9 @@ struct GitInputScheme : InputScheme
runProgram("git", true,
{ "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "add", "--intent-to-add", "--", std::string(path.rel()) });

// Pause the logger to allow for user input (such as a gpg passphrase) in `git commit`
logger->pause();
Finally restoreLogger([]() { logger->resume(); });
if (commitMsg)
runProgram("git", true,
{ "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "commit", std::string(path.rel()), "-m", *commitMsg });
Expand Down
1 change: 1 addition & 0 deletions src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "namespaces.hh"
#include "child.hh"
#include "unix-domain-socket.hh"
#include "posix-fs-canonicalise.hh"

#include <regex>
#include <queue>
Expand Down
159 changes: 1 addition & 158 deletions src/libstore/local-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "finally.hh"
#include "compression.hh"
#include "signals.hh"
#include "posix-fs-canonicalise.hh"

#include <iostream>
#include <algorithm>
Expand Down Expand Up @@ -581,164 +582,6 @@ void LocalStore::makeStoreWritable()
}


const time_t mtimeStore = 1; /* 1 second into the epoch */


static void canonicaliseTimestampAndPermissions(const Path & path, const struct stat & st)
{
if (!S_ISLNK(st.st_mode)) {

/* Mask out all type related bits. */
mode_t mode = st.st_mode & ~S_IFMT;

if (mode != 0444 && mode != 0555) {
mode = (st.st_mode & S_IFMT)
| 0444
| (st.st_mode & S_IXUSR ? 0111 : 0);
if (chmod(path.c_str(), mode) == -1)
throw SysError("changing mode of '%1%' to %2$o", path, mode);
}

}

if (st.st_mtime != mtimeStore) {
struct timeval times[2];
times[0].tv_sec = st.st_atime;
times[0].tv_usec = 0;
times[1].tv_sec = mtimeStore;
times[1].tv_usec = 0;
#if HAVE_LUTIMES
if (lutimes(path.c_str(), times) == -1)
if (errno != ENOSYS ||
(!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1))
#else
if (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1)
#endif
throw SysError("changing modification time of '%1%'", path);
}
}


void canonicaliseTimestampAndPermissions(const Path & path)
{
canonicaliseTimestampAndPermissions(path, lstat(path));
}


static void canonicalisePathMetaData_(
const Path & path,
std::optional<std::pair<uid_t, uid_t>> uidRange,
InodesSeen & inodesSeen)
{
checkInterrupt();

#if __APPLE__
/* Remove flags, in particular UF_IMMUTABLE which would prevent
the file from being garbage-collected. FIXME: Use
setattrlist() to remove other attributes as well. */
if (lchflags(path.c_str(), 0)) {
if (errno != ENOTSUP)
throw SysError("clearing flags of path '%1%'", path);
}
#endif

auto st = lstat(path);

/* Really make sure that the path is of a supported type. */
if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)))
throw Error("file '%1%' has an unsupported type", path);

#if __linux__
/* Remove extended attributes / ACLs. */
ssize_t eaSize = llistxattr(path.c_str(), nullptr, 0);

if (eaSize < 0) {
if (errno != ENOTSUP && errno != ENODATA)
throw SysError("querying extended attributes of '%s'", path);
} else if (eaSize > 0) {
std::vector<char> eaBuf(eaSize);

if ((eaSize = llistxattr(path.c_str(), eaBuf.data(), eaBuf.size())) < 0)
throw SysError("querying extended attributes of '%s'", path);

for (auto & eaName: tokenizeString<Strings>(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) {
if (settings.ignoredAcls.get().count(eaName)) continue;
if (lremovexattr(path.c_str(), eaName.c_str()) == -1)
throw SysError("removing extended attribute '%s' from '%s'", eaName, path);
}
}
#endif

/* Fail if the file is not owned by the build user. This prevents
us from messing up the ownership/permissions of files
hard-linked into the output (e.g. "ln /etc/shadow $out/foo").
However, ignore files that we chown'ed ourselves previously to
ensure that we don't fail on hard links within the same build
(i.e. "touch $out/foo; ln $out/foo $out/bar"). */
if (uidRange && (st.st_uid < uidRange->first || st.st_uid > uidRange->second)) {
if (S_ISDIR(st.st_mode) || !inodesSeen.count(Inode(st.st_dev, st.st_ino)))
throw BuildError("invalid ownership on file '%1%'", path);
mode_t mode = st.st_mode & ~S_IFMT;
assert(S_ISLNK(st.st_mode) || (st.st_uid == geteuid() && (mode == 0444 || mode == 0555) && st.st_mtime == mtimeStore));
return;
}

inodesSeen.insert(Inode(st.st_dev, st.st_ino));

canonicaliseTimestampAndPermissions(path, st);

/* Change ownership to the current uid. If it's a symlink, use
lchown if available, otherwise don't bother. Wrong ownership
of a symlink doesn't matter, since the owning user can't change
the symlink and can't delete it because the directory is not
writable. The only exception is top-level paths in the Nix
store (since that directory is group-writable for the Nix build
users group); we check for this case below. */
if (st.st_uid != geteuid()) {
#if HAVE_LCHOWN
if (lchown(path.c_str(), geteuid(), getegid()) == -1)
#else
if (!S_ISLNK(st.st_mode) &&
chown(path.c_str(), geteuid(), getegid()) == -1)
#endif
throw SysError("changing owner of '%1%' to %2%",
path, geteuid());
}

if (S_ISDIR(st.st_mode)) {
DirEntries entries = readDirectory(path);
for (auto & i : entries)
canonicalisePathMetaData_(path + "/" + i.name, uidRange, inodesSeen);
}
}


void canonicalisePathMetaData(
const Path & path,
std::optional<std::pair<uid_t, uid_t>> uidRange,
InodesSeen & inodesSeen)
{
canonicalisePathMetaData_(path, uidRange, inodesSeen);

/* On platforms that don't have lchown(), the top-level path can't
be a symlink, since we can't change its ownership. */
auto st = lstat(path);

if (st.st_uid != geteuid()) {
assert(S_ISLNK(st.st_mode));
throw Error("wrong ownership of top-level store path '%1%'", path);
}
}


void canonicalisePathMetaData(const Path & path,
std::optional<std::pair<uid_t, uid_t>> uidRange)
{
InodesSeen inodesSeen;
canonicalisePathMetaData(path, uidRange, inodesSeen);
}


void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
{
experimentalFeatureSettings.require(Xp::CaDerivations);
Expand Down
34 changes: 0 additions & 34 deletions src/libstore/local-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -371,38 +371,4 @@ private:
friend struct DerivationGoal;
};


typedef std::pair<dev_t, ino_t> Inode;
typedef std::set<Inode> InodesSeen;


/**
* "Fix", or canonicalise, the meta-data of the files in a store path
* after it has been built. In particular:
*
* - the last modification date on each file is set to 1 (i.e.,
* 00:00:01 1/1/1970 UTC)
*
* - the permissions are set of 444 or 555 (i.e., read-only with or
* without execute permission; setuid bits etc. are cleared)
*
* - the owner and group are set to the Nix user and group, if we're
* running as root.
*
* If uidRange is not empty, this function will throw an error if it
* encounters files owned by a user outside of the closed interval
* [uidRange->first, uidRange->second].
*/
void canonicalisePathMetaData(
const Path & path,
std::optional<std::pair<uid_t, uid_t>> uidRange,
InodesSeen & inodesSeen);
void canonicalisePathMetaData(
const Path & path,
std::optional<std::pair<uid_t, uid_t>> uidRange);

void canonicaliseTimestampAndPermissions(const Path & path);

MakeError(PathInUse, Error);

}
1 change: 1 addition & 0 deletions src/libstore/optimise-store.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "local-store.hh"
#include "globals.hh"
#include "signals.hh"
#include "posix-fs-canonicalise.hh"

#include <cstdlib>
#include <cstring>
Expand Down
Loading

0 comments on commit 0e8672d

Please sign in to comment.